Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: GPL-2.0+
  2/*
  3 * Copyright (c) 2021 Richtek Technology Corp.
  4 *
  5 * Author: ChiYuan Huang <cy_huang@richtek.com>
  6 */
  7
  8#include <linux/gpio/consumer.h>
  9#include <linux/i2c.h>
 10#include <linux/kernel.h>
 11#include <linux/mfd/core.h>
 12#include <linux/module.h>
 13#include <linux/regmap.h>
 14
 15#define RT4831_REG_REVISION	0x01
 16#define RT4831_REG_ENABLE	0x08
 17#define RT4831_REG_I2CPROT	0x15
 18
 19#define RICHTEK_VENDOR_ID	0x03
 20#define RT4831_VID_MASK		GENMASK(1, 0)
 21#define RT4831_RESET_MASK	BIT(7)
 22#define RT4831_I2CSAFETMR_MASK	BIT(0)
 23
 24static const struct mfd_cell rt4831_subdevs[] = {
 25	MFD_CELL_OF("rt4831-backlight", NULL, NULL, 0, 0, "richtek,rt4831-backlight"),
 26	MFD_CELL_NAME("rt4831-regulator")
 27};
 28
 29static bool rt4831_is_accessible_reg(struct device *dev, unsigned int reg)
 30{
 31	if (reg >= RT4831_REG_REVISION && reg <= RT4831_REG_I2CPROT)
 32		return true;
 33	return false;
 34}
 35
 36static const struct regmap_config rt4831_regmap_config = {
 37	.reg_bits = 8,
 38	.val_bits = 8,
 39	.max_register = RT4831_REG_I2CPROT,
 40
 41	.readable_reg = rt4831_is_accessible_reg,
 42	.writeable_reg = rt4831_is_accessible_reg,
 43};
 44
 45static int rt4831_probe(struct i2c_client *client)
 46{
 47	struct gpio_desc *enable_gpio;
 48	struct regmap *regmap;
 49	unsigned int chip_id;
 50	int ret;
 51
 52	enable_gpio = devm_gpiod_get_optional(&client->dev, "enable", GPIOD_OUT_HIGH);
 53	if (IS_ERR(enable_gpio)) {
 54		dev_err(&client->dev, "Failed to get 'enable' GPIO\n");
 55		return PTR_ERR(enable_gpio);
 56	}
 57
 58	regmap = devm_regmap_init_i2c(client, &rt4831_regmap_config);
 59	if (IS_ERR(regmap)) {
 60		dev_err(&client->dev, "Failed to initialize regmap\n");
 61		return PTR_ERR(regmap);
 62	}
 63
 64	ret = regmap_read(regmap, RT4831_REG_REVISION, &chip_id);
 65	if (ret) {
 66		dev_err(&client->dev, "Failed to get H/W revision\n");
 67		return ret;
 68	}
 69
 70	if ((chip_id & RT4831_VID_MASK) != RICHTEK_VENDOR_ID) {
 71		dev_err(&client->dev, "Chip vendor ID 0x%02x not matched\n", chip_id);
 72		return -ENODEV;
 73	}
 74
 75	/*
 76	 * Used to prevent the abnormal shutdown.
 77	 * If SCL/SDA both keep low for one second to reset HW.
 78	 */
 79	ret = regmap_update_bits(regmap, RT4831_REG_I2CPROT, RT4831_I2CSAFETMR_MASK,
 80				 RT4831_I2CSAFETMR_MASK);
 81	if (ret) {
 82		dev_err(&client->dev, "Failed to enable I2C safety timer\n");
 83		return ret;
 84	}
 85
 86	return devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_AUTO, rt4831_subdevs,
 87				    ARRAY_SIZE(rt4831_subdevs), NULL, 0, NULL);
 88}
 89
 90static int rt4831_remove(struct i2c_client *client)
 91{
 92	struct regmap *regmap = dev_get_regmap(&client->dev, NULL);
 93
 94	/* Disable WLED and DSV outputs */
 95	return regmap_update_bits(regmap, RT4831_REG_ENABLE, RT4831_RESET_MASK, RT4831_RESET_MASK);
 96}
 97
 98static const struct of_device_id __maybe_unused rt4831_of_match[] = {
 99	{ .compatible = "richtek,rt4831", },
100	{}
101};
102MODULE_DEVICE_TABLE(of, rt4831_of_match);
103
104static struct i2c_driver rt4831_driver = {
105	.driver = {
106		.name = "rt4831",
107		.of_match_table = rt4831_of_match,
108	},
109	.probe_new = rt4831_probe,
110	.remove = rt4831_remove,
111};
112module_i2c_driver(rt4831_driver);
113
114MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
115MODULE_LICENSE("GPL v2");