| 1 | |
| 2 | |
| 3 | * Copyright (c) 2021 Richtek Technology Corp.
|
| 4 | *
|
| 5 | * Author: ChiYuan Huang <[email protected]>
|
| 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 |
|
| 24 | static 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 |
|
| 29 | static 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 |
|
| 36 | static 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 |
|
| 45 | static 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 |
|
| 90 | static void rt4831_remove(struct i2c_client *client)
|
| 91 | {
|
| 92 | struct regmap *regmap = dev_get_regmap(&client->dev, NULL);
|
| 93 | int ret;
|
| 94 |
|
| 95 |
|
| 96 | ret = regmap_update_bits(regmap, RT4831_REG_ENABLE, RT4831_RESET_MASK, RT4831_RESET_MASK);
|
| 97 | if (ret)
|
| 98 | dev_warn(&client->dev, "Failed to disable outputs (%pe)\n", ERR_PTR(ret));
|
| 99 | }
|
| 100 |
|
| 101 | static const struct of_device_id __maybe_unused rt4831_of_match[] = {
|
| 102 | { .compatible = "richtek,rt4831", },
|
| 103 | {}
|
| 104 | };
|
| 105 | MODULE_DEVICE_TABLE(of, rt4831_of_match);
|
| 106 |
|
| 107 | static struct i2c_driver rt4831_driver = {
|
| 108 | .driver = {
|
| 109 | .name = "rt4831",
|
| 110 | .of_match_table = rt4831_of_match,
|
| 111 | },
|
| 112 | .probe = rt4831_probe,
|
| 113 | .remove = rt4831_remove,
|
| 114 | };
|
| 115 | module_i2c_driver(rt4831_driver);
|
| 116 |
|
| 117 | MODULE_AUTHOR("ChiYuan Huang <[email protected]>");
|
| 118 | MODULE_DESCRIPTION("Richtek RT4831 core driver");
|
| 119 | MODULE_LICENSE("GPL v2");
|