1 /*
2 * Simple driver for multi-string single control backlight driver chips of
3 * Texas Instruments.
4 *
5 * Copyright (C) 2015 Texas Instruments
6 * Author: Daniel Jeong <gshark.jeong@gmail.com>
7 * Ldd Mlp <ldd-mlp@list.ti.com>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 *
13 */
14 #include <linux/backlight.h>
15 #include <linux/delay.h>
16 #include <linux/err.h>
17 #include <linux/i2c.h>
18 #include <linux/module.h>
19 #include <linux/platform_data/ti-scbl.h>
20 #include <linux/regmap.h>
21 #include <linux/slab.h>
22 #include <linux/uaccess.h>
24 #define scbl_attr(_name, _show, _store)\
25 {\
26 .attr = {\
27 .name = _name,\
28 .mode = S_IWUSR | S_IRUSR,\
29 },\
30 .show = _show,\
31 .store = _store,\
32 }
34 struct scbl_reg_ctrl {
35 unsigned int reg;
36 unsigned int mask;
37 unsigned int shift;
38 };
40 /*
41 *brightness control
42 *@min : minimum brightness
43 *@max : maximum brightness
44 *@msb_shift : msb bit shfit
45 *@lsb_mask : lsb bit mask
46 *@msb : register for the upper 8bits of the brightness code
47 *@lsb : register for the lower 8bits of the brightness code
48 */
49 struct scbl_brt_ctrl {
50 unsigned int min;
51 unsigned int max;
52 unsigned int msb_shift;
53 unsigned int lsb_mask;
54 struct scbl_reg_ctrl msb;
55 struct scbl_reg_ctrl lsb;
56 };
58 /*
59 *fault data
60 *@reg : fault register
61 *@mask: mask bit of fault
62 *@bl_fault : backlight fault mapped the bit
63 */
64 struct scbl_fault {
65 unsigned int reg;
66 unsigned int mask;
67 unsigned int bl_fault;
68 };
70 /*
71 *single control backlight data
72 *@name : chip name
73 *@num_led : number of led string
74 *@en_chip : chip enable register
75 *@en_led : led string enable register
76 *@brt : brightness register
77 *@fault : fault register
78 *@boot : function that should be called before chip enable
79 *@init : function that should be called after chip enable
80 *@reset : reset function
81 *@num_devnode : number of device node to be created
82 *@scbl_dev_attr : device node attribute
83 */
84 struct scbl_data {
85 char *name;
87 int num_led;
88 struct scbl_reg_ctrl en_chip;
89 struct scbl_reg_ctrl en_led[SCBL_LED_MAX];
91 struct scbl_brt_ctrl brt;
92 struct scbl_fault fault[SCBL_FAULT_MAX];
94 int (*boot)(struct regmap* regmap);
95 int (*init)(struct regmap* regmap);
96 int (*reset)(struct regmap* regmap);
98 int num_devnode;
99 struct device_attribute *scbl_dev_attr;
100 };
102 /*
103 *chip data
104 *@dev : device
105 *@regmap: register map
106 *@bled : backlight device
107 *@data : single control backlight data
108 */
109 struct scbl_chip {
110 struct device *dev;
111 struct regmap *regmap;
113 struct backlight_device *bled;
114 const struct scbl_data *data;
115 };
117 /* chip reset */
118 static ssize_t scbl_reset_store(struct device *dev,
119 struct device_attribute *attr,
120 const char *buf, size_t size)
121 {
122 struct scbl_chip *pchip = dev_get_drvdata(dev);
123 const struct scbl_data *data = pchip->data;
124 u8 input;
125 int ret;
127 if (kstrtou8(buf, 0, &input))
128 return -EINVAL;
130 if (input == 1) {
131 ret = data->reset(pchip->regmap);
132 if (ret<0)
133 return ret;
134 }
135 return size;
136 }
138 /* fault status */
139 static ssize_t scbl_fault_show(struct device *dev,
140 struct device_attribute *attr, char *buf)
141 {
142 struct scbl_chip *pchip = dev_get_drvdata(dev);
143 const struct scbl_data *data = pchip->data;
144 unsigned int reg_val, reg = 0xfff;
145 s32 fault = 0x0000;
146 int ret, icnt;
148 for(icnt = 0; icnt < SCBL_FAULT_MAX; icnt++) {
149 if(data->fault[icnt].mask == 0x00)
150 continue;
151 if(data->fault[icnt].reg != reg) {
152 reg = data->fault[icnt].reg;
153 ret = regmap_read(pchip->regmap, reg, ®_val);
154 if (ret < 0) {
155 dev_err(pchip->dev,
156 "fail : i2c access to register.\n");
157 return sprintf(buf, "%d\n", ret);
158 }
159 }
160 if (reg_val & data->fault[icnt].mask)
161 fault |= data->fault[icnt].bl_fault;
162 }
163 return sprintf(buf, "%d\n", fault);
164 }
166 /* chip enable control */
167 static ssize_t scbl_enable_show(struct device *dev,
168 struct device_attribute *attr, char *buf)
169 {
170 struct scbl_chip *pchip = dev_get_drvdata(dev);
171 const struct scbl_data *data = pchip->data;
172 unsigned int reg_val;
173 int ret;
175 ret = regmap_read(pchip->regmap, data->en_chip.reg, ®_val);
176 if (ret <0) {
177 return sprintf(buf, "%d\n", -EINVAL);
178 }
179 return sprintf(buf, "%d\n",
180 (reg_val & data->en_chip.mask) >> data->en_chip.shift);
181 }
183 static ssize_t scbl_enable_store(struct device *dev,
184 struct device_attribute *attr,
185 const char *buf, size_t size)
186 {
187 struct scbl_chip *pchip = dev_get_drvdata(dev);
188 const struct scbl_data *data = pchip->data;
189 int ret;
190 u8 input;
192 if (kstrtou8(buf, 0, &input))
193 return -EINVAL;
195 if (input == 0)
196 ret = regmap_update_bits(pchip->regmap,
197 data->en_chip.reg, data->en_chip.mask, 0x00);
198 else
199 ret = regmap_update_bits(pchip->regmap, data->en_chip.reg,
200 data->en_chip.mask, 0x01 << data->en_chip.shift);
201 if(ret <0)
202 return ret;
204 return size;
205 }
207 /* brightness control */
208 static int scbl_update_status(struct backlight_device *bl)
209 {
210 struct scbl_chip *pchip = bl_get_data(bl);
211 const struct scbl_data *data = pchip->data;
212 int ret = -EINVAL;
213 int msb, lsb;
215 if (bl->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK))
216 bl->props.brightness = 0;
218 /* lsb write first */
219 if(data->brt.lsb_mask != 0x00) {
220 msb = bl->props.brightness >> data->brt.msb_shift ;
221 lsb = bl->props.brightness & data->brt.lsb_mask ;
223 ret = regmap_update_bits(pchip->regmap, data->brt.lsb.reg,
224 data->brt.lsb.mask, lsb << data->brt.lsb.shift);
225 } else {
226 msb = bl->props.brightness;
227 }
229 /* msb write */
230 ret = regmap_update_bits(pchip->regmap, data->brt.msb.reg,
231 data->brt.msb.mask, msb << data->brt.msb.shift);
233 if (ret < 0)
234 dev_err(pchip->dev, "fail : i2c access to register.\n");
235 else
236 ret = bl->props.brightness;
238 return ret;
239 }
241 static int scbl_get_brightness(struct backlight_device *bl)
242 {
243 return bl->props.brightness;
244 }
246 static const struct backlight_ops scbl_bled_ops = {
247 .options = BL_CORE_SUSPENDRESUME,
248 .update_status = scbl_update_status,
249 .get_brightness = scbl_get_brightness,
250 };
252 /*
253 * LP36923 backlight chip data
254 * lp36923 is an ultra-compact, highly efficient, three string white-LED
255 * driver.
256 */
257 static struct device_attribute lm36923_dev_attr[] = {
258 scbl_attr("fault", scbl_fault_show, NULL),
259 scbl_attr("reset", NULL, scbl_reset_store),
260 scbl_attr("enable", scbl_enable_show, scbl_enable_store),
261 };
263 static int scbl_lm36923_reset(struct regmap *regmap)
264 {
265 return regmap_update_bits(regmap, 0x01, 0x01, 0x01);
266 }
268 static int scbl_lm36923_boot(struct regmap *regmap)
269 {
270 int rval;
272 rval = regmap_update_bits(regmap, 0x10, 0x0f, 0x00);
273 /*
274 * For glitch free operation, the following data should
275 * only be written while chine enable bit is 0
276 */
277 /* mapping mode / brt mode / ramp / ramp rate / bl_adj polarity */
278 rval |= regmap_write(regmap, 0x11, 0x81);
279 /* pwm */
280 rval |= regmap_write(regmap, 0x12, 0x73);
281 /* auto frequency high threshold */
282 rval |= regmap_write(regmap, 0x15, 0x00);
283 /* auto frequency low threshold */
284 rval |= regmap_write(regmap, 0x16, 0x00);
285 /* backlight adjust threshold */
286 rval |= regmap_write(regmap, 0x17, 0x00);
287 /* chip and leds enable */
288 rval |= regmap_update_bits(regmap, 0x10, 0x0f, 0x0f);
289 return rval;
290 }
292 static const struct scbl_data bl_lm36923 = {
293 .name = LM36923_NAME,
294 .num_led = 3,
295 .en_chip = {.reg = 0x10, .mask = 0x01, .shift = 0},
296 .en_led = {
297 [0] = {.reg = 0x10, .mask = 0x02, .shift = 1},
298 [1] = {.reg = 0x10, .mask = 0x04, .shift = 2},
299 [2] = {.reg = 0x10, .mask = 0x08, .shift = 3},
300 },
301 .brt = {
302 .min = 0x00, .max = 0x7ff,
303 .msb_shift = 3, .lsb_mask = 0x07,
304 .msb = {.reg = 0x19, .mask = 0xff, .shift = 0},
305 .lsb = {.reg = 0x18, .mask = 0x07, .shift = 0},
306 },
307 .fault = {
308 [0] = {
309 .reg = 0x1f, .mask = 0x01,
310 .bl_fault = SCBL_FAULT_OVER_VOLTAGE
311 },
312 [1] = {
313 .reg = 0x1f, .mask = 0x02,
314 .bl_fault = SCBL_FAULT_OVER_CURRENT
315 },
316 [2] = {
317 .reg = 0x1f, .mask = 0x04,
318 .bl_fault = SCBL_FAULT_THERMAL_SHDN
319 },
320 [3] = {
321 .reg = 0x1f, .mask = 0x08,
322 .bl_fault = SCBL_FAULT_LED_SHORT
323 },
324 [4] = {
325 .reg = 0x1f, .mask = 0x10,
326 .bl_fault = SCBL_FAULT_LED_OPEN
327 },
328 },
329 .boot = scbl_lm36923_boot,
330 .init = NULL,
331 .reset = scbl_lm36923_reset,
332 .num_devnode = 3,
333 .scbl_dev_attr = lm36923_dev_attr,
334 };
336 static const struct regmap_config scbl_regmap = {
337 .reg_bits = 8,
338 .val_bits = 8,
339 .max_register = SCBL_REG_MAX,
340 };
342 static int scbl_probe(struct i2c_client *client,
343 const struct i2c_device_id *devid)
344 {
345 struct scbl_chip *pchip;
346 struct backlight_properties props;
347 int ret, icnt;
349 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
350 dev_err(&client->dev, "fail : i2c functionality check.\n");
351 return -EOPNOTSUPP;
352 }
354 pchip = devm_kzalloc(&client->dev,
355 sizeof(struct scbl_chip), GFP_KERNEL);
356 if (!pchip)
357 return -ENOMEM;
358 pchip->dev = &client->dev;
360 pchip->regmap = devm_regmap_init_i2c(client, &scbl_regmap);
361 if (IS_ERR(pchip->regmap)) {
362 ret = PTR_ERR(pchip->regmap);
363 dev_err(pchip->dev, "fail : allocate i2c register map.\n");
364 return ret;
365 }
367 pchip->data = (const struct scbl_data *)devid->driver_data;
368 i2c_set_clientdata(client, pchip);
370 props.brightness = 0;
371 props.type = BACKLIGHT_RAW;
372 props.max_brightness = pchip->data->brt.max;
373 pchip->bled = devm_backlight_device_register(pchip->dev,
374 pchip->data->name,
375 pchip->dev,
376 pchip, &scbl_bled_ops,
377 &props);
378 if (IS_ERR(pchip->bled)) {
379 dev_err(pchip->dev, "fail : backlight register.\n");
380 ret = PTR_ERR(pchip->bled);
381 return ret;
382 }
384 for (icnt = 0; icnt < pchip->data->num_devnode; icnt++) {
385 ret =
386 device_create_file(&(pchip->bled->dev),
387 &(pchip->data->scbl_dev_attr)[icnt]);
388 if (ret < 0) {
389 dev_err(pchip->dev, "fail : node create\n");
390 goto err_out;
391 }
392 }
393 /* chip boot sequence before chip enable */
394 if(pchip->data->boot != NULL) {
395 ret = pchip->data->boot(pchip->regmap);
396 if (ret < 0)
397 goto err_out;
398 }
399 /* chip enable */
400 ret = regmap_update_bits(pchip->regmap, pchip->data->en_chip.reg,
401 pchip->data->en_chip.mask,
402 0x01<<pchip->data->en_chip.shift);
404 /* chip init sequence after chip enable */
405 if(pchip->data->init != NULL) {
406 ret = pchip->data->boot(pchip->regmap);
407 if (ret < 0)
408 goto err_out;
409 }
410 dev_info(pchip->dev, "[%s] initialized.\n", pchip->data->name);
411 return 0;
413 err_out:
414 while (--icnt >= 0)
415 device_remove_file(&(pchip->bled->dev),
416 &(pchip->data->scbl_dev_attr)[icnt]);
417 dev_info(pchip->dev, "[%s] init failed.\n", pchip->data->name);
418 return ret;
419 }
421 static int scbl_remove(struct i2c_client *client)
422 {
423 struct scbl_chip *pchip = i2c_get_clientdata(client);
424 int icnt;
426 for (icnt = 0; icnt < pchip->data->num_devnode; icnt++)
427 device_remove_file(&(pchip->bled->dev),
428 &(pchip->data->scbl_dev_attr)[icnt]);
429 return 0;
430 }
432 static const struct i2c_device_id scbl_id[] = {
433 {LM36923_NAME, (unsigned long)&bl_lm36923},
434 {}
435 };
437 MODULE_DEVICE_TABLE(i2c, scbl_id);
438 static struct i2c_driver scbl_i2c_driver = {
439 .driver = {
440 .name = TI_SINGLE_CONTROL_BL_NAME,
441 },
442 .probe = scbl_probe,
443 .remove = scbl_remove,
444 .id_table = scbl_id,
445 };
447 module_i2c_driver(scbl_i2c_driver);
449 MODULE_DESCRIPTION("Texas Instruments Single Control Backlight Driver");
450 MODULE_AUTHOR("Daniel Jeong <gshark.jeong@gmail.com>");
451 MODULE_AUTHOR("Ldd Mlp <ldd-mlp@list.ti.com>");
452 MODULE_LICENSE("GPL v2");