1 /* 2 * TI LMU (Lighting Management Unit) Core Driver 3 * 4 * Copyright 2017 Texas Instruments 5 * 6 * Author: Milo Kim <milo.kim@ti.com> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License version 2 as 10 * published by the Free Software Foundation. 11 */ 12 13 #include <linux/delay.h> 14 #include <linux/err.h> 15 #include <linux/gpio.h> 16 #include <linux/i2c.h> 17 #include <linux/kernel.h> 18 #include <linux/mfd/core.h> 19 #include <linux/mfd/ti-lmu.h> 20 #include <linux/mfd/ti-lmu-register.h> 21 #include <linux/module.h> 22 #include <linux/of.h> 23 #include <linux/of_device.h> 24 #include <linux/of_gpio.h> 25 #include <linux/slab.h> 26 27 struct ti_lmu_data { 28 struct mfd_cell *cells; 29 int num_cells; 30 unsigned int max_register; 31 }; 32 33 static int ti_lmu_enable_hw(struct ti_lmu *lmu, enum ti_lmu_id id) 34 { 35 int ret; 36 37 if (gpio_is_valid(lmu->en_gpio)) { 38 ret = devm_gpio_request_one(lmu->dev, lmu->en_gpio, 39 GPIOF_OUT_INIT_HIGH, "lmu_hwen"); 40 if (ret) { 41 dev_err(lmu->dev, "Can not request enable GPIO: %d\n", 42 ret); 43 return ret; 44 } 45 } 46 47 /* Delay about 1ms after HW enable pin control */ 48 usleep_range(1000, 1500); 49 50 /* LM3631 has additional power up sequence - enable LCD_EN bit. */ 51 if (id == LM3631) { 52 return regmap_update_bits(lmu->regmap, LM3631_REG_DEVCTRL, 53 LM3631_LCD_EN_MASK, 54 LM3631_LCD_EN_MASK); 55 } 56 57 return 0; 58 } 59 60 static void ti_lmu_disable_hw(struct ti_lmu *lmu) 61 { 62 if (gpio_is_valid(lmu->en_gpio)) 63 gpio_set_value(lmu->en_gpio, 0); 64 } 65 66 static struct mfd_cell lm3532_devices[] = { 67 { 68 .name = "ti-lmu-backlight", 69 .id = LM3532, 70 .of_compatible = "ti,lm3532-backlight", 71 }, 72 }; 73 74 #define LM363X_REGULATOR(_id) \ 75 { \ 76 .name = "lm363x-regulator", \ 77 .id = _id, \ 78 .of_compatible = "ti,lm363x-regulator", \ 79 } \ 80 81 static struct mfd_cell lm3631_devices[] = { 82 LM363X_REGULATOR(LM3631_BOOST), 83 LM363X_REGULATOR(LM3631_LDO_CONT), 84 LM363X_REGULATOR(LM3631_LDO_OREF), 85 LM363X_REGULATOR(LM3631_LDO_POS), 86 LM363X_REGULATOR(LM3631_LDO_NEG), 87 { 88 .name = "ti-lmu-backlight", 89 .id = LM3631, 90 .of_compatible = "ti,lm3631-backlight", 91 }, 92 }; 93 94 static struct mfd_cell lm3632_devices[] = { 95 LM363X_REGULATOR(LM3632_BOOST), 96 LM363X_REGULATOR(LM3632_LDO_POS), 97 LM363X_REGULATOR(LM3632_LDO_NEG), 98 { 99 .name = "ti-lmu-backlight", 100 .id = LM3632, 101 .of_compatible = "ti,lm3632-backlight", 102 }, 103 }; 104 105 static struct mfd_cell lm3633_devices[] = { 106 { 107 .name = "ti-lmu-backlight", 108 .id = LM3633, 109 .of_compatible = "ti,lm3633-backlight", 110 }, 111 { 112 .name = "lm3633-leds", 113 .of_compatible = "ti,lm3633-leds", 114 }, 115 /* Monitoring driver for open/short circuit detection */ 116 { 117 .name = "ti-lmu-fault-monitor", 118 .id = LM3633, 119 .of_compatible = "ti,lm3633-fault-monitor", 120 }, 121 }; 122 123 static struct mfd_cell lm3695_devices[] = { 124 { 125 .name = "ti-lmu-backlight", 126 .id = LM3695, 127 .of_compatible = "ti,lm3695-backlight", 128 }, 129 }; 130 131 static struct mfd_cell lm3697_devices[] = { 132 { 133 .name = "ti-lmu-backlight", 134 .id = LM3697, 135 .of_compatible = "ti,lm3697-backlight", 136 }, 137 /* Monitoring driver for open/short circuit detection */ 138 { 139 .name = "ti-lmu-fault-monitor", 140 .id = LM3697, 141 .of_compatible = "ti,lm3697-fault-monitor", 142 }, 143 }; 144 145 #define TI_LMU_DATA(chip, max_reg) \ 146 static const struct ti_lmu_data chip##_data = \ 147 { \ 148 .cells = chip##_devices, \ 149 .num_cells = ARRAY_SIZE(chip##_devices),\ 150 .max_register = max_reg, \ 151 } \ 152 153 TI_LMU_DATA(lm3532, LM3532_MAX_REG); 154 TI_LMU_DATA(lm3631, LM3631_MAX_REG); 155 TI_LMU_DATA(lm3632, LM3632_MAX_REG); 156 TI_LMU_DATA(lm3633, LM3633_MAX_REG); 157 TI_LMU_DATA(lm3695, LM3695_MAX_REG); 158 TI_LMU_DATA(lm3697, LM3697_MAX_REG); 159 160 static const struct of_device_id ti_lmu_of_match[] = { 161 { .compatible = "ti,lm3532", .data = &lm3532_data }, 162 { .compatible = "ti,lm3631", .data = &lm3631_data }, 163 { .compatible = "ti,lm3632", .data = &lm3632_data }, 164 { .compatible = "ti,lm3633", .data = &lm3633_data }, 165 { .compatible = "ti,lm3695", .data = &lm3695_data }, 166 { .compatible = "ti,lm3697", .data = &lm3697_data }, 167 { } 168 }; 169 MODULE_DEVICE_TABLE(of, ti_lmu_of_match); 170 171 static int ti_lmu_probe(struct i2c_client *cl, const struct i2c_device_id *id) 172 { 173 struct device *dev = &cl->dev; 174 const struct of_device_id *match; 175 const struct ti_lmu_data *data; 176 struct regmap_config regmap_cfg; 177 struct ti_lmu *lmu; 178 int ret; 179 180 match = of_match_device(ti_lmu_of_match, dev); 181 if (!match) 182 return -ENODEV; 183 /* 184 * Get device specific data from of_match table. 185 * This data is defined by using TI_LMU_DATA() macro. 186 */ 187 data = (struct ti_lmu_data *)match->data; 188 189 lmu = devm_kzalloc(dev, sizeof(*lmu), GFP_KERNEL); 190 if (!lmu) 191 return -ENOMEM; 192 193 lmu->dev = &cl->dev; 194 195 /* Setup regmap */ 196 memset(®map_cfg, 0, sizeof(struct regmap_config)); 197 regmap_cfg.reg_bits = 8; 198 regmap_cfg.val_bits = 8; 199 regmap_cfg.name = id->name; 200 regmap_cfg.max_register = data->max_register; 201 202 lmu->regmap = devm_regmap_init_i2c(cl, ®map_cfg); 203 if (IS_ERR(lmu->regmap)) 204 return PTR_ERR(lmu->regmap); 205 206 /* HW enable pin control and additional power up sequence if required */ 207 lmu->en_gpio = of_get_named_gpio(dev->of_node, "enable-gpios", 0); 208 ret = ti_lmu_enable_hw(lmu, id->driver_data); 209 if (ret) 210 return ret; 211 212 /* 213 * Fault circuit(open/short) can be detected by ti-lmu-fault-monitor. 214 * After fault detection is done, some devices should re-initialize 215 * configuration. The notifier enables such kind of handling. 216 */ 217 BLOCKING_INIT_NOTIFIER_HEAD(&lmu->notifier); 218 219 i2c_set_clientdata(cl, lmu); 220 221 return mfd_add_devices(lmu->dev, 0, data->cells, 222 data->num_cells, NULL, 0, NULL); 223 } 224 225 static int ti_lmu_remove(struct i2c_client *cl) 226 { 227 struct ti_lmu *lmu = i2c_get_clientdata(cl); 228 229 ti_lmu_disable_hw(lmu); 230 mfd_remove_devices(lmu->dev); 231 return 0; 232 } 233 234 static const struct i2c_device_id ti_lmu_ids[] = { 235 { "lm3532", LM3532 }, 236 { "lm3631", LM3631 }, 237 { "lm3632", LM3632 }, 238 { "lm3633", LM3633 }, 239 { "lm3695", LM3695 }, 240 { "lm3697", LM3697 }, 241 { } 242 }; 243 MODULE_DEVICE_TABLE(i2c, ti_lmu_ids); 244 245 static struct i2c_driver ti_lmu_driver = { 246 .probe = ti_lmu_probe, 247 .remove = ti_lmu_remove, 248 .driver = { 249 .name = "ti-lmu", 250 .of_match_table = ti_lmu_of_match, 251 }, 252 .id_table = ti_lmu_ids, 253 }; 254 255 module_i2c_driver(ti_lmu_driver); 256 257 MODULE_DESCRIPTION("TI LMU MFD Core Driver"); 258 MODULE_AUTHOR("Milo Kim"); 259 MODULE_LICENSE("GPL v2"); 260