1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2d5aa11bfSMilo Kim /* 3d5aa11bfSMilo Kim * TI LMU (Lighting Management Unit) Core Driver 4d5aa11bfSMilo Kim * 5d5aa11bfSMilo Kim * Copyright 2017 Texas Instruments 6d5aa11bfSMilo Kim * 7d5aa11bfSMilo Kim * Author: Milo Kim <milo.kim@ti.com> 8d5aa11bfSMilo Kim */ 9d5aa11bfSMilo Kim 10d5aa11bfSMilo Kim #include <linux/delay.h> 11d5aa11bfSMilo Kim #include <linux/err.h> 127a6a395bSPavel Machek #include <linux/gpio/consumer.h> 13d5aa11bfSMilo Kim #include <linux/i2c.h> 14d5aa11bfSMilo Kim #include <linux/kernel.h> 15d5aa11bfSMilo Kim #include <linux/mfd/core.h> 16d5aa11bfSMilo Kim #include <linux/mfd/ti-lmu.h> 17d5aa11bfSMilo Kim #include <linux/mfd/ti-lmu-register.h> 18d5aa11bfSMilo Kim #include <linux/module.h> 19d5aa11bfSMilo Kim #include <linux/of.h> 20d5aa11bfSMilo Kim #include <linux/of_device.h> 21d5aa11bfSMilo Kim #include <linux/slab.h> 22d5aa11bfSMilo Kim 23d5aa11bfSMilo Kim struct ti_lmu_data { 245b6850faSSebastian Reichel const struct mfd_cell *cells; 25d5aa11bfSMilo Kim int num_cells; 26d5aa11bfSMilo Kim unsigned int max_register; 27d5aa11bfSMilo Kim }; 28d5aa11bfSMilo Kim 29d5aa11bfSMilo Kim static int ti_lmu_enable_hw(struct ti_lmu *lmu, enum ti_lmu_id id) 30d5aa11bfSMilo Kim { 317a6a395bSPavel Machek if (lmu->en_gpio) 327a6a395bSPavel Machek gpiod_set_value(lmu->en_gpio, 1); 33d5aa11bfSMilo Kim 34d5aa11bfSMilo Kim /* Delay about 1ms after HW enable pin control */ 35d5aa11bfSMilo Kim usleep_range(1000, 1500); 36d5aa11bfSMilo Kim 37d5aa11bfSMilo Kim /* LM3631 has additional power up sequence - enable LCD_EN bit. */ 38d5aa11bfSMilo Kim if (id == LM3631) { 39d5aa11bfSMilo Kim return regmap_update_bits(lmu->regmap, LM3631_REG_DEVCTRL, 40d5aa11bfSMilo Kim LM3631_LCD_EN_MASK, 41d5aa11bfSMilo Kim LM3631_LCD_EN_MASK); 42d5aa11bfSMilo Kim } 43d5aa11bfSMilo Kim 44d5aa11bfSMilo Kim return 0; 45d5aa11bfSMilo Kim } 46d5aa11bfSMilo Kim 477891d375SPavel Machek static void ti_lmu_disable_hw(void *data) 48d5aa11bfSMilo Kim { 497891d375SPavel Machek struct ti_lmu *lmu = data; 507a6a395bSPavel Machek if (lmu->en_gpio) 517a6a395bSPavel Machek gpiod_set_value(lmu->en_gpio, 0); 52d5aa11bfSMilo Kim } 53d5aa11bfSMilo Kim 54d5aa11bfSMilo Kim #define LM363X_REGULATOR(_id) \ 55d5aa11bfSMilo Kim { \ 56d5aa11bfSMilo Kim .name = "lm363x-regulator", \ 57d5aa11bfSMilo Kim .id = _id, \ 58d5aa11bfSMilo Kim .of_compatible = "ti,lm363x-regulator", \ 59d5aa11bfSMilo Kim } \ 60d5aa11bfSMilo Kim 615b6850faSSebastian Reichel static const struct mfd_cell lm3631_devices[] = { 62d5aa11bfSMilo Kim LM363X_REGULATOR(LM3631_BOOST), 63d5aa11bfSMilo Kim LM363X_REGULATOR(LM3631_LDO_CONT), 64d5aa11bfSMilo Kim LM363X_REGULATOR(LM3631_LDO_OREF), 65d5aa11bfSMilo Kim LM363X_REGULATOR(LM3631_LDO_POS), 66d5aa11bfSMilo Kim LM363X_REGULATOR(LM3631_LDO_NEG), 67d5aa11bfSMilo Kim { 68d5aa11bfSMilo Kim .name = "ti-lmu-backlight", 69d5aa11bfSMilo Kim .id = LM3631, 70d5aa11bfSMilo Kim .of_compatible = "ti,lm3631-backlight", 71d5aa11bfSMilo Kim }, 72d5aa11bfSMilo Kim }; 73d5aa11bfSMilo Kim 745b6850faSSebastian Reichel static const struct mfd_cell lm3632_devices[] = { 75d5aa11bfSMilo Kim LM363X_REGULATOR(LM3632_BOOST), 76d5aa11bfSMilo Kim LM363X_REGULATOR(LM3632_LDO_POS), 77d5aa11bfSMilo Kim LM363X_REGULATOR(LM3632_LDO_NEG), 78d5aa11bfSMilo Kim { 79d5aa11bfSMilo Kim .name = "ti-lmu-backlight", 80d5aa11bfSMilo Kim .id = LM3632, 81d5aa11bfSMilo Kim .of_compatible = "ti,lm3632-backlight", 82d5aa11bfSMilo Kim }, 83d5aa11bfSMilo Kim }; 84d5aa11bfSMilo Kim 855b6850faSSebastian Reichel static const struct mfd_cell lm3633_devices[] = { 86d5aa11bfSMilo Kim { 87d5aa11bfSMilo Kim .name = "ti-lmu-backlight", 88d5aa11bfSMilo Kim .id = LM3633, 89d5aa11bfSMilo Kim .of_compatible = "ti,lm3633-backlight", 90d5aa11bfSMilo Kim }, 91d5aa11bfSMilo Kim { 92d5aa11bfSMilo Kim .name = "lm3633-leds", 93d5aa11bfSMilo Kim .of_compatible = "ti,lm3633-leds", 94d5aa11bfSMilo Kim }, 95d5aa11bfSMilo Kim /* Monitoring driver for open/short circuit detection */ 96d5aa11bfSMilo Kim { 97d5aa11bfSMilo Kim .name = "ti-lmu-fault-monitor", 98d5aa11bfSMilo Kim .id = LM3633, 99d5aa11bfSMilo Kim .of_compatible = "ti,lm3633-fault-monitor", 100d5aa11bfSMilo Kim }, 101d5aa11bfSMilo Kim }; 102d5aa11bfSMilo Kim 1035b6850faSSebastian Reichel static const struct mfd_cell lm3695_devices[] = { 104d5aa11bfSMilo Kim { 105d5aa11bfSMilo Kim .name = "ti-lmu-backlight", 106d5aa11bfSMilo Kim .id = LM3695, 107d5aa11bfSMilo Kim .of_compatible = "ti,lm3695-backlight", 108d5aa11bfSMilo Kim }, 109d5aa11bfSMilo Kim }; 110d5aa11bfSMilo Kim 1115b6850faSSebastian Reichel static const struct mfd_cell lm3697_devices[] = { 112d5aa11bfSMilo Kim { 113d5aa11bfSMilo Kim .name = "ti-lmu-backlight", 114d5aa11bfSMilo Kim .id = LM3697, 115d5aa11bfSMilo Kim .of_compatible = "ti,lm3697-backlight", 116d5aa11bfSMilo Kim }, 117d5aa11bfSMilo Kim /* Monitoring driver for open/short circuit detection */ 118d5aa11bfSMilo Kim { 119d5aa11bfSMilo Kim .name = "ti-lmu-fault-monitor", 120d5aa11bfSMilo Kim .id = LM3697, 121d5aa11bfSMilo Kim .of_compatible = "ti,lm3697-fault-monitor", 122d5aa11bfSMilo Kim }, 123d5aa11bfSMilo Kim }; 124d5aa11bfSMilo Kim 125d5aa11bfSMilo Kim #define TI_LMU_DATA(chip, max_reg) \ 126d5aa11bfSMilo Kim static const struct ti_lmu_data chip##_data = \ 127d5aa11bfSMilo Kim { \ 128d5aa11bfSMilo Kim .cells = chip##_devices, \ 129d5aa11bfSMilo Kim .num_cells = ARRAY_SIZE(chip##_devices),\ 130d5aa11bfSMilo Kim .max_register = max_reg, \ 131d5aa11bfSMilo Kim } \ 132d5aa11bfSMilo Kim 133d5aa11bfSMilo Kim TI_LMU_DATA(lm3631, LM3631_MAX_REG); 134d5aa11bfSMilo Kim TI_LMU_DATA(lm3632, LM3632_MAX_REG); 135d5aa11bfSMilo Kim TI_LMU_DATA(lm3633, LM3633_MAX_REG); 136d5aa11bfSMilo Kim TI_LMU_DATA(lm3695, LM3695_MAX_REG); 137d5aa11bfSMilo Kim TI_LMU_DATA(lm3697, LM3697_MAX_REG); 138d5aa11bfSMilo Kim 139d5aa11bfSMilo Kim static int ti_lmu_probe(struct i2c_client *cl, const struct i2c_device_id *id) 140d5aa11bfSMilo Kim { 141d5aa11bfSMilo Kim struct device *dev = &cl->dev; 142d5aa11bfSMilo Kim const struct ti_lmu_data *data; 143d5aa11bfSMilo Kim struct regmap_config regmap_cfg; 144d5aa11bfSMilo Kim struct ti_lmu *lmu; 145d5aa11bfSMilo Kim int ret; 146d5aa11bfSMilo Kim 147d5aa11bfSMilo Kim /* 148d5aa11bfSMilo Kim * Get device specific data from of_match table. 149d5aa11bfSMilo Kim * This data is defined by using TI_LMU_DATA() macro. 150d5aa11bfSMilo Kim */ 151697894b9SPavel Machek data = of_device_get_match_data(dev); 152697894b9SPavel Machek if (!data) 153697894b9SPavel Machek return -ENODEV; 154d5aa11bfSMilo Kim 155d5aa11bfSMilo Kim lmu = devm_kzalloc(dev, sizeof(*lmu), GFP_KERNEL); 156d5aa11bfSMilo Kim if (!lmu) 157d5aa11bfSMilo Kim return -ENOMEM; 158d5aa11bfSMilo Kim 159d5aa11bfSMilo Kim lmu->dev = &cl->dev; 160d5aa11bfSMilo Kim 161d5aa11bfSMilo Kim /* Setup regmap */ 162d5aa11bfSMilo Kim memset(®map_cfg, 0, sizeof(struct regmap_config)); 163d5aa11bfSMilo Kim regmap_cfg.reg_bits = 8; 164d5aa11bfSMilo Kim regmap_cfg.val_bits = 8; 165d5aa11bfSMilo Kim regmap_cfg.name = id->name; 166d5aa11bfSMilo Kim regmap_cfg.max_register = data->max_register; 167d5aa11bfSMilo Kim 168d5aa11bfSMilo Kim lmu->regmap = devm_regmap_init_i2c(cl, ®map_cfg); 169d5aa11bfSMilo Kim if (IS_ERR(lmu->regmap)) 170d5aa11bfSMilo Kim return PTR_ERR(lmu->regmap); 171d5aa11bfSMilo Kim 172d5aa11bfSMilo Kim /* HW enable pin control and additional power up sequence if required */ 1737a6a395bSPavel Machek lmu->en_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_HIGH); 1747a6a395bSPavel Machek if (IS_ERR(lmu->en_gpio)) { 1757a6a395bSPavel Machek ret = PTR_ERR(lmu->en_gpio); 1767a6a395bSPavel Machek dev_err(dev, "Can not request enable GPIO: %d\n", ret); 1777a6a395bSPavel Machek return ret; 1787a6a395bSPavel Machek } 1797a6a395bSPavel Machek 180d5aa11bfSMilo Kim ret = ti_lmu_enable_hw(lmu, id->driver_data); 181d5aa11bfSMilo Kim if (ret) 182d5aa11bfSMilo Kim return ret; 183d5aa11bfSMilo Kim 1847891d375SPavel Machek ret = devm_add_action_or_reset(dev, ti_lmu_disable_hw, lmu); 1857891d375SPavel Machek if (ret) 1867891d375SPavel Machek return ret; 1877891d375SPavel Machek 188d5aa11bfSMilo Kim /* 189d5aa11bfSMilo Kim * Fault circuit(open/short) can be detected by ti-lmu-fault-monitor. 190d5aa11bfSMilo Kim * After fault detection is done, some devices should re-initialize 191d5aa11bfSMilo Kim * configuration. The notifier enables such kind of handling. 192d5aa11bfSMilo Kim */ 193d5aa11bfSMilo Kim BLOCKING_INIT_NOTIFIER_HEAD(&lmu->notifier); 194d5aa11bfSMilo Kim 195d5aa11bfSMilo Kim i2c_set_clientdata(cl, lmu); 196d5aa11bfSMilo Kim 1977891d375SPavel Machek return devm_mfd_add_devices(lmu->dev, 0, data->cells, 198d5aa11bfSMilo Kim data->num_cells, NULL, 0, NULL); 199d5aa11bfSMilo Kim } 200d5aa11bfSMilo Kim 201697894b9SPavel Machek static const struct of_device_id ti_lmu_of_match[] = { 202697894b9SPavel Machek { .compatible = "ti,lm3631", .data = &lm3631_data }, 203697894b9SPavel Machek { .compatible = "ti,lm3632", .data = &lm3632_data }, 204697894b9SPavel Machek { .compatible = "ti,lm3633", .data = &lm3633_data }, 205697894b9SPavel Machek { .compatible = "ti,lm3695", .data = &lm3695_data }, 206697894b9SPavel Machek { .compatible = "ti,lm3697", .data = &lm3697_data }, 207697894b9SPavel Machek { } 208697894b9SPavel Machek }; 209697894b9SPavel Machek MODULE_DEVICE_TABLE(of, ti_lmu_of_match); 210697894b9SPavel Machek 211d5aa11bfSMilo Kim static const struct i2c_device_id ti_lmu_ids[] = { 212d5aa11bfSMilo Kim { "lm3631", LM3631 }, 213d5aa11bfSMilo Kim { "lm3632", LM3632 }, 214d5aa11bfSMilo Kim { "lm3633", LM3633 }, 215d5aa11bfSMilo Kim { "lm3695", LM3695 }, 216d5aa11bfSMilo Kim { "lm3697", LM3697 }, 217d5aa11bfSMilo Kim { } 218d5aa11bfSMilo Kim }; 219d5aa11bfSMilo Kim MODULE_DEVICE_TABLE(i2c, ti_lmu_ids); 220d5aa11bfSMilo Kim 221d5aa11bfSMilo Kim static struct i2c_driver ti_lmu_driver = { 222d5aa11bfSMilo Kim .probe = ti_lmu_probe, 223d5aa11bfSMilo Kim .driver = { 224d5aa11bfSMilo Kim .name = "ti-lmu", 225d5aa11bfSMilo Kim .of_match_table = ti_lmu_of_match, 226d5aa11bfSMilo Kim }, 227d5aa11bfSMilo Kim .id_table = ti_lmu_ids, 228d5aa11bfSMilo Kim }; 229d5aa11bfSMilo Kim 230d5aa11bfSMilo Kim module_i2c_driver(ti_lmu_driver); 231d5aa11bfSMilo Kim 232d5aa11bfSMilo Kim MODULE_DESCRIPTION("TI LMU MFD Core Driver"); 233d5aa11bfSMilo Kim MODULE_AUTHOR("Milo Kim"); 234d5aa11bfSMilo Kim MODULE_LICENSE("GPL v2"); 235