aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohan Hovold <jhovold@gmail.com>2012-05-03 06:26:36 -0400
committerSamuel Ortiz <sameo@linux.intel.com>2012-05-09 11:20:01 -0400
commit16c5c023aac86228e3e94c4bf6d19708ea861a05 (patch)
tree2fb7e87ef18d2520e4e0e957e4512c9f92a3886d
parentae8406357eca7fde4ff047e858d285faee836804 (diff)
mfd: Add LM3533 lighting-power core driver
Add support for National Semiconductor / TI LM3533 lighting power chips. This is the core driver which provides register access over I2C and registers the ambient-light-sensor, LED and backlight sub-drivers. Signed-off-by: Johan Hovold <jhovold@gmail.com> Reviewed-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
-rw-r--r--Documentation/ABI/testing/sysfs-bus-i2c-devices-lm353338
-rw-r--r--drivers/mfd/Kconfig13
-rw-r--r--drivers/mfd/Makefile1
-rw-r--r--drivers/mfd/lm3533-core.c717
-rw-r--r--drivers/mfd/lm3533-ctrlbank.c134
-rw-r--r--include/linux/mfd/lm3533.h89
6 files changed, 992 insertions, 0 deletions
diff --git a/Documentation/ABI/testing/sysfs-bus-i2c-devices-lm3533 b/Documentation/ABI/testing/sysfs-bus-i2c-devices-lm3533
new file mode 100644
index 000000000000..570072180b8d
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-i2c-devices-lm3533
@@ -0,0 +1,38 @@
1What: /sys/bus/i2c/devices/.../boost_freq
2Date: April 2012
3KernelVersion: 3.5
4Contact: Johan Hovold <jhovold@gmail.com>
5Description:
6 Set the boost converter switching frequency (0, 1), where
7
8 0 - 500Hz
9 1 - 1000Hz
10
11What: /sys/bus/i2c/devices/.../boost_ovp
12Date: April 2012
13KernelVersion: 3.5
14Contact: Johan Hovold <jhovold@gmail.com>
15Description:
16 Set the boost converter over-voltage protection threshold
17 (0..3), where
18
19 0 - 16V
20 1 - 24V
21 2 - 32V
22 3 - 40V
23
24What: /sys/bus/i2c/devices/.../output_hvled[n]
25Date: April 2012
26KernelVersion: 3.5
27Contact: Johan Hovold <jhovold@gmail.com>
28Description:
29 Set the controlling backlight device for high-voltage current
30 sink HVLED[n] (n = 1, 2) (0, 1).
31
32What: /sys/bus/i2c/devices/.../output_lvled[n]
33Date: April 2012
34KernelVersion: 3.5
35Contact: Johan Hovold <jhovold@gmail.com>
36Description:
37 Set the controlling led device for low-voltage current sink
38 LVLED[n] (n = 1..5) (0..3).
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 48eed22c65a5..211f5dee9b68 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -106,6 +106,19 @@ config UCB1400_CORE
106 To compile this driver as a module, choose M here: the 106 To compile this driver as a module, choose M here: the
107 module will be called ucb1400_core. 107 module will be called ucb1400_core.
108 108
109config MFD_LM3533
110 tristate "LM3533 Lighting Power chip"
111 depends on I2C
112 select MFD_CORE
113 select REGMAP_I2C
114 help
115 Say yes here to enable support for National Semiconductor / TI
116 LM3533 Lighting Power chips.
117
118 This driver provides common support for accessing the device;
119 additional drivers must be enabled in order to use the LED,
120 backlight or ambient-light-sensor functionality of the device.
121
109config TPS6105X 122config TPS6105X
110 tristate "TPS61050/61052 Boost Converters" 123 tristate "TPS61050/61052 Boost Converters"
111 depends on I2C 124 depends on I2C
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 0dc55cbefa09..d3dae9567800 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -120,3 +120,4 @@ obj-$(CONFIG_MFD_INTEL_MSIC) += intel_msic.o
120obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o 120obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o
121obj-$(CONFIG_MFD_S5M_CORE) += s5m-core.o s5m-irq.o 121obj-$(CONFIG_MFD_S5M_CORE) += s5m-core.o s5m-irq.o
122obj-$(CONFIG_MFD_ANATOP) += anatop-mfd.o 122obj-$(CONFIG_MFD_ANATOP) += anatop-mfd.o
123obj-$(CONFIG_MFD_LM3533) += lm3533-core.o lm3533-ctrlbank.o
diff --git a/drivers/mfd/lm3533-core.c b/drivers/mfd/lm3533-core.c
new file mode 100644
index 000000000000..75f4b7f5a4fd
--- /dev/null
+++ b/drivers/mfd/lm3533-core.c
@@ -0,0 +1,717 @@
1/*
2 * lm3533-core.c -- LM3533 Core
3 *
4 * Copyright (C) 2011-2012 Texas Instruments
5 *
6 * Author: Johan Hovold <jhovold@gmail.com>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 */
13
14#include <linux/module.h>
15#include <linux/init.h>
16#include <linux/kernel.h>
17#include <linux/err.h>
18#include <linux/gpio.h>
19#include <linux/i2c.h>
20#include <linux/mfd/core.h>
21#include <linux/regmap.h>
22#include <linux/seq_file.h>
23#include <linux/slab.h>
24#include <linux/uaccess.h>
25
26#include <linux/mfd/lm3533.h>
27
28
29#define LM3533_BOOST_OVP_MAX 0x03
30#define LM3533_BOOST_OVP_MASK 0x06
31#define LM3533_BOOST_OVP_SHIFT 1
32
33#define LM3533_BOOST_FREQ_MAX 0x01
34#define LM3533_BOOST_FREQ_MASK 0x01
35#define LM3533_BOOST_FREQ_SHIFT 0
36
37#define LM3533_BL_ID_MASK 1
38#define LM3533_LED_ID_MASK 3
39#define LM3533_BL_ID_MAX 1
40#define LM3533_LED_ID_MAX 3
41
42#define LM3533_HVLED_ID_MAX 2
43#define LM3533_LVLED_ID_MAX 5
44
45#define LM3533_REG_OUTPUT_CONF1 0x10
46#define LM3533_REG_OUTPUT_CONF2 0x11
47#define LM3533_REG_BOOST_PWM 0x2c
48
49#define LM3533_REG_MAX 0xb2
50
51
52static struct mfd_cell lm3533_als_devs[] = {
53 {
54 .name = "lm3533-als",
55 .id = -1,
56 },
57};
58
59static struct mfd_cell lm3533_bl_devs[] = {
60 {
61 .name = "lm3533-backlight",
62 .id = 0,
63 },
64 {
65 .name = "lm3533-backlight",
66 .id = 1,
67 },
68};
69
70static struct mfd_cell lm3533_led_devs[] = {
71 {
72 .name = "lm3533-leds",
73 .id = 0,
74 },
75 {
76 .name = "lm3533-leds",
77 .id = 1,
78 },
79 {
80 .name = "lm3533-leds",
81 .id = 2,
82 },
83 {
84 .name = "lm3533-leds",
85 .id = 3,
86 },
87};
88
89int lm3533_read(struct lm3533 *lm3533, u8 reg, u8 *val)
90{
91 int tmp;
92 int ret;
93
94 ret = regmap_read(lm3533->regmap, reg, &tmp);
95 if (ret < 0) {
96 dev_err(lm3533->dev, "failed to read register %02x: %d\n",
97 reg, ret);
98 return ret;
99 }
100
101 *val = tmp;
102
103 dev_dbg(lm3533->dev, "read [%02x]: %02x\n", reg, *val);
104
105 return ret;
106}
107EXPORT_SYMBOL_GPL(lm3533_read);
108
109int lm3533_write(struct lm3533 *lm3533, u8 reg, u8 val)
110{
111 int ret;
112
113 dev_dbg(lm3533->dev, "write [%02x]: %02x\n", reg, val);
114
115 ret = regmap_write(lm3533->regmap, reg, val);
116 if (ret < 0) {
117 dev_err(lm3533->dev, "failed to write register %02x: %d\n",
118 reg, ret);
119 }
120
121 return ret;
122}
123EXPORT_SYMBOL_GPL(lm3533_write);
124
125int lm3533_update(struct lm3533 *lm3533, u8 reg, u8 val, u8 mask)
126{
127 int ret;
128
129 dev_dbg(lm3533->dev, "update [%02x]: %02x/%02x\n", reg, val, mask);
130
131 ret = regmap_update_bits(lm3533->regmap, reg, val, mask);
132 if (ret < 0) {
133 dev_err(lm3533->dev, "failed to update register %02x: %d\n",
134 reg, ret);
135 }
136
137 return ret;
138}
139EXPORT_SYMBOL_GPL(lm3533_update);
140
141/*
142 * HVLED output config -- output hvled controlled by backlight bl
143 */
144static int lm3533_set_hvled_config(struct lm3533 *lm3533, u8 hvled, u8 bl)
145{
146 u8 val;
147 u8 mask;
148 int shift;
149 int ret;
150
151 if (hvled == 0 || hvled > LM3533_HVLED_ID_MAX)
152 return -EINVAL;
153
154 if (bl > LM3533_BL_ID_MAX)
155 return -EINVAL;
156
157 shift = hvled - 1;
158 mask = LM3533_BL_ID_MASK << shift;
159 val = bl << shift;
160
161 ret = lm3533_update(lm3533, LM3533_REG_OUTPUT_CONF1, val, mask);
162 if (ret)
163 dev_err(lm3533->dev, "failed to set hvled config\n");
164
165 return ret;
166}
167
168/*
169 * LVLED output config -- output lvled controlled by LED led
170 */
171static int lm3533_set_lvled_config(struct lm3533 *lm3533, u8 lvled, u8 led)
172{
173 u8 reg;
174 u8 val;
175 u8 mask;
176 int shift;
177 int ret;
178
179 if (lvled == 0 || lvled > LM3533_LVLED_ID_MAX)
180 return -EINVAL;
181
182 if (led > LM3533_LED_ID_MAX)
183 return -EINVAL;
184
185 if (lvled < 4) {
186 reg = LM3533_REG_OUTPUT_CONF1;
187 shift = 2 * lvled;
188 } else {
189 reg = LM3533_REG_OUTPUT_CONF2;
190 shift = 2 * (lvled - 4);
191 }
192
193 mask = LM3533_LED_ID_MASK << shift;
194 val = led << shift;
195
196 ret = lm3533_update(lm3533, reg, val, mask);
197 if (ret)
198 dev_err(lm3533->dev, "failed to set lvled config\n");
199
200 return ret;
201}
202
203static void lm3533_enable(struct lm3533 *lm3533)
204{
205 if (gpio_is_valid(lm3533->gpio_hwen))
206 gpio_set_value(lm3533->gpio_hwen, 1);
207}
208
209static void lm3533_disable(struct lm3533 *lm3533)
210{
211 if (gpio_is_valid(lm3533->gpio_hwen))
212 gpio_set_value(lm3533->gpio_hwen, 0);
213}
214
215enum lm3533_attribute_type {
216 LM3533_ATTR_TYPE_BACKLIGHT,
217 LM3533_ATTR_TYPE_LED,
218};
219
220struct lm3533_device_attribute {
221 struct device_attribute dev_attr;
222 enum lm3533_attribute_type type;
223 union {
224 struct {
225 u8 id;
226 } output;
227 struct {
228 u8 reg;
229 u8 shift;
230 u8 mask;
231 u8 max;
232 } generic;
233 } u;
234};
235
236#define to_lm3533_dev_attr(_attr) \
237 container_of(_attr, struct lm3533_device_attribute, dev_attr)
238
239static ssize_t show_lm3533_reg(struct device *dev,
240 struct device_attribute *attr, char *buf)
241{
242 struct lm3533 *lm3533 = dev_get_drvdata(dev);
243 struct lm3533_device_attribute *lattr = to_lm3533_dev_attr(attr);
244 u8 val;
245 int ret;
246
247 ret = lm3533_read(lm3533, lattr->u.generic.reg, &val);
248 if (ret)
249 return ret;
250
251 val = (val & lattr->u.generic.mask) >> lattr->u.generic.shift;
252
253 return scnprintf(buf, PAGE_SIZE, "%u\n", val);
254}
255
256static ssize_t store_lm3533_reg(struct device *dev,
257 struct device_attribute *attr,
258 const char *buf, size_t len)
259{
260 struct lm3533 *lm3533 = dev_get_drvdata(dev);
261 struct lm3533_device_attribute *lattr = to_lm3533_dev_attr(attr);
262 u8 val;
263 int ret;
264
265 if (kstrtou8(buf, 0, &val) || val > lattr->u.generic.max)
266 return -EINVAL;
267
268 val = val << lattr->u.generic.shift;
269 ret = lm3533_update(lm3533, lattr->u.generic.reg, val,
270 lattr->u.generic.mask);
271 if (ret)
272 return ret;
273
274 return len;
275}
276
277#define GENERIC_ATTR(_reg, _max, _mask, _shift) \
278 { .reg = _reg, \
279 .max = _max, \
280 .mask = _mask, \
281 .shift = _shift }
282
283#define LM3533_GENERIC_ATTR(_name, _mode, _show, _store, _type, \
284 _reg, _max, _mask, _shift) \
285 struct lm3533_device_attribute lm3533_dev_attr_##_name = { \
286 .dev_attr = __ATTR(_name, _mode, _show, _store), \
287 .type = _type, \
288 .u.generic = GENERIC_ATTR(_reg, _max, _mask, _shift) }
289
290#define LM3533_GENERIC_ATTR_RW(_name, _type, _reg, _max, _mask, _shift) \
291 LM3533_GENERIC_ATTR(_name, S_IRUGO | S_IWUSR, \
292 show_lm3533_reg, store_lm3533_reg, \
293 _type, _reg, _max, _mask, _shift)
294
295#define LM3533_BOOST_ATTR_RW(_name, _NAME) \
296 LM3533_GENERIC_ATTR_RW(_name, LM3533_ATTR_TYPE_BACKLIGHT, \
297 LM3533_REG_BOOST_PWM, LM3533_##_NAME##_MAX, \
298 LM3533_##_NAME##_MASK, LM3533_##_NAME##_SHIFT)
299/*
300 * Boost Over Voltage Protection Select
301 *
302 * 0 - 16 V (default)
303 * 1 - 24 V
304 * 2 - 32 V
305 * 3 - 40 V
306 */
307static LM3533_BOOST_ATTR_RW(boost_ovp, BOOST_OVP);
308
309/*
310 * Boost Frequency Select
311 *
312 * 0 - 500 kHz (default)
313 * 1 - 1 MHz
314 */
315static LM3533_BOOST_ATTR_RW(boost_freq, BOOST_FREQ);
316
317static ssize_t show_output(struct device *dev,
318 struct device_attribute *attr, char *buf)
319{
320 struct lm3533 *lm3533 = dev_get_drvdata(dev);
321 struct lm3533_device_attribute *lattr = to_lm3533_dev_attr(attr);
322 int id = lattr->u.output.id;
323 u8 reg;
324 u8 val;
325 u8 mask;
326 int shift;
327 int ret;
328
329 if (lattr->type == LM3533_ATTR_TYPE_BACKLIGHT) {
330 reg = LM3533_REG_OUTPUT_CONF1;
331 shift = id - 1;
332 mask = LM3533_BL_ID_MASK << shift;
333 } else {
334 if (id < 4) {
335 reg = LM3533_REG_OUTPUT_CONF1;
336 shift = 2 * id;
337 } else {
338 reg = LM3533_REG_OUTPUT_CONF2;
339 shift = 2 * (id - 4);
340 }
341 mask = LM3533_LED_ID_MASK << shift;
342 }
343
344 ret = lm3533_read(lm3533, reg, &val);
345 if (ret)
346 return ret;
347
348 val = (val & mask) >> shift;
349
350 return scnprintf(buf, PAGE_SIZE, "%u\n", val);
351}
352
353static ssize_t store_output(struct device *dev,
354 struct device_attribute *attr,
355 const char *buf, size_t len)
356{
357 struct lm3533 *lm3533 = dev_get_drvdata(dev);
358 struct lm3533_device_attribute *lattr = to_lm3533_dev_attr(attr);
359 int id = lattr->u.output.id;
360 u8 val;
361 int ret;
362
363 if (kstrtou8(buf, 0, &val))
364 return -EINVAL;
365
366 if (lattr->type == LM3533_ATTR_TYPE_BACKLIGHT)
367 ret = lm3533_set_hvled_config(lm3533, id, val);
368 else
369 ret = lm3533_set_lvled_config(lm3533, id, val);
370
371 if (ret)
372 return ret;
373
374 return len;
375}
376
377#define LM3533_OUTPUT_ATTR(_name, _mode, _show, _store, _type, _id) \
378 struct lm3533_device_attribute lm3533_dev_attr_##_name = \
379 { .dev_attr = __ATTR(_name, _mode, _show, _store), \
380 .type = _type, \
381 .u.output = { .id = _id }, }
382
383#define LM3533_OUTPUT_ATTR_RW(_name, _type, _id) \
384 LM3533_OUTPUT_ATTR(output_##_name, S_IRUGO | S_IWUSR, \
385 show_output, store_output, _type, _id)
386
387#define LM3533_OUTPUT_HVLED_ATTR_RW(_nr) \
388 LM3533_OUTPUT_ATTR_RW(hvled##_nr, LM3533_ATTR_TYPE_BACKLIGHT, _nr)
389#define LM3533_OUTPUT_LVLED_ATTR_RW(_nr) \
390 LM3533_OUTPUT_ATTR_RW(lvled##_nr, LM3533_ATTR_TYPE_LED, _nr)
391/*
392 * Output config:
393 *
394 * output_hvled<nr> 0-1
395 * output_lvled<nr> 0-3
396 */
397static LM3533_OUTPUT_HVLED_ATTR_RW(1);
398static LM3533_OUTPUT_HVLED_ATTR_RW(2);
399static LM3533_OUTPUT_LVLED_ATTR_RW(1);
400static LM3533_OUTPUT_LVLED_ATTR_RW(2);
401static LM3533_OUTPUT_LVLED_ATTR_RW(3);
402static LM3533_OUTPUT_LVLED_ATTR_RW(4);
403static LM3533_OUTPUT_LVLED_ATTR_RW(5);
404
405static struct attribute *lm3533_attributes[] = {
406 &lm3533_dev_attr_boost_freq.dev_attr.attr,
407 &lm3533_dev_attr_boost_ovp.dev_attr.attr,
408 &lm3533_dev_attr_output_hvled1.dev_attr.attr,
409 &lm3533_dev_attr_output_hvled2.dev_attr.attr,
410 &lm3533_dev_attr_output_lvled1.dev_attr.attr,
411 &lm3533_dev_attr_output_lvled2.dev_attr.attr,
412 &lm3533_dev_attr_output_lvled3.dev_attr.attr,
413 &lm3533_dev_attr_output_lvled4.dev_attr.attr,
414 &lm3533_dev_attr_output_lvled5.dev_attr.attr,
415 NULL,
416};
417
418#define to_dev_attr(_attr) \
419 container_of(_attr, struct device_attribute, attr)
420
421static mode_t lm3533_attr_is_visible(struct kobject *kobj,
422 struct attribute *attr, int n)
423{
424 struct device *dev = container_of(kobj, struct device, kobj);
425 struct lm3533 *lm3533 = dev_get_drvdata(dev);
426 struct device_attribute *dattr = to_dev_attr(attr);
427 struct lm3533_device_attribute *lattr = to_lm3533_dev_attr(dattr);
428 enum lm3533_attribute_type type = lattr->type;
429 mode_t mode = attr->mode;
430
431 if (!lm3533->have_backlights && type == LM3533_ATTR_TYPE_BACKLIGHT)
432 mode = 0;
433 else if (!lm3533->have_leds && type == LM3533_ATTR_TYPE_LED)
434 mode = 0;
435
436 return mode;
437};
438
439static struct attribute_group lm3533_attribute_group = {
440 .is_visible = lm3533_attr_is_visible,
441 .attrs = lm3533_attributes
442};
443
444static int __devinit lm3533_device_als_init(struct lm3533 *lm3533)
445{
446 struct lm3533_platform_data *pdata = lm3533->dev->platform_data;
447 int ret;
448
449 if (!pdata->als)
450 return 0;
451
452 lm3533_als_devs[0].platform_data = pdata->als;
453 lm3533_als_devs[0].pdata_size = sizeof(*pdata->als);
454
455 ret = mfd_add_devices(lm3533->dev, 0, lm3533_als_devs, 1, NULL, 0);
456 if (ret) {
457 dev_err(lm3533->dev, "failed to add ALS device\n");
458 return ret;
459 }
460
461 lm3533->have_als = 1;
462
463 return 0;
464}
465
466static int __devinit lm3533_device_bl_init(struct lm3533 *lm3533)
467{
468 struct lm3533_platform_data *pdata = lm3533->dev->platform_data;
469 int i;
470 int ret;
471
472 if (!pdata->backlights || pdata->num_backlights == 0)
473 return 0;
474
475 if (pdata->num_backlights > ARRAY_SIZE(lm3533_bl_devs))
476 pdata->num_backlights = ARRAY_SIZE(lm3533_bl_devs);
477
478 for (i = 0; i < pdata->num_backlights; ++i) {
479 lm3533_bl_devs[i].platform_data = &pdata->backlights[i];
480 lm3533_bl_devs[i].pdata_size = sizeof(pdata->backlights[i]);
481 }
482
483 ret = mfd_add_devices(lm3533->dev, 0, lm3533_bl_devs,
484 pdata->num_backlights, NULL, 0);
485 if (ret) {
486 dev_err(lm3533->dev, "failed to add backlight devices\n");
487 return ret;
488 }
489
490 lm3533->have_backlights = 1;
491
492 return 0;
493}
494
495static int __devinit lm3533_device_led_init(struct lm3533 *lm3533)
496{
497 struct lm3533_platform_data *pdata = lm3533->dev->platform_data;
498 int i;
499 int ret;
500
501 if (!pdata->leds || pdata->num_leds == 0)
502 return 0;
503
504 if (pdata->num_leds > ARRAY_SIZE(lm3533_led_devs))
505 pdata->num_leds = ARRAY_SIZE(lm3533_led_devs);
506
507 for (i = 0; i < pdata->num_leds; ++i) {
508 lm3533_led_devs[i].platform_data = &pdata->leds[i];
509 lm3533_led_devs[i].pdata_size = sizeof(pdata->leds[i]);
510 }
511
512 ret = mfd_add_devices(lm3533->dev, 0, lm3533_led_devs,
513 pdata->num_leds, NULL, 0);
514 if (ret) {
515 dev_err(lm3533->dev, "failed to add LED devices\n");
516 return ret;
517 }
518
519 lm3533->have_leds = 1;
520
521 return 0;
522}
523
524static int __devinit lm3533_device_init(struct lm3533 *lm3533)
525{
526 struct lm3533_platform_data *pdata = lm3533->dev->platform_data;
527 int ret;
528
529 dev_dbg(lm3533->dev, "%s\n", __func__);
530
531 if (!pdata) {
532 dev_err(lm3533->dev, "no platform data\n");
533 return -EINVAL;
534 }
535
536 lm3533->gpio_hwen = pdata->gpio_hwen;
537
538 dev_set_drvdata(lm3533->dev, lm3533);
539
540 if (gpio_is_valid(lm3533->gpio_hwen)) {
541 ret = gpio_request_one(lm3533->gpio_hwen, GPIOF_OUT_INIT_LOW,
542 "lm3533-hwen");
543 if (ret < 0) {
544 dev_err(lm3533->dev,
545 "failed to request HWEN GPIO %d\n",
546 lm3533->gpio_hwen);
547 return ret;
548 }
549 }
550
551 lm3533_enable(lm3533);
552
553 lm3533_device_als_init(lm3533);
554 lm3533_device_bl_init(lm3533);
555 lm3533_device_led_init(lm3533);
556
557 ret = sysfs_create_group(&lm3533->dev->kobj, &lm3533_attribute_group);
558 if (ret < 0) {
559 dev_err(lm3533->dev, "failed to create sysfs attributes\n");
560 goto err_unregister;
561 }
562
563 return 0;
564
565err_unregister:
566 mfd_remove_devices(lm3533->dev);
567 lm3533_disable(lm3533);
568 if (gpio_is_valid(lm3533->gpio_hwen))
569 gpio_free(lm3533->gpio_hwen);
570
571 return ret;
572}
573
574static void __devexit lm3533_device_exit(struct lm3533 *lm3533)
575{
576 dev_dbg(lm3533->dev, "%s\n", __func__);
577
578 sysfs_remove_group(&lm3533->dev->kobj, &lm3533_attribute_group);
579
580 mfd_remove_devices(lm3533->dev);
581 lm3533_disable(lm3533);
582 if (gpio_is_valid(lm3533->gpio_hwen))
583 gpio_free(lm3533->gpio_hwen);
584}
585
586static bool lm3533_readable_register(struct device *dev, unsigned int reg)
587{
588 switch (reg) {
589 case 0x10 ... 0x2c:
590 case 0x30 ... 0x38:
591 case 0x40 ... 0x45:
592 case 0x50 ... 0x57:
593 case 0x60 ... 0x6e:
594 case 0x70 ... 0x75:
595 case 0x80 ... 0x85:
596 case 0x90 ... 0x95:
597 case 0xa0 ... 0xa5:
598 case 0xb0 ... 0xb2:
599 return true;
600 default:
601 return false;
602 }
603}
604
605static bool lm3533_volatile_register(struct device *dev, unsigned int reg)
606{
607 switch (reg) {
608 case 0x34: /* zone */
609 case 0x37 ... 0x38: /* adc */
610 case 0xb0 ... 0xb1: /* fault */
611 return true;
612 default:
613 return false;
614 }
615}
616
617static bool lm3533_precious_register(struct device *dev, unsigned int reg)
618{
619 switch (reg) {
620 case 0x34: /* zone */
621 return true;
622 default:
623 return false;
624 }
625}
626
627static struct regmap_config regmap_config = {
628 .reg_bits = 8,
629 .val_bits = 8,
630 .max_register = LM3533_REG_MAX,
631 .readable_reg = lm3533_readable_register,
632 .volatile_reg = lm3533_volatile_register,
633 .precious_reg = lm3533_precious_register,
634};
635
636static int __devinit lm3533_i2c_probe(struct i2c_client *i2c,
637 const struct i2c_device_id *id)
638{
639 struct lm3533 *lm3533;
640 int ret;
641
642 dev_dbg(&i2c->dev, "%s\n", __func__);
643
644 lm3533 = kzalloc(sizeof(*lm3533), GFP_KERNEL);
645 if (!lm3533)
646 return -ENOMEM;
647
648 i2c_set_clientdata(i2c, lm3533);
649
650 lm3533->regmap = regmap_init_i2c(i2c, &regmap_config);
651 if (IS_ERR(lm3533->regmap)) {
652 ret = PTR_ERR(lm3533->regmap);
653 goto err_regmap;
654 }
655
656 lm3533->dev = &i2c->dev;
657 lm3533->irq = i2c->irq;
658
659 ret = lm3533_device_init(lm3533);
660 if (ret)
661 goto err_dev;
662
663 return 0;
664
665err_dev:
666 regmap_exit(lm3533->regmap);
667err_regmap:
668 kfree(lm3533);
669
670 return ret;
671}
672
673static int __devexit lm3533_i2c_remove(struct i2c_client *i2c)
674{
675 struct lm3533 *lm3533 = i2c_get_clientdata(i2c);
676
677 dev_dbg(&i2c->dev, "%s\n", __func__);
678
679 lm3533_device_exit(lm3533);
680 regmap_exit(lm3533->regmap);
681
682 kfree(lm3533);
683
684 return 0;
685}
686
687static const struct i2c_device_id lm3533_i2c_ids[] = {
688 { "lm3533", 0 },
689 { },
690};
691MODULE_DEVICE_TABLE(i2c, lm3533_i2c_ids);
692
693static struct i2c_driver lm3533_i2c_driver = {
694 .driver = {
695 .name = "lm3533",
696 .owner = THIS_MODULE,
697 },
698 .id_table = lm3533_i2c_ids,
699 .probe = lm3533_i2c_probe,
700 .remove = __devexit_p(lm3533_i2c_remove),
701};
702
703static int __init lm3533_i2c_init(void)
704{
705 return i2c_add_driver(&lm3533_i2c_driver);
706}
707subsys_initcall(lm3533_i2c_init);
708
709static void __exit lm3533_i2c_exit(void)
710{
711 i2c_del_driver(&lm3533_i2c_driver);
712}
713module_exit(lm3533_i2c_exit);
714
715MODULE_AUTHOR("Johan Hovold <jhovold@gmail.com>");
716MODULE_DESCRIPTION("LM3533 Core");
717MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/lm3533-ctrlbank.c b/drivers/mfd/lm3533-ctrlbank.c
new file mode 100644
index 000000000000..c2732a37c65a
--- /dev/null
+++ b/drivers/mfd/lm3533-ctrlbank.c
@@ -0,0 +1,134 @@
1/*
2 * lm3533-ctrlbank.c -- LM3533 Generic Control Bank interface
3 *
4 * Copyright (C) 2011-2012 Texas Instruments
5 *
6 * Author: Johan Hovold <jhovold@gmail.com>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 */
13
14#include <linux/device.h>
15#include <linux/module.h>
16
17#include <linux/mfd/lm3533.h>
18
19
20#define LM3533_BRIGHTNESS_MAX 255
21#define LM3533_MAX_CURRENT_MAX 31
22#define LM3533_PWM_MAX 0x3f
23
24#define LM3533_REG_PWM_BASE 0x14
25#define LM3533_REG_MAX_CURRENT_BASE 0x1f
26#define LM3533_REG_CTRLBANK_ENABLE 0x27
27#define LM3533_REG_BRIGHTNESS_BASE 0x40
28
29
30static inline u8 lm3533_ctrlbank_get_reg(struct lm3533_ctrlbank *cb, u8 base)
31{
32 return base + cb->id;
33}
34
35int lm3533_ctrlbank_enable(struct lm3533_ctrlbank *cb)
36{
37 u8 mask;
38 int ret;
39
40 dev_dbg(cb->dev, "%s - %d\n", __func__, cb->id);
41
42 mask = 1 << cb->id;
43 ret = lm3533_update(cb->lm3533, LM3533_REG_CTRLBANK_ENABLE,
44 mask, mask);
45 if (ret)
46 dev_err(cb->dev, "failed to enable ctrlbank %d\n", cb->id);
47
48 return ret;
49}
50EXPORT_SYMBOL_GPL(lm3533_ctrlbank_enable);
51
52int lm3533_ctrlbank_disable(struct lm3533_ctrlbank *cb)
53{
54 u8 mask;
55 int ret;
56
57 dev_dbg(cb->dev, "%s - %d\n", __func__, cb->id);
58
59 mask = 1 << cb->id;
60 ret = lm3533_update(cb->lm3533, LM3533_REG_CTRLBANK_ENABLE, 0, mask);
61 if (ret)
62 dev_err(cb->dev, "failed to disable ctrlbank %d\n", cb->id);
63
64 return ret;
65}
66EXPORT_SYMBOL_GPL(lm3533_ctrlbank_disable);
67
68#define lm3533_ctrlbank_set(_name, _NAME) \
69int lm3533_ctrlbank_set_##_name(struct lm3533_ctrlbank *cb, u8 val) \
70{ \
71 u8 reg; \
72 int ret; \
73 \
74 if (val > LM3533_##_NAME##_MAX) \
75 return -EINVAL; \
76 \
77 reg = lm3533_ctrlbank_get_reg(cb, LM3533_REG_##_NAME##_BASE); \
78 ret = lm3533_write(cb->lm3533, reg, val); \
79 if (ret) \
80 dev_err(cb->dev, "failed to set " #_name "\n"); \
81 \
82 return ret; \
83} \
84EXPORT_SYMBOL_GPL(lm3533_ctrlbank_set_##_name);
85
86#define lm3533_ctrlbank_get(_name, _NAME) \
87int lm3533_ctrlbank_get_##_name(struct lm3533_ctrlbank *cb, u8 *val) \
88{ \
89 u8 reg; \
90 int ret; \
91 \
92 reg = lm3533_ctrlbank_get_reg(cb, LM3533_REG_##_NAME##_BASE); \
93 ret = lm3533_read(cb->lm3533, reg, val); \
94 if (ret) \
95 dev_err(cb->dev, "failed to get " #_name "\n"); \
96 \
97 return ret; \
98} \
99EXPORT_SYMBOL_GPL(lm3533_ctrlbank_get_##_name);
100
101lm3533_ctrlbank_set(brightness, BRIGHTNESS);
102lm3533_ctrlbank_get(brightness, BRIGHTNESS);
103
104/*
105 * Full scale current.
106 *
107 * Imax = 5 + val * 0.8 mA, e.g.:
108 *
109 * 0 - 5 mA
110 * ...
111 * 19 - 20.2 mA (default)
112 * ...
113 * 31 - 29.8 mA
114 */
115lm3533_ctrlbank_set(max_current, MAX_CURRENT);
116lm3533_ctrlbank_get(max_current, MAX_CURRENT);
117
118/*
119 * PWM-input control mask:
120 *
121 * bit 5 - PWM-input enabled in Zone 4
122 * bit 4 - PWM-input enabled in Zone 3
123 * bit 3 - PWM-input enabled in Zone 2
124 * bit 2 - PWM-input enabled in Zone 1
125 * bit 1 - PWM-input enabled in Zone 0
126 * bit 0 - PWM-input enabled
127 */
128lm3533_ctrlbank_set(pwm, PWM);
129lm3533_ctrlbank_get(pwm, PWM);
130
131
132MODULE_AUTHOR("Johan Hovold <jhovold@gmail.com>");
133MODULE_DESCRIPTION("LM3533 Control Bank interface");
134MODULE_LICENSE("GPL");
diff --git a/include/linux/mfd/lm3533.h b/include/linux/mfd/lm3533.h
new file mode 100644
index 000000000000..75f85f3fbd90
--- /dev/null
+++ b/include/linux/mfd/lm3533.h
@@ -0,0 +1,89 @@
1/*
2 * lm3533.h -- LM3533 interface
3 *
4 * Copyright (C) 2011-2012 Texas Instruments
5 *
6 * Author: Johan Hovold <jhovold@gmail.com>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 */
13
14#ifndef __LINUX_MFD_LM3533_H
15#define __LINUX_MFD_LM3533_H
16
17#define LM3533_ATTR_RO(_name) \
18 DEVICE_ATTR(_name, S_IRUGO, show_##_name, NULL)
19#define LM3533_ATTR_RW(_name) \
20 DEVICE_ATTR(_name, S_IRUGO | S_IWUSR , show_##_name, store_##_name)
21
22struct device;
23struct regmap;
24
25struct lm3533 {
26 struct device *dev;
27
28 struct regmap *regmap;
29
30 int gpio_hwen;
31 int irq;
32
33 unsigned have_als:1;
34 unsigned have_backlights:1;
35 unsigned have_leds:1;
36};
37
38struct lm3533_ctrlbank {
39 struct lm3533 *lm3533;
40 struct device *dev;
41 int id;
42};
43
44struct lm3533_als_platform_data {
45 unsigned pwm_mode:1; /* PWM input mode (default analog) */
46};
47
48struct lm3533_bl_platform_data {
49 char *name;
50 u8 default_brightness; /* 0 - 255 */
51 u8 max_current; /* 0 - 31 */
52 u8 pwm; /* 0 - 0x3f */
53};
54
55struct lm3533_led_platform_data {
56 char *name;
57 const char *default_trigger;
58 u8 max_current; /* 0 - 31 */
59 u8 pwm; /* 0 - 0x3f */
60};
61
62struct lm3533_platform_data {
63 int gpio_hwen;
64
65 struct lm3533_als_platform_data *als;
66
67 struct lm3533_bl_platform_data *backlights;
68 int num_backlights;
69
70 struct lm3533_led_platform_data *leds;
71 int num_leds;
72};
73
74extern int lm3533_ctrlbank_enable(struct lm3533_ctrlbank *cb);
75extern int lm3533_ctrlbank_disable(struct lm3533_ctrlbank *cb);
76
77extern int lm3533_ctrlbank_set_brightness(struct lm3533_ctrlbank *cb, u8 val);
78extern int lm3533_ctrlbank_get_brightness(struct lm3533_ctrlbank *cb, u8 *val);
79extern int lm3533_ctrlbank_set_max_current(struct lm3533_ctrlbank *cb, u8 val);
80extern int lm3533_ctrlbank_get_max_current(struct lm3533_ctrlbank *cb,
81 u8 *val);
82extern int lm3533_ctrlbank_set_pwm(struct lm3533_ctrlbank *cb, u8 val);
83extern int lm3533_ctrlbank_get_pwm(struct lm3533_ctrlbank *cb, u8 *val);
84
85extern int lm3533_read(struct lm3533 *lm3533, u8 reg, u8 *val);
86extern int lm3533_write(struct lm3533 *lm3533, u8 reg, u8 val);
87extern int lm3533_update(struct lm3533 *lm3533, u8 reg, u8 val, u8 mask);
88
89#endif /* __LINUX_MFD_LM3533_H */