summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Murphy <dmurphy@ti.com>2019-05-06 15:16:14 -0400
committerJacek Anaszewski <jacek.anaszewski@gmail.com>2019-05-24 16:40:47 -0400
commit5c1d824cda9f6059ee5fb6cc83cd4f47c85cf215 (patch)
treed8a9e7fb8e186a4dfc83b17a4cb8eb06abb63e38
parentb86b9ba55a2e0d1013db26084385d83dd7d0b475 (diff)
leds: lm3697: Introduce the lm3697 driver
Introduce the lm3697 LED driver for backlighting and display. Datasheet location: http://www.ti.com/lit/ds/symlink/lm3697.pdf Signed-off-by: Dan Murphy <dmurphy@ti.com> Signed-off-by: Jacek Anaszewski <jacek.anaszewski@gmail.com>
-rw-r--r--drivers/leds/Kconfig8
-rw-r--r--drivers/leds/Makefile1
-rw-r--r--drivers/leds/leds-lm3697.c395
3 files changed, 404 insertions, 0 deletions
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 4e262696be19..ba14b4894855 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -792,6 +792,14 @@ config LEDS_TI_LMU_COMMON
792 This supports common features between the TI LM3532, LM3631, LM3632, 792 This supports common features between the TI LM3532, LM3631, LM3632,
793 LM3633, LM3695 and LM3697. 793 LM3633, LM3695 and LM3697.
794 794
795config LEDS_LM3697
796 tristate "LED driver for LM3697"
797 depends on LEDS_TI_LMU_COMMON
798 depends on I2C && OF
799 help
800 Say Y to enable the LM3697 LED driver for TI LMU devices.
801 This supports the LED device LM3697.
802
795comment "LED Triggers" 803comment "LED Triggers"
796source "drivers/leds/trigger/Kconfig" 804source "drivers/leds/trigger/Kconfig"
797 805
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 84c49339a8e3..6c3350404ede 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -82,6 +82,7 @@ obj-$(CONFIG_LEDS_LM3692X) += leds-lm3692x.o
82obj-$(CONFIG_LEDS_SC27XX_BLTC) += leds-sc27xx-bltc.o 82obj-$(CONFIG_LEDS_SC27XX_BLTC) += leds-sc27xx-bltc.o
83obj-$(CONFIG_LEDS_LM3601X) += leds-lm3601x.o 83obj-$(CONFIG_LEDS_LM3601X) += leds-lm3601x.o
84obj-$(CONFIG_LEDS_TI_LMU_COMMON) += leds-ti-lmu-common.o 84obj-$(CONFIG_LEDS_TI_LMU_COMMON) += leds-ti-lmu-common.o
85obj-$(CONFIG_LEDS_LM3697) += leds-lm3697.o
85 86
86# LED SPI Drivers 87# LED SPI Drivers
87obj-$(CONFIG_LEDS_CR0014114) += leds-cr0014114.o 88obj-$(CONFIG_LEDS_CR0014114) += leds-cr0014114.o
diff --git a/drivers/leds/leds-lm3697.c b/drivers/leds/leds-lm3697.c
new file mode 100644
index 000000000000..54e0e35df824
--- /dev/null
+++ b/drivers/leds/leds-lm3697.c
@@ -0,0 +1,395 @@
1// SPDX-License-Identifier: GPL-2.0
2// TI LM3697 LED chip family driver
3// Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
4
5#include <linux/gpio/consumer.h>
6#include <linux/i2c.h>
7#include <linux/of.h>
8#include <linux/of_gpio.h>
9#include <linux/regulator/consumer.h>
10#include <linux/leds-ti-lmu-common.h>
11
12#define LM3697_REV 0x0
13#define LM3697_RESET 0x1
14#define LM3697_OUTPUT_CONFIG 0x10
15#define LM3697_CTRL_A_RAMP 0x11
16#define LM3697_CTRL_B_RAMP 0x12
17#define LM3697_CTRL_A_B_RT_RAMP 0x13
18#define LM3697_CTRL_A_B_RAMP_CFG 0x14
19#define LM3697_CTRL_A_B_BRT_CFG 0x16
20#define LM3697_CTRL_A_FS_CURR_CFG 0x17
21#define LM3697_CTRL_B_FS_CURR_CFG 0x18
22#define LM3697_PWM_CFG 0x1c
23#define LM3697_CTRL_A_BRT_LSB 0x20
24#define LM3697_CTRL_A_BRT_MSB 0x21
25#define LM3697_CTRL_B_BRT_LSB 0x22
26#define LM3697_CTRL_B_BRT_MSB 0x23
27#define LM3697_CTRL_ENABLE 0x24
28
29#define LM3697_SW_RESET BIT(0)
30
31#define LM3697_CTRL_A_EN BIT(0)
32#define LM3697_CTRL_B_EN BIT(1)
33#define LM3697_CTRL_A_B_EN (LM3697_CTRL_A_EN | LM3697_CTRL_B_EN)
34
35#define LM3697_MAX_LED_STRINGS 3
36
37#define LM3697_CONTROL_A 0
38#define LM3697_CONTROL_B 1
39#define LM3697_MAX_CONTROL_BANKS 2
40
41/**
42 * struct lm3697_led -
43 * @hvled_strings: Array of LED strings associated with a control bank
44 * @label: LED label
45 * @led_dev: LED class device
46 * @priv: Pointer to the device struct
47 * @lmu_data: Register and setting values for common code
48 * @control_bank: Control bank the LED is associated to. 0 is control bank A
49 * 1 is control bank B
50 */
51struct lm3697_led {
52 u32 hvled_strings[LM3697_MAX_LED_STRINGS];
53 char label[LED_MAX_NAME_SIZE];
54 struct led_classdev led_dev;
55 struct lm3697 *priv;
56 struct ti_lmu_bank lmu_data;
57 int control_bank;
58 int enabled;
59 int num_leds;
60};
61
62/**
63 * struct lm3697 -
64 * @enable_gpio: Hardware enable gpio
65 * @regulator: LED supply regulator pointer
66 * @client: Pointer to the I2C client
67 * @regmap: Devices register map
68 * @dev: Pointer to the devices device struct
69 * @lock: Lock for reading/writing the device
70 * @leds: Array of LED strings
71 */
72struct lm3697 {
73 struct gpio_desc *enable_gpio;
74 struct regulator *regulator;
75 struct i2c_client *client;
76 struct regmap *regmap;
77 struct device *dev;
78 struct mutex lock;
79
80 int bank_cfg;
81
82 struct lm3697_led leds[];
83};
84
85static const struct reg_default lm3697_reg_defs[] = {
86 {LM3697_OUTPUT_CONFIG, 0x6},
87 {LM3697_CTRL_A_RAMP, 0x0},
88 {LM3697_CTRL_B_RAMP, 0x0},
89 {LM3697_CTRL_A_B_RT_RAMP, 0x0},
90 {LM3697_CTRL_A_B_RAMP_CFG, 0x0},
91 {LM3697_CTRL_A_B_BRT_CFG, 0x0},
92 {LM3697_CTRL_A_FS_CURR_CFG, 0x13},
93 {LM3697_CTRL_B_FS_CURR_CFG, 0x13},
94 {LM3697_PWM_CFG, 0xc},
95 {LM3697_CTRL_A_BRT_LSB, 0x0},
96 {LM3697_CTRL_A_BRT_MSB, 0x0},
97 {LM3697_CTRL_B_BRT_LSB, 0x0},
98 {LM3697_CTRL_B_BRT_MSB, 0x0},
99 {LM3697_CTRL_ENABLE, 0x0},
100};
101
102static const struct regmap_config lm3697_regmap_config = {
103 .reg_bits = 8,
104 .val_bits = 8,
105
106 .max_register = LM3697_CTRL_ENABLE,
107 .reg_defaults = lm3697_reg_defs,
108 .num_reg_defaults = ARRAY_SIZE(lm3697_reg_defs),
109 .cache_type = REGCACHE_FLAT,
110};
111
112static int lm3697_brightness_set(struct led_classdev *led_cdev,
113 enum led_brightness brt_val)
114{
115 struct lm3697_led *led = container_of(led_cdev, struct lm3697_led,
116 led_dev);
117 int ctrl_en_val = (1 << led->control_bank);
118 int ret;
119
120 mutex_lock(&led->priv->lock);
121
122 if (brt_val == LED_OFF) {
123 ret = regmap_update_bits(led->priv->regmap, LM3697_CTRL_ENABLE,
124 ctrl_en_val, ~ctrl_en_val);
125 if (ret) {
126 dev_err(&led->priv->client->dev, "Cannot write ctrl register\n");
127 goto brightness_out;
128 }
129
130 led->enabled = LED_OFF;
131 } else {
132 ret = ti_lmu_common_set_brightness(&led->lmu_data, brt_val);
133 if (ret) {
134 dev_err(&led->priv->client->dev,
135 "Cannot write brightness\n");
136 goto brightness_out;
137 }
138
139 if (!led->enabled) {
140 ret = regmap_update_bits(led->priv->regmap,
141 LM3697_CTRL_ENABLE,
142 ctrl_en_val, ctrl_en_val);
143 if (ret) {
144 dev_err(&led->priv->client->dev,
145 "Cannot enable the device\n");
146 goto brightness_out;
147 }
148
149 led->enabled = brt_val;
150 }
151 }
152
153brightness_out:
154 mutex_unlock(&led->priv->lock);
155 return ret;
156}
157
158static int lm3697_init(struct lm3697 *priv)
159{
160 struct lm3697_led *led;
161 int i, ret;
162
163 if (priv->enable_gpio) {
164 gpiod_direction_output(priv->enable_gpio, 1);
165 } else {
166 ret = regmap_write(priv->regmap, LM3697_RESET, LM3697_SW_RESET);
167 if (ret) {
168 dev_err(&priv->client->dev, "Cannot reset the device\n");
169 goto out;
170 }
171 }
172
173 ret = regmap_write(priv->regmap, LM3697_CTRL_ENABLE, 0x0);
174 if (ret) {
175 dev_err(&priv->client->dev, "Cannot write ctrl enable\n");
176 goto out;
177 }
178
179 ret = regmap_write(priv->regmap, LM3697_OUTPUT_CONFIG, priv->bank_cfg);
180 if (ret)
181 dev_err(&priv->client->dev, "Cannot write OUTPUT config\n");
182
183 for (i = 0; i < LM3697_MAX_CONTROL_BANKS; i++) {
184 led = &priv->leds[i];
185 ret = ti_lmu_common_set_ramp(&led->lmu_data);
186 if (ret)
187 dev_err(&priv->client->dev, "Setting the ramp rate failed\n");
188 }
189out:
190 return ret;
191}
192
193static int lm3697_probe_dt(struct lm3697 *priv)
194{
195 struct fwnode_handle *child = NULL;
196 struct lm3697_led *led;
197 const char *name;
198 int control_bank;
199 size_t i = 0;
200 int ret = -EINVAL;
201 int j;
202
203 priv->enable_gpio = devm_gpiod_get_optional(&priv->client->dev,
204 "enable", GPIOD_OUT_LOW);
205 if (IS_ERR(priv->enable_gpio)) {
206 ret = PTR_ERR(priv->enable_gpio);
207 dev_err(&priv->client->dev, "Failed to get enable gpio: %d\n",
208 ret);
209 return ret;
210 }
211
212 priv->regulator = devm_regulator_get(&priv->client->dev, "vled");
213 if (IS_ERR(priv->regulator))
214 priv->regulator = NULL;
215
216 device_for_each_child_node(priv->dev, child) {
217 ret = fwnode_property_read_u32(child, "reg", &control_bank);
218 if (ret) {
219 dev_err(&priv->client->dev, "reg property missing\n");
220 fwnode_handle_put(child);
221 goto child_out;
222 }
223
224 if (control_bank > LM3697_CONTROL_B) {
225 dev_err(&priv->client->dev, "reg property is invalid\n");
226 ret = -EINVAL;
227 fwnode_handle_put(child);
228 goto child_out;
229 }
230
231 led = &priv->leds[i];
232
233 ret = ti_lmu_common_get_brt_res(&priv->client->dev,
234 child, &led->lmu_data);
235 if (ret)
236 dev_warn(&priv->client->dev, "brightness resolution property missing\n");
237
238 led->control_bank = control_bank;
239 led->lmu_data.regmap = priv->regmap;
240 led->lmu_data.runtime_ramp_reg = LM3697_CTRL_A_RAMP +
241 control_bank;
242 led->lmu_data.msb_brightness_reg = LM3697_CTRL_A_BRT_MSB +
243 led->control_bank * 2;
244 led->lmu_data.lsb_brightness_reg = LM3697_CTRL_A_BRT_LSB +
245 led->control_bank * 2;
246
247 led->num_leds = fwnode_property_read_u32_array(child,
248 "led-sources",
249 NULL, 0);
250
251 if (led->num_leds > LM3697_MAX_LED_STRINGS) {
252 dev_err(&priv->client->dev, "To many LED strings defined\n");
253 continue;
254 }
255
256 ret = fwnode_property_read_u32_array(child, "led-sources",
257 led->hvled_strings,
258 led->num_leds);
259 if (ret) {
260 dev_err(&priv->client->dev, "led-sources property missing\n");
261 fwnode_handle_put(child);
262 goto child_out;
263 }
264
265 for (j = 0; j < led->num_leds; j++)
266 priv->bank_cfg |=
267 (led->control_bank << led->hvled_strings[j]);
268
269 ret = ti_lmu_common_get_ramp_params(&priv->client->dev,
270 child, &led->lmu_data);
271 if (ret)
272 dev_warn(&priv->client->dev, "runtime-ramp properties missing\n");
273
274 fwnode_property_read_string(child, "linux,default-trigger",
275 &led->led_dev.default_trigger);
276
277 ret = fwnode_property_read_string(child, "label", &name);
278 if (ret)
279 snprintf(led->label, sizeof(led->label),
280 "%s::", priv->client->name);
281 else
282 snprintf(led->label, sizeof(led->label),
283 "%s:%s", priv->client->name, name);
284
285 led->priv = priv;
286 led->led_dev.name = led->label;
287 led->led_dev.max_brightness = led->lmu_data.max_brightness;
288 led->led_dev.brightness_set_blocking = lm3697_brightness_set;
289
290 ret = devm_led_classdev_register(priv->dev, &led->led_dev);
291 if (ret) {
292 dev_err(&priv->client->dev, "led register err: %d\n",
293 ret);
294 fwnode_handle_put(child);
295 goto child_out;
296 }
297
298 i++;
299 }
300
301child_out:
302 return ret;
303}
304
305static int lm3697_probe(struct i2c_client *client,
306 const struct i2c_device_id *id)
307{
308 struct lm3697 *led;
309 int count;
310 int ret;
311
312 count = device_get_child_node_count(&client->dev);
313 if (!count) {
314 dev_err(&client->dev, "LEDs are not defined in device tree!");
315 return -ENODEV;
316 }
317
318 led = devm_kzalloc(&client->dev, struct_size(led, leds, count),
319 GFP_KERNEL);
320 if (!led)
321 return -ENOMEM;
322
323 mutex_init(&led->lock);
324 i2c_set_clientdata(client, led);
325
326 led->client = client;
327 led->dev = &client->dev;
328 led->regmap = devm_regmap_init_i2c(client, &lm3697_regmap_config);
329 if (IS_ERR(led->regmap)) {
330 ret = PTR_ERR(led->regmap);
331 dev_err(&client->dev, "Failed to allocate register map: %d\n",
332 ret);
333 return ret;
334 }
335
336 ret = lm3697_probe_dt(led);
337 if (ret)
338 return ret;
339
340 return lm3697_init(led);
341}
342
343static int lm3697_remove(struct i2c_client *client)
344{
345 struct lm3697 *led = i2c_get_clientdata(client);
346 int ret;
347
348 ret = regmap_update_bits(led->regmap, LM3697_CTRL_ENABLE,
349 LM3697_CTRL_A_B_EN, 0);
350 if (ret) {
351 dev_err(&led->client->dev, "Failed to disable the device\n");
352 return ret;
353 }
354
355 if (led->enable_gpio)
356 gpiod_direction_output(led->enable_gpio, 0);
357
358 if (led->regulator) {
359 ret = regulator_disable(led->regulator);
360 if (ret)
361 dev_err(&led->client->dev,
362 "Failed to disable regulator\n");
363 }
364
365 mutex_destroy(&led->lock);
366
367 return 0;
368}
369
370static const struct i2c_device_id lm3697_id[] = {
371 { "lm3697", 0 },
372 { }
373};
374MODULE_DEVICE_TABLE(i2c, lm3697_id);
375
376static const struct of_device_id of_lm3697_leds_match[] = {
377 { .compatible = "ti,lm3697", },
378 {},
379};
380MODULE_DEVICE_TABLE(of, of_lm3697_leds_match);
381
382static struct i2c_driver lm3697_driver = {
383 .driver = {
384 .name = "lm3697",
385 .of_match_table = of_lm3697_leds_match,
386 },
387 .probe = lm3697_probe,
388 .remove = lm3697_remove,
389 .id_table = lm3697_id,
390};
391module_i2c_driver(lm3697_driver);
392
393MODULE_DESCRIPTION("Texas Instruments LM3697 LED driver");
394MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
395MODULE_LICENSE("GPL v2");