xref: /openbmc/linux/drivers/leds/leds-lm3533.c (revision 7ae9fb1b7ecbb5d85d07857943f677fd1a559b18)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2401dea7fSJohan Hovold /*
3401dea7fSJohan Hovold  * leds-lm3533.c -- LM3533 LED driver
4401dea7fSJohan Hovold  *
5401dea7fSJohan Hovold  * Copyright (C) 2011-2012 Texas Instruments
6401dea7fSJohan Hovold  *
7401dea7fSJohan Hovold  * Author: Johan Hovold <jhovold@gmail.com>
8401dea7fSJohan Hovold  */
9401dea7fSJohan Hovold 
10401dea7fSJohan Hovold #include <linux/module.h>
11401dea7fSJohan Hovold #include <linux/leds.h>
12401dea7fSJohan Hovold #include <linux/mfd/core.h>
13401dea7fSJohan Hovold #include <linux/mutex.h>
14401dea7fSJohan Hovold #include <linux/platform_device.h>
15401dea7fSJohan Hovold #include <linux/slab.h>
16401dea7fSJohan Hovold 
17401dea7fSJohan Hovold #include <linux/mfd/lm3533.h>
18401dea7fSJohan Hovold 
19401dea7fSJohan Hovold 
20401dea7fSJohan Hovold #define LM3533_LVCTRLBANK_MIN		2
21401dea7fSJohan Hovold #define LM3533_LVCTRLBANK_MAX		5
22401dea7fSJohan Hovold #define LM3533_LVCTRLBANK_COUNT		4
23401dea7fSJohan Hovold #define LM3533_RISEFALLTIME_MAX		7
24401dea7fSJohan Hovold #define LM3533_ALS_CHANNEL_LV_MIN	1
25401dea7fSJohan Hovold #define LM3533_ALS_CHANNEL_LV_MAX	2
26401dea7fSJohan Hovold 
27401dea7fSJohan Hovold #define LM3533_REG_CTRLBANK_BCONF_BASE		0x1b
28401dea7fSJohan Hovold #define LM3533_REG_PATTERN_ENABLE		0x28
29401dea7fSJohan Hovold #define LM3533_REG_PATTERN_LOW_TIME_BASE	0x71
30401dea7fSJohan Hovold #define LM3533_REG_PATTERN_HIGH_TIME_BASE	0x72
31401dea7fSJohan Hovold #define LM3533_REG_PATTERN_RISETIME_BASE	0x74
32401dea7fSJohan Hovold #define LM3533_REG_PATTERN_FALLTIME_BASE	0x75
33401dea7fSJohan Hovold 
34401dea7fSJohan Hovold #define LM3533_REG_PATTERN_STEP			0x10
35401dea7fSJohan Hovold 
36401dea7fSJohan Hovold #define LM3533_REG_CTRLBANK_BCONF_MAPPING_MASK		0x04
37401dea7fSJohan Hovold #define LM3533_REG_CTRLBANK_BCONF_ALS_EN_MASK		0x02
38401dea7fSJohan Hovold #define LM3533_REG_CTRLBANK_BCONF_ALS_CHANNEL_MASK	0x01
39401dea7fSJohan Hovold 
40401dea7fSJohan Hovold #define LM3533_LED_FLAG_PATTERN_ENABLE		1
41401dea7fSJohan Hovold 
42401dea7fSJohan Hovold 
43401dea7fSJohan Hovold struct lm3533_led {
44401dea7fSJohan Hovold 	struct lm3533 *lm3533;
45401dea7fSJohan Hovold 	struct lm3533_ctrlbank cb;
46401dea7fSJohan Hovold 	struct led_classdev cdev;
47401dea7fSJohan Hovold 	int id;
48401dea7fSJohan Hovold 
49401dea7fSJohan Hovold 	struct mutex mutex;
50401dea7fSJohan Hovold 	unsigned long flags;
51401dea7fSJohan Hovold };
52401dea7fSJohan Hovold 
53401dea7fSJohan Hovold 
to_lm3533_led(struct led_classdev * cdev)54401dea7fSJohan Hovold static inline struct lm3533_led *to_lm3533_led(struct led_classdev *cdev)
55401dea7fSJohan Hovold {
56401dea7fSJohan Hovold 	return container_of(cdev, struct lm3533_led, cdev);
57401dea7fSJohan Hovold }
58401dea7fSJohan Hovold 
lm3533_led_get_ctrlbank_id(struct lm3533_led * led)59401dea7fSJohan Hovold static inline int lm3533_led_get_ctrlbank_id(struct lm3533_led *led)
60401dea7fSJohan Hovold {
61401dea7fSJohan Hovold 	return led->id + 2;
62401dea7fSJohan Hovold }
63401dea7fSJohan Hovold 
lm3533_led_get_lv_reg(struct lm3533_led * led,u8 base)64401dea7fSJohan Hovold static inline u8 lm3533_led_get_lv_reg(struct lm3533_led *led, u8 base)
65401dea7fSJohan Hovold {
66401dea7fSJohan Hovold 	return base + led->id;
67401dea7fSJohan Hovold }
68401dea7fSJohan Hovold 
lm3533_led_get_pattern(struct lm3533_led * led)69401dea7fSJohan Hovold static inline u8 lm3533_led_get_pattern(struct lm3533_led *led)
70401dea7fSJohan Hovold {
71401dea7fSJohan Hovold 	return led->id;
72401dea7fSJohan Hovold }
73401dea7fSJohan Hovold 
lm3533_led_get_pattern_reg(struct lm3533_led * led,u8 base)74401dea7fSJohan Hovold static inline u8 lm3533_led_get_pattern_reg(struct lm3533_led *led,
75401dea7fSJohan Hovold 								u8 base)
76401dea7fSJohan Hovold {
77401dea7fSJohan Hovold 	return base + lm3533_led_get_pattern(led) * LM3533_REG_PATTERN_STEP;
78401dea7fSJohan Hovold }
79401dea7fSJohan Hovold 
lm3533_led_pattern_enable(struct lm3533_led * led,int enable)80401dea7fSJohan Hovold static int lm3533_led_pattern_enable(struct lm3533_led *led, int enable)
81401dea7fSJohan Hovold {
82401dea7fSJohan Hovold 	u8 mask;
83401dea7fSJohan Hovold 	u8 val;
84401dea7fSJohan Hovold 	int pattern;
85401dea7fSJohan Hovold 	int state;
86401dea7fSJohan Hovold 	int ret = 0;
87401dea7fSJohan Hovold 
88401dea7fSJohan Hovold 	dev_dbg(led->cdev.dev, "%s - %d\n", __func__, enable);
89401dea7fSJohan Hovold 
90401dea7fSJohan Hovold 	mutex_lock(&led->mutex);
91401dea7fSJohan Hovold 
92401dea7fSJohan Hovold 	state = test_bit(LM3533_LED_FLAG_PATTERN_ENABLE, &led->flags);
93401dea7fSJohan Hovold 	if ((enable && state) || (!enable && !state))
94401dea7fSJohan Hovold 		goto out;
95401dea7fSJohan Hovold 
96401dea7fSJohan Hovold 	pattern = lm3533_led_get_pattern(led);
97401dea7fSJohan Hovold 	mask = 1 << (2 * pattern);
98401dea7fSJohan Hovold 
99401dea7fSJohan Hovold 	if (enable)
100401dea7fSJohan Hovold 		val = mask;
101401dea7fSJohan Hovold 	else
102401dea7fSJohan Hovold 		val = 0;
103401dea7fSJohan Hovold 
104401dea7fSJohan Hovold 	ret = lm3533_update(led->lm3533, LM3533_REG_PATTERN_ENABLE, val, mask);
105401dea7fSJohan Hovold 	if (ret) {
106401dea7fSJohan Hovold 		dev_err(led->cdev.dev, "failed to enable pattern %d (%d)\n",
107401dea7fSJohan Hovold 							pattern, enable);
108401dea7fSJohan Hovold 		goto out;
109401dea7fSJohan Hovold 	}
110401dea7fSJohan Hovold 
111401dea7fSJohan Hovold 	__change_bit(LM3533_LED_FLAG_PATTERN_ENABLE, &led->flags);
112401dea7fSJohan Hovold out:
113401dea7fSJohan Hovold 	mutex_unlock(&led->mutex);
114401dea7fSJohan Hovold 
115401dea7fSJohan Hovold 	return ret;
116401dea7fSJohan Hovold }
117401dea7fSJohan Hovold 
lm3533_led_set(struct led_classdev * cdev,enum led_brightness value)118a478851cSAndrew Lunn static int lm3533_led_set(struct led_classdev *cdev,
119401dea7fSJohan Hovold 						enum led_brightness value)
120401dea7fSJohan Hovold {
121401dea7fSJohan Hovold 	struct lm3533_led *led = to_lm3533_led(cdev);
122401dea7fSJohan Hovold 
123401dea7fSJohan Hovold 	dev_dbg(led->cdev.dev, "%s - %d\n", __func__, value);
124401dea7fSJohan Hovold 
125a478851cSAndrew Lunn 	if (value == 0)
126a478851cSAndrew Lunn 		lm3533_led_pattern_enable(led, 0);	/* disable blink */
127a478851cSAndrew Lunn 
128a478851cSAndrew Lunn 	return lm3533_ctrlbank_set_brightness(&led->cb, value);
129401dea7fSJohan Hovold }
130401dea7fSJohan Hovold 
lm3533_led_get(struct led_classdev * cdev)131401dea7fSJohan Hovold static enum led_brightness lm3533_led_get(struct led_classdev *cdev)
132401dea7fSJohan Hovold {
133401dea7fSJohan Hovold 	struct lm3533_led *led = to_lm3533_led(cdev);
134401dea7fSJohan Hovold 	u8 val;
135401dea7fSJohan Hovold 	int ret;
136401dea7fSJohan Hovold 
137401dea7fSJohan Hovold 	ret = lm3533_ctrlbank_get_brightness(&led->cb, &val);
138401dea7fSJohan Hovold 	if (ret)
139401dea7fSJohan Hovold 		return ret;
140401dea7fSJohan Hovold 
141401dea7fSJohan Hovold 	dev_dbg(led->cdev.dev, "%s - %u\n", __func__, val);
142401dea7fSJohan Hovold 
143401dea7fSJohan Hovold 	return val;
144401dea7fSJohan Hovold }
145401dea7fSJohan Hovold 
146401dea7fSJohan Hovold /* Pattern generator defines (delays in us). */
147401dea7fSJohan Hovold #define LM3533_LED_DELAY1_VMIN	0x00
148401dea7fSJohan Hovold #define LM3533_LED_DELAY2_VMIN	0x3d
149401dea7fSJohan Hovold #define LM3533_LED_DELAY3_VMIN	0x80
150401dea7fSJohan Hovold 
151401dea7fSJohan Hovold #define LM3533_LED_DELAY1_VMAX	(LM3533_LED_DELAY2_VMIN - 1)
152401dea7fSJohan Hovold #define LM3533_LED_DELAY2_VMAX	(LM3533_LED_DELAY3_VMIN - 1)
153401dea7fSJohan Hovold #define LM3533_LED_DELAY3_VMAX	0xff
154401dea7fSJohan Hovold 
155401dea7fSJohan Hovold #define LM3533_LED_DELAY1_TMIN	16384U
156401dea7fSJohan Hovold #define LM3533_LED_DELAY2_TMIN	1130496U
157401dea7fSJohan Hovold #define LM3533_LED_DELAY3_TMIN	10305536U
158401dea7fSJohan Hovold 
159401dea7fSJohan Hovold #define LM3533_LED_DELAY1_TMAX	999424U
160401dea7fSJohan Hovold #define LM3533_LED_DELAY2_TMAX	9781248U
161401dea7fSJohan Hovold #define LM3533_LED_DELAY3_TMAX	76890112U
162401dea7fSJohan Hovold 
163401dea7fSJohan Hovold /* t_step = (t_max - t_min) / (v_max - v_min) */
164401dea7fSJohan Hovold #define LM3533_LED_DELAY1_TSTEP	16384
165401dea7fSJohan Hovold #define LM3533_LED_DELAY2_TSTEP	131072
166401dea7fSJohan Hovold #define LM3533_LED_DELAY3_TSTEP	524288
167401dea7fSJohan Hovold 
168401dea7fSJohan Hovold /* Delay limits for hardware accelerated blinking (in ms). */
169401dea7fSJohan Hovold #define LM3533_LED_DELAY_ON_MAX \
170401dea7fSJohan Hovold 	((LM3533_LED_DELAY2_TMAX + LM3533_LED_DELAY2_TSTEP / 2) / 1000)
171401dea7fSJohan Hovold #define LM3533_LED_DELAY_OFF_MAX \
172401dea7fSJohan Hovold 	((LM3533_LED_DELAY3_TMAX + LM3533_LED_DELAY3_TSTEP / 2) / 1000)
173401dea7fSJohan Hovold 
174401dea7fSJohan Hovold /*
175401dea7fSJohan Hovold  * Returns linear map of *t from [t_min,t_max] to [v_min,v_max] with a step
176401dea7fSJohan Hovold  * size of t_step, where
177401dea7fSJohan Hovold  *
178401dea7fSJohan Hovold  *	t_step = (t_max - t_min) / (v_max - v_min)
179401dea7fSJohan Hovold  *
180401dea7fSJohan Hovold  * and updates *t to reflect the mapped value.
181401dea7fSJohan Hovold  */
time_to_val(unsigned * t,unsigned t_min,unsigned t_step,u8 v_min,u8 v_max)182401dea7fSJohan Hovold static u8 time_to_val(unsigned *t, unsigned t_min, unsigned t_step,
183401dea7fSJohan Hovold 							u8 v_min, u8 v_max)
184401dea7fSJohan Hovold {
185401dea7fSJohan Hovold 	unsigned val;
186401dea7fSJohan Hovold 
187401dea7fSJohan Hovold 	val = (*t + t_step / 2 - t_min) / t_step + v_min;
188401dea7fSJohan Hovold 
189401dea7fSJohan Hovold 	*t = t_step * (val - v_min) + t_min;
190401dea7fSJohan Hovold 
191401dea7fSJohan Hovold 	return (u8)val;
192401dea7fSJohan Hovold }
193401dea7fSJohan Hovold 
194401dea7fSJohan Hovold /*
195401dea7fSJohan Hovold  * Returns time code corresponding to *delay (in ms) and updates *delay to
196401dea7fSJohan Hovold  * reflect actual hardware delay.
197401dea7fSJohan Hovold  *
198401dea7fSJohan Hovold  * Hardware supports 256 discrete delay times, divided into three groups with
199401dea7fSJohan Hovold  * the following ranges and step-sizes:
200401dea7fSJohan Hovold  *
201401dea7fSJohan Hovold  *	[   16,   999]	[0x00, 0x3e]	step  16 ms
202401dea7fSJohan Hovold  *	[ 1130,  9781]	[0x3d, 0x7f]	step 131 ms
203401dea7fSJohan Hovold  *	[10306, 76890]	[0x80, 0xff]	step 524 ms
204401dea7fSJohan Hovold  *
205401dea7fSJohan Hovold  * Note that delay group 3 is only available for delay_off.
206401dea7fSJohan Hovold  */
lm3533_led_get_hw_delay(unsigned * delay)207401dea7fSJohan Hovold static u8 lm3533_led_get_hw_delay(unsigned *delay)
208401dea7fSJohan Hovold {
209401dea7fSJohan Hovold 	unsigned t;
210401dea7fSJohan Hovold 	u8 val;
211401dea7fSJohan Hovold 
212401dea7fSJohan Hovold 	t = *delay * 1000;
213401dea7fSJohan Hovold 
214401dea7fSJohan Hovold 	if (t >= (LM3533_LED_DELAY2_TMAX + LM3533_LED_DELAY3_TMIN) / 2) {
215401dea7fSJohan Hovold 		t = clamp(t, LM3533_LED_DELAY3_TMIN, LM3533_LED_DELAY3_TMAX);
216401dea7fSJohan Hovold 		val = time_to_val(&t,	LM3533_LED_DELAY3_TMIN,
217401dea7fSJohan Hovold 					LM3533_LED_DELAY3_TSTEP,
218401dea7fSJohan Hovold 					LM3533_LED_DELAY3_VMIN,
219401dea7fSJohan Hovold 					LM3533_LED_DELAY3_VMAX);
220401dea7fSJohan Hovold 	} else if (t >= (LM3533_LED_DELAY1_TMAX + LM3533_LED_DELAY2_TMIN) / 2) {
221401dea7fSJohan Hovold 		t = clamp(t, LM3533_LED_DELAY2_TMIN, LM3533_LED_DELAY2_TMAX);
222401dea7fSJohan Hovold 		val = time_to_val(&t,	LM3533_LED_DELAY2_TMIN,
223401dea7fSJohan Hovold 					LM3533_LED_DELAY2_TSTEP,
224401dea7fSJohan Hovold 					LM3533_LED_DELAY2_VMIN,
225401dea7fSJohan Hovold 					LM3533_LED_DELAY2_VMAX);
226401dea7fSJohan Hovold 	} else {
227401dea7fSJohan Hovold 		t = clamp(t, LM3533_LED_DELAY1_TMIN, LM3533_LED_DELAY1_TMAX);
228401dea7fSJohan Hovold 		val = time_to_val(&t,	LM3533_LED_DELAY1_TMIN,
229401dea7fSJohan Hovold 					LM3533_LED_DELAY1_TSTEP,
230401dea7fSJohan Hovold 					LM3533_LED_DELAY1_VMIN,
231401dea7fSJohan Hovold 					LM3533_LED_DELAY1_VMAX);
232401dea7fSJohan Hovold 	}
233401dea7fSJohan Hovold 
234401dea7fSJohan Hovold 	*delay = (t + 500) / 1000;
235401dea7fSJohan Hovold 
236401dea7fSJohan Hovold 	return val;
237401dea7fSJohan Hovold }
238401dea7fSJohan Hovold 
239401dea7fSJohan Hovold /*
240401dea7fSJohan Hovold  * Set delay register base to *delay (in ms) and update *delay to reflect
241401dea7fSJohan Hovold  * actual hardware delay used.
242401dea7fSJohan Hovold  */
lm3533_led_delay_set(struct lm3533_led * led,u8 base,unsigned long * delay)243401dea7fSJohan Hovold static u8 lm3533_led_delay_set(struct lm3533_led *led, u8 base,
244401dea7fSJohan Hovold 							unsigned long *delay)
245401dea7fSJohan Hovold {
246401dea7fSJohan Hovold 	unsigned t;
247401dea7fSJohan Hovold 	u8 val;
248401dea7fSJohan Hovold 	u8 reg;
249401dea7fSJohan Hovold 	int ret;
250401dea7fSJohan Hovold 
251401dea7fSJohan Hovold 	t = (unsigned)*delay;
252401dea7fSJohan Hovold 
253401dea7fSJohan Hovold 	/* Delay group 3 is only available for low time (delay off). */
254401dea7fSJohan Hovold 	if (base != LM3533_REG_PATTERN_LOW_TIME_BASE)
255401dea7fSJohan Hovold 		t = min(t, LM3533_LED_DELAY2_TMAX / 1000);
256401dea7fSJohan Hovold 
257401dea7fSJohan Hovold 	val = lm3533_led_get_hw_delay(&t);
258401dea7fSJohan Hovold 
259401dea7fSJohan Hovold 	dev_dbg(led->cdev.dev, "%s - %lu: %u (0x%02x)\n", __func__,
260401dea7fSJohan Hovold 							*delay, t, val);
261401dea7fSJohan Hovold 	reg = lm3533_led_get_pattern_reg(led, base);
262401dea7fSJohan Hovold 	ret = lm3533_write(led->lm3533, reg, val);
263401dea7fSJohan Hovold 	if (ret)
264401dea7fSJohan Hovold 		dev_err(led->cdev.dev, "failed to set delay (%02x)\n", reg);
265401dea7fSJohan Hovold 
266401dea7fSJohan Hovold 	*delay = t;
267401dea7fSJohan Hovold 
268401dea7fSJohan Hovold 	return ret;
269401dea7fSJohan Hovold }
270401dea7fSJohan Hovold 
lm3533_led_delay_on_set(struct lm3533_led * led,unsigned long * t)271401dea7fSJohan Hovold static int lm3533_led_delay_on_set(struct lm3533_led *led, unsigned long *t)
272401dea7fSJohan Hovold {
273401dea7fSJohan Hovold 	return lm3533_led_delay_set(led, LM3533_REG_PATTERN_HIGH_TIME_BASE, t);
274401dea7fSJohan Hovold }
275401dea7fSJohan Hovold 
lm3533_led_delay_off_set(struct lm3533_led * led,unsigned long * t)276401dea7fSJohan Hovold static int lm3533_led_delay_off_set(struct lm3533_led *led, unsigned long *t)
277401dea7fSJohan Hovold {
278401dea7fSJohan Hovold 	return lm3533_led_delay_set(led, LM3533_REG_PATTERN_LOW_TIME_BASE, t);
279401dea7fSJohan Hovold }
280401dea7fSJohan Hovold 
lm3533_led_blink_set(struct led_classdev * cdev,unsigned long * delay_on,unsigned long * delay_off)281401dea7fSJohan Hovold static int lm3533_led_blink_set(struct led_classdev *cdev,
282401dea7fSJohan Hovold 				unsigned long *delay_on,
283401dea7fSJohan Hovold 				unsigned long *delay_off)
284401dea7fSJohan Hovold {
285401dea7fSJohan Hovold 	struct lm3533_led *led = to_lm3533_led(cdev);
286401dea7fSJohan Hovold 	int ret;
287401dea7fSJohan Hovold 
288401dea7fSJohan Hovold 	dev_dbg(led->cdev.dev, "%s - on = %lu, off = %lu\n", __func__,
289401dea7fSJohan Hovold 							*delay_on, *delay_off);
290401dea7fSJohan Hovold 
291401dea7fSJohan Hovold 	if (*delay_on > LM3533_LED_DELAY_ON_MAX ||
292401dea7fSJohan Hovold 					*delay_off > LM3533_LED_DELAY_OFF_MAX)
293401dea7fSJohan Hovold 		return -EINVAL;
294401dea7fSJohan Hovold 
295401dea7fSJohan Hovold 	if (*delay_on == 0 && *delay_off == 0) {
296401dea7fSJohan Hovold 		*delay_on = 500;
297401dea7fSJohan Hovold 		*delay_off = 500;
298401dea7fSJohan Hovold 	}
299401dea7fSJohan Hovold 
300401dea7fSJohan Hovold 	ret = lm3533_led_delay_on_set(led, delay_on);
301401dea7fSJohan Hovold 	if (ret)
302401dea7fSJohan Hovold 		return ret;
303401dea7fSJohan Hovold 
304401dea7fSJohan Hovold 	ret = lm3533_led_delay_off_set(led, delay_off);
305401dea7fSJohan Hovold 	if (ret)
306401dea7fSJohan Hovold 		return ret;
307401dea7fSJohan Hovold 
308401dea7fSJohan Hovold 	return lm3533_led_pattern_enable(led, 1);
309401dea7fSJohan Hovold }
310401dea7fSJohan Hovold 
show_id(struct device * dev,struct device_attribute * attr,char * buf)311401dea7fSJohan Hovold static ssize_t show_id(struct device *dev,
312401dea7fSJohan Hovold 				struct device_attribute *attr, char *buf)
313401dea7fSJohan Hovold {
314401dea7fSJohan Hovold 	struct led_classdev *led_cdev = dev_get_drvdata(dev);
315401dea7fSJohan Hovold 	struct lm3533_led *led = to_lm3533_led(led_cdev);
316401dea7fSJohan Hovold 
317*3f6fb1cfSye xingchen 	return sysfs_emit(buf, "%d\n", led->id);
318401dea7fSJohan Hovold }
319401dea7fSJohan Hovold 
320401dea7fSJohan Hovold /*
321401dea7fSJohan Hovold  * Pattern generator rise/fall times:
322401dea7fSJohan Hovold  *
323401dea7fSJohan Hovold  *   0 - 2048 us (default)
324401dea7fSJohan Hovold  *   1 - 262 ms
325401dea7fSJohan Hovold  *   2 - 524 ms
326401dea7fSJohan Hovold  *   3 - 1.049 s
327401dea7fSJohan Hovold  *   4 - 2.097 s
328401dea7fSJohan Hovold  *   5 - 4.194 s
329401dea7fSJohan Hovold  *   6 - 8.389 s
330401dea7fSJohan Hovold  *   7 - 16.78 s
331401dea7fSJohan Hovold  */
show_risefalltime(struct device * dev,struct device_attribute * attr,char * buf,u8 base)332401dea7fSJohan Hovold static ssize_t show_risefalltime(struct device *dev,
333401dea7fSJohan Hovold 					struct device_attribute *attr,
334401dea7fSJohan Hovold 					char *buf, u8 base)
335401dea7fSJohan Hovold {
336401dea7fSJohan Hovold 	struct led_classdev *led_cdev = dev_get_drvdata(dev);
337401dea7fSJohan Hovold 	struct lm3533_led *led = to_lm3533_led(led_cdev);
338401dea7fSJohan Hovold 	ssize_t ret;
339401dea7fSJohan Hovold 	u8 reg;
340401dea7fSJohan Hovold 	u8 val;
341401dea7fSJohan Hovold 
342401dea7fSJohan Hovold 	reg = lm3533_led_get_pattern_reg(led, base);
343401dea7fSJohan Hovold 	ret = lm3533_read(led->lm3533, reg, &val);
344401dea7fSJohan Hovold 	if (ret)
345401dea7fSJohan Hovold 		return ret;
346401dea7fSJohan Hovold 
347*3f6fb1cfSye xingchen 	return sysfs_emit(buf, "%x\n", val);
348401dea7fSJohan Hovold }
349401dea7fSJohan Hovold 
show_risetime(struct device * dev,struct device_attribute * attr,char * buf)350401dea7fSJohan Hovold static ssize_t show_risetime(struct device *dev,
351401dea7fSJohan Hovold 				struct device_attribute *attr, char *buf)
352401dea7fSJohan Hovold {
353401dea7fSJohan Hovold 	return show_risefalltime(dev, attr, buf,
354401dea7fSJohan Hovold 					LM3533_REG_PATTERN_RISETIME_BASE);
355401dea7fSJohan Hovold }
356401dea7fSJohan Hovold 
show_falltime(struct device * dev,struct device_attribute * attr,char * buf)357401dea7fSJohan Hovold static ssize_t show_falltime(struct device *dev,
358401dea7fSJohan Hovold 				struct device_attribute *attr, char *buf)
359401dea7fSJohan Hovold {
360401dea7fSJohan Hovold 	return show_risefalltime(dev, attr, buf,
361401dea7fSJohan Hovold 					LM3533_REG_PATTERN_FALLTIME_BASE);
362401dea7fSJohan Hovold }
363401dea7fSJohan Hovold 
store_risefalltime(struct device * dev,struct device_attribute * attr,const char * buf,size_t len,u8 base)364401dea7fSJohan Hovold static ssize_t store_risefalltime(struct device *dev,
365401dea7fSJohan Hovold 					struct device_attribute *attr,
366401dea7fSJohan Hovold 					const char *buf, size_t len, u8 base)
367401dea7fSJohan Hovold {
368401dea7fSJohan Hovold 	struct led_classdev *led_cdev = dev_get_drvdata(dev);
369401dea7fSJohan Hovold 	struct lm3533_led *led = to_lm3533_led(led_cdev);
370401dea7fSJohan Hovold 	u8 val;
371401dea7fSJohan Hovold 	u8 reg;
372401dea7fSJohan Hovold 	int ret;
373401dea7fSJohan Hovold 
374401dea7fSJohan Hovold 	if (kstrtou8(buf, 0, &val) || val > LM3533_RISEFALLTIME_MAX)
375401dea7fSJohan Hovold 		return -EINVAL;
376401dea7fSJohan Hovold 
377401dea7fSJohan Hovold 	reg = lm3533_led_get_pattern_reg(led, base);
378401dea7fSJohan Hovold 	ret = lm3533_write(led->lm3533, reg, val);
379401dea7fSJohan Hovold 	if (ret)
380401dea7fSJohan Hovold 		return ret;
381401dea7fSJohan Hovold 
382401dea7fSJohan Hovold 	return len;
383401dea7fSJohan Hovold }
384401dea7fSJohan Hovold 
store_risetime(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)385401dea7fSJohan Hovold static ssize_t store_risetime(struct device *dev,
386401dea7fSJohan Hovold 					struct device_attribute *attr,
387401dea7fSJohan Hovold 					const char *buf, size_t len)
388401dea7fSJohan Hovold {
389401dea7fSJohan Hovold 	return store_risefalltime(dev, attr, buf, len,
390401dea7fSJohan Hovold 					LM3533_REG_PATTERN_RISETIME_BASE);
391401dea7fSJohan Hovold }
392401dea7fSJohan Hovold 
store_falltime(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)393401dea7fSJohan Hovold static ssize_t store_falltime(struct device *dev,
394401dea7fSJohan Hovold 					struct device_attribute *attr,
395401dea7fSJohan Hovold 					const char *buf, size_t len)
396401dea7fSJohan Hovold {
397401dea7fSJohan Hovold 	return store_risefalltime(dev, attr, buf, len,
398401dea7fSJohan Hovold 					LM3533_REG_PATTERN_FALLTIME_BASE);
399401dea7fSJohan Hovold }
400401dea7fSJohan Hovold 
show_als_channel(struct device * dev,struct device_attribute * attr,char * buf)401401dea7fSJohan Hovold static ssize_t show_als_channel(struct device *dev,
402401dea7fSJohan Hovold 				struct device_attribute *attr, char *buf)
403401dea7fSJohan Hovold {
404401dea7fSJohan Hovold 	struct led_classdev *led_cdev = dev_get_drvdata(dev);
405401dea7fSJohan Hovold 	struct lm3533_led *led = to_lm3533_led(led_cdev);
406401dea7fSJohan Hovold 	unsigned channel;
407401dea7fSJohan Hovold 	u8 reg;
408401dea7fSJohan Hovold 	u8 val;
409401dea7fSJohan Hovold 	int ret;
410401dea7fSJohan Hovold 
411401dea7fSJohan Hovold 	reg = lm3533_led_get_lv_reg(led, LM3533_REG_CTRLBANK_BCONF_BASE);
412401dea7fSJohan Hovold 	ret = lm3533_read(led->lm3533, reg, &val);
413401dea7fSJohan Hovold 	if (ret)
414401dea7fSJohan Hovold 		return ret;
415401dea7fSJohan Hovold 
416401dea7fSJohan Hovold 	channel = (val & LM3533_REG_CTRLBANK_BCONF_ALS_CHANNEL_MASK) + 1;
417401dea7fSJohan Hovold 
418*3f6fb1cfSye xingchen 	return sysfs_emit(buf, "%u\n", channel);
419401dea7fSJohan Hovold }
420401dea7fSJohan Hovold 
store_als_channel(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)421401dea7fSJohan Hovold static ssize_t store_als_channel(struct device *dev,
422401dea7fSJohan Hovold 					struct device_attribute *attr,
423401dea7fSJohan Hovold 					const char *buf, size_t len)
424401dea7fSJohan Hovold {
425401dea7fSJohan Hovold 	struct led_classdev *led_cdev = dev_get_drvdata(dev);
426401dea7fSJohan Hovold 	struct lm3533_led *led = to_lm3533_led(led_cdev);
427401dea7fSJohan Hovold 	unsigned channel;
428401dea7fSJohan Hovold 	u8 reg;
429401dea7fSJohan Hovold 	u8 val;
430401dea7fSJohan Hovold 	u8 mask;
431401dea7fSJohan Hovold 	int ret;
432401dea7fSJohan Hovold 
433401dea7fSJohan Hovold 	if (kstrtouint(buf, 0, &channel))
434401dea7fSJohan Hovold 		return -EINVAL;
435401dea7fSJohan Hovold 
436401dea7fSJohan Hovold 	if (channel < LM3533_ALS_CHANNEL_LV_MIN ||
437401dea7fSJohan Hovold 					channel > LM3533_ALS_CHANNEL_LV_MAX)
438401dea7fSJohan Hovold 		return -EINVAL;
439401dea7fSJohan Hovold 
440401dea7fSJohan Hovold 	reg = lm3533_led_get_lv_reg(led, LM3533_REG_CTRLBANK_BCONF_BASE);
441401dea7fSJohan Hovold 	mask = LM3533_REG_CTRLBANK_BCONF_ALS_CHANNEL_MASK;
442401dea7fSJohan Hovold 	val = channel - 1;
443401dea7fSJohan Hovold 
444401dea7fSJohan Hovold 	ret = lm3533_update(led->lm3533, reg, val, mask);
445401dea7fSJohan Hovold 	if (ret)
446401dea7fSJohan Hovold 		return ret;
447401dea7fSJohan Hovold 
448401dea7fSJohan Hovold 	return len;
449401dea7fSJohan Hovold }
450401dea7fSJohan Hovold 
show_als_en(struct device * dev,struct device_attribute * attr,char * buf)451401dea7fSJohan Hovold static ssize_t show_als_en(struct device *dev,
452401dea7fSJohan Hovold 				struct device_attribute *attr, char *buf)
453401dea7fSJohan Hovold {
454401dea7fSJohan Hovold 	struct led_classdev *led_cdev = dev_get_drvdata(dev);
455401dea7fSJohan Hovold 	struct lm3533_led *led = to_lm3533_led(led_cdev);
456401dea7fSJohan Hovold 	bool enable;
457401dea7fSJohan Hovold 	u8 reg;
458401dea7fSJohan Hovold 	u8 val;
459401dea7fSJohan Hovold 	int ret;
460401dea7fSJohan Hovold 
461401dea7fSJohan Hovold 	reg = lm3533_led_get_lv_reg(led, LM3533_REG_CTRLBANK_BCONF_BASE);
462401dea7fSJohan Hovold 	ret = lm3533_read(led->lm3533, reg, &val);
463401dea7fSJohan Hovold 	if (ret)
464401dea7fSJohan Hovold 		return ret;
465401dea7fSJohan Hovold 
466401dea7fSJohan Hovold 	enable = val & LM3533_REG_CTRLBANK_BCONF_ALS_EN_MASK;
467401dea7fSJohan Hovold 
468*3f6fb1cfSye xingchen 	return sysfs_emit(buf, "%d\n", enable);
469401dea7fSJohan Hovold }
470401dea7fSJohan Hovold 
store_als_en(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)471401dea7fSJohan Hovold static ssize_t store_als_en(struct device *dev,
472401dea7fSJohan Hovold 					struct device_attribute *attr,
473401dea7fSJohan Hovold 					const char *buf, size_t len)
474401dea7fSJohan Hovold {
475401dea7fSJohan Hovold 	struct led_classdev *led_cdev = dev_get_drvdata(dev);
476401dea7fSJohan Hovold 	struct lm3533_led *led = to_lm3533_led(led_cdev);
477401dea7fSJohan Hovold 	unsigned enable;
478401dea7fSJohan Hovold 	u8 reg;
479401dea7fSJohan Hovold 	u8 mask;
480401dea7fSJohan Hovold 	u8 val;
481401dea7fSJohan Hovold 	int ret;
482401dea7fSJohan Hovold 
483401dea7fSJohan Hovold 	if (kstrtouint(buf, 0, &enable))
484401dea7fSJohan Hovold 		return -EINVAL;
485401dea7fSJohan Hovold 
486401dea7fSJohan Hovold 	reg = lm3533_led_get_lv_reg(led, LM3533_REG_CTRLBANK_BCONF_BASE);
487401dea7fSJohan Hovold 	mask = LM3533_REG_CTRLBANK_BCONF_ALS_EN_MASK;
488401dea7fSJohan Hovold 
489401dea7fSJohan Hovold 	if (enable)
490401dea7fSJohan Hovold 		val = mask;
491401dea7fSJohan Hovold 	else
492401dea7fSJohan Hovold 		val = 0;
493401dea7fSJohan Hovold 
494401dea7fSJohan Hovold 	ret = lm3533_update(led->lm3533, reg, val, mask);
495401dea7fSJohan Hovold 	if (ret)
496401dea7fSJohan Hovold 		return ret;
497401dea7fSJohan Hovold 
498401dea7fSJohan Hovold 	return len;
499401dea7fSJohan Hovold }
500401dea7fSJohan Hovold 
show_linear(struct device * dev,struct device_attribute * attr,char * buf)501401dea7fSJohan Hovold static ssize_t show_linear(struct device *dev,
502401dea7fSJohan Hovold 				struct device_attribute *attr, char *buf)
503401dea7fSJohan Hovold {
504401dea7fSJohan Hovold 	struct led_classdev *led_cdev = dev_get_drvdata(dev);
505401dea7fSJohan Hovold 	struct lm3533_led *led = to_lm3533_led(led_cdev);
506401dea7fSJohan Hovold 	u8 reg;
507401dea7fSJohan Hovold 	u8 val;
508401dea7fSJohan Hovold 	int linear;
509401dea7fSJohan Hovold 	int ret;
510401dea7fSJohan Hovold 
511401dea7fSJohan Hovold 	reg = lm3533_led_get_lv_reg(led, LM3533_REG_CTRLBANK_BCONF_BASE);
512401dea7fSJohan Hovold 	ret = lm3533_read(led->lm3533, reg, &val);
513401dea7fSJohan Hovold 	if (ret)
514401dea7fSJohan Hovold 		return ret;
515401dea7fSJohan Hovold 
516401dea7fSJohan Hovold 	if (val & LM3533_REG_CTRLBANK_BCONF_MAPPING_MASK)
517401dea7fSJohan Hovold 		linear = 1;
518401dea7fSJohan Hovold 	else
519401dea7fSJohan Hovold 		linear = 0;
520401dea7fSJohan Hovold 
521*3f6fb1cfSye xingchen 	return sysfs_emit(buf, "%x\n", linear);
522401dea7fSJohan Hovold }
523401dea7fSJohan Hovold 
store_linear(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)524401dea7fSJohan Hovold static ssize_t store_linear(struct device *dev,
525401dea7fSJohan Hovold 					struct device_attribute *attr,
526401dea7fSJohan Hovold 					const char *buf, size_t len)
527401dea7fSJohan Hovold {
528401dea7fSJohan Hovold 	struct led_classdev *led_cdev = dev_get_drvdata(dev);
529401dea7fSJohan Hovold 	struct lm3533_led *led = to_lm3533_led(led_cdev);
530401dea7fSJohan Hovold 	unsigned long linear;
531401dea7fSJohan Hovold 	u8 reg;
532401dea7fSJohan Hovold 	u8 mask;
533401dea7fSJohan Hovold 	u8 val;
534401dea7fSJohan Hovold 	int ret;
535401dea7fSJohan Hovold 
536401dea7fSJohan Hovold 	if (kstrtoul(buf, 0, &linear))
537401dea7fSJohan Hovold 		return -EINVAL;
538401dea7fSJohan Hovold 
539401dea7fSJohan Hovold 	reg = lm3533_led_get_lv_reg(led, LM3533_REG_CTRLBANK_BCONF_BASE);
540401dea7fSJohan Hovold 	mask = LM3533_REG_CTRLBANK_BCONF_MAPPING_MASK;
541401dea7fSJohan Hovold 
542401dea7fSJohan Hovold 	if (linear)
543401dea7fSJohan Hovold 		val = mask;
544401dea7fSJohan Hovold 	else
545401dea7fSJohan Hovold 		val = 0;
546401dea7fSJohan Hovold 
547401dea7fSJohan Hovold 	ret = lm3533_update(led->lm3533, reg, val, mask);
548401dea7fSJohan Hovold 	if (ret)
549401dea7fSJohan Hovold 		return ret;
550401dea7fSJohan Hovold 
551401dea7fSJohan Hovold 	return len;
552401dea7fSJohan Hovold }
553401dea7fSJohan Hovold 
show_pwm(struct device * dev,struct device_attribute * attr,char * buf)554401dea7fSJohan Hovold static ssize_t show_pwm(struct device *dev,
555401dea7fSJohan Hovold 					struct device_attribute *attr,
556401dea7fSJohan Hovold 					char *buf)
557401dea7fSJohan Hovold {
558401dea7fSJohan Hovold 	struct led_classdev *led_cdev = dev_get_drvdata(dev);
559401dea7fSJohan Hovold 	struct lm3533_led *led = to_lm3533_led(led_cdev);
560401dea7fSJohan Hovold 	u8 val;
561401dea7fSJohan Hovold 	int ret;
562401dea7fSJohan Hovold 
563401dea7fSJohan Hovold 	ret = lm3533_ctrlbank_get_pwm(&led->cb, &val);
564401dea7fSJohan Hovold 	if (ret)
565401dea7fSJohan Hovold 		return ret;
566401dea7fSJohan Hovold 
567*3f6fb1cfSye xingchen 	return sysfs_emit(buf, "%u\n", val);
568401dea7fSJohan Hovold }
569401dea7fSJohan Hovold 
store_pwm(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)570401dea7fSJohan Hovold static ssize_t store_pwm(struct device *dev,
571401dea7fSJohan Hovold 					struct device_attribute *attr,
572401dea7fSJohan Hovold 					const char *buf, size_t len)
573401dea7fSJohan Hovold {
574401dea7fSJohan Hovold 	struct led_classdev *led_cdev = dev_get_drvdata(dev);
575401dea7fSJohan Hovold 	struct lm3533_led *led = to_lm3533_led(led_cdev);
576401dea7fSJohan Hovold 	u8 val;
577401dea7fSJohan Hovold 	int ret;
578401dea7fSJohan Hovold 
579401dea7fSJohan Hovold 	if (kstrtou8(buf, 0, &val))
580401dea7fSJohan Hovold 		return -EINVAL;
581401dea7fSJohan Hovold 
582401dea7fSJohan Hovold 	ret = lm3533_ctrlbank_set_pwm(&led->cb, val);
583401dea7fSJohan Hovold 	if (ret)
584401dea7fSJohan Hovold 		return ret;
585401dea7fSJohan Hovold 
586401dea7fSJohan Hovold 	return len;
587401dea7fSJohan Hovold }
588401dea7fSJohan Hovold 
589401dea7fSJohan Hovold static LM3533_ATTR_RW(als_channel);
590401dea7fSJohan Hovold static LM3533_ATTR_RW(als_en);
591401dea7fSJohan Hovold static LM3533_ATTR_RW(falltime);
592401dea7fSJohan Hovold static LM3533_ATTR_RO(id);
593401dea7fSJohan Hovold static LM3533_ATTR_RW(linear);
594401dea7fSJohan Hovold static LM3533_ATTR_RW(pwm);
595401dea7fSJohan Hovold static LM3533_ATTR_RW(risetime);
596401dea7fSJohan Hovold 
597401dea7fSJohan Hovold static struct attribute *lm3533_led_attributes[] = {
598401dea7fSJohan Hovold 	&dev_attr_als_channel.attr,
599401dea7fSJohan Hovold 	&dev_attr_als_en.attr,
600401dea7fSJohan Hovold 	&dev_attr_falltime.attr,
601401dea7fSJohan Hovold 	&dev_attr_id.attr,
602401dea7fSJohan Hovold 	&dev_attr_linear.attr,
603401dea7fSJohan Hovold 	&dev_attr_pwm.attr,
604401dea7fSJohan Hovold 	&dev_attr_risetime.attr,
605401dea7fSJohan Hovold 	NULL,
606401dea7fSJohan Hovold };
607401dea7fSJohan Hovold 
lm3533_led_attr_is_visible(struct kobject * kobj,struct attribute * attr,int n)608401dea7fSJohan Hovold static umode_t lm3533_led_attr_is_visible(struct kobject *kobj,
609401dea7fSJohan Hovold 					     struct attribute *attr, int n)
610401dea7fSJohan Hovold {
6116c3384d8STian Tao 	struct device *dev = kobj_to_dev(kobj);
612401dea7fSJohan Hovold 	struct led_classdev *led_cdev = dev_get_drvdata(dev);
613401dea7fSJohan Hovold 	struct lm3533_led *led = to_lm3533_led(led_cdev);
614401dea7fSJohan Hovold 	umode_t mode = attr->mode;
615401dea7fSJohan Hovold 
616401dea7fSJohan Hovold 	if (attr == &dev_attr_als_channel.attr ||
617401dea7fSJohan Hovold 					attr == &dev_attr_als_en.attr) {
618401dea7fSJohan Hovold 		if (!led->lm3533->have_als)
619401dea7fSJohan Hovold 			mode = 0;
620401dea7fSJohan Hovold 	}
621401dea7fSJohan Hovold 
622401dea7fSJohan Hovold 	return mode;
623401dea7fSJohan Hovold };
624401dea7fSJohan Hovold 
625430e48ecSAmitoj Kaur Chawla static const struct attribute_group lm3533_led_attribute_group = {
626401dea7fSJohan Hovold 	.is_visible	= lm3533_led_attr_is_visible,
627401dea7fSJohan Hovold 	.attrs		= lm3533_led_attributes
628401dea7fSJohan Hovold };
629401dea7fSJohan Hovold 
6309db93860SJohan Hovold static const struct attribute_group *lm3533_led_attribute_groups[] = {
6319db93860SJohan Hovold 	&lm3533_led_attribute_group,
6329db93860SJohan Hovold 	NULL
6339db93860SJohan Hovold };
6349db93860SJohan Hovold 
lm3533_led_setup(struct lm3533_led * led,struct lm3533_led_platform_data * pdata)63598ea1ea2SBill Pemberton static int lm3533_led_setup(struct lm3533_led *led,
636401dea7fSJohan Hovold 					struct lm3533_led_platform_data *pdata)
637401dea7fSJohan Hovold {
638401dea7fSJohan Hovold 	int ret;
639401dea7fSJohan Hovold 
640401dea7fSJohan Hovold 	ret = lm3533_ctrlbank_set_max_current(&led->cb, pdata->max_current);
641401dea7fSJohan Hovold 	if (ret)
642401dea7fSJohan Hovold 		return ret;
643401dea7fSJohan Hovold 
644401dea7fSJohan Hovold 	return lm3533_ctrlbank_set_pwm(&led->cb, pdata->pwm);
645401dea7fSJohan Hovold }
646401dea7fSJohan Hovold 
lm3533_led_probe(struct platform_device * pdev)64798ea1ea2SBill Pemberton static int lm3533_led_probe(struct platform_device *pdev)
648401dea7fSJohan Hovold {
649401dea7fSJohan Hovold 	struct lm3533 *lm3533;
650401dea7fSJohan Hovold 	struct lm3533_led_platform_data *pdata;
651401dea7fSJohan Hovold 	struct lm3533_led *led;
652401dea7fSJohan Hovold 	int ret;
653401dea7fSJohan Hovold 
654401dea7fSJohan Hovold 	dev_dbg(&pdev->dev, "%s\n", __func__);
655401dea7fSJohan Hovold 
656401dea7fSJohan Hovold 	lm3533 = dev_get_drvdata(pdev->dev.parent);
657401dea7fSJohan Hovold 	if (!lm3533)
658401dea7fSJohan Hovold 		return -EINVAL;
659401dea7fSJohan Hovold 
66087aae1eaSJingoo Han 	pdata = dev_get_platdata(&pdev->dev);
661401dea7fSJohan Hovold 	if (!pdata) {
662401dea7fSJohan Hovold 		dev_err(&pdev->dev, "no platform data\n");
663401dea7fSJohan Hovold 		return -EINVAL;
664401dea7fSJohan Hovold 	}
665401dea7fSJohan Hovold 
666401dea7fSJohan Hovold 	if (pdev->id < 0 || pdev->id >= LM3533_LVCTRLBANK_COUNT) {
667401dea7fSJohan Hovold 		dev_err(&pdev->dev, "illegal LED id %d\n", pdev->id);
668401dea7fSJohan Hovold 		return -EINVAL;
669401dea7fSJohan Hovold 	}
670401dea7fSJohan Hovold 
671401dea7fSJohan Hovold 	led = devm_kzalloc(&pdev->dev, sizeof(*led), GFP_KERNEL);
672401dea7fSJohan Hovold 	if (!led)
673401dea7fSJohan Hovold 		return -ENOMEM;
674401dea7fSJohan Hovold 
675401dea7fSJohan Hovold 	led->lm3533 = lm3533;
676401dea7fSJohan Hovold 	led->cdev.name = pdata->name;
677401dea7fSJohan Hovold 	led->cdev.default_trigger = pdata->default_trigger;
678a478851cSAndrew Lunn 	led->cdev.brightness_set_blocking = lm3533_led_set;
679401dea7fSJohan Hovold 	led->cdev.brightness_get = lm3533_led_get;
680401dea7fSJohan Hovold 	led->cdev.blink_set = lm3533_led_blink_set;
681401dea7fSJohan Hovold 	led->cdev.brightness = LED_OFF;
6824e04b118SZheng Yongjun 	led->cdev.groups = lm3533_led_attribute_groups;
683401dea7fSJohan Hovold 	led->id = pdev->id;
684401dea7fSJohan Hovold 
685401dea7fSJohan Hovold 	mutex_init(&led->mutex);
686401dea7fSJohan Hovold 
687401dea7fSJohan Hovold 	/* The class framework makes a callback to get brightness during
688401dea7fSJohan Hovold 	 * registration so use parent device (for error reporting) until
689401dea7fSJohan Hovold 	 * registered.
690401dea7fSJohan Hovold 	 */
691401dea7fSJohan Hovold 	led->cb.lm3533 = lm3533;
692401dea7fSJohan Hovold 	led->cb.id = lm3533_led_get_ctrlbank_id(led);
693401dea7fSJohan Hovold 	led->cb.dev = lm3533->dev;
694401dea7fSJohan Hovold 
695401dea7fSJohan Hovold 	platform_set_drvdata(pdev, led);
696401dea7fSJohan Hovold 
697d584221eSJohan Hovold 	ret = led_classdev_register(pdev->dev.parent, &led->cdev);
698401dea7fSJohan Hovold 	if (ret) {
699401dea7fSJohan Hovold 		dev_err(&pdev->dev, "failed to register LED %d\n", pdev->id);
700401dea7fSJohan Hovold 		return ret;
701401dea7fSJohan Hovold 	}
702401dea7fSJohan Hovold 
703401dea7fSJohan Hovold 	led->cb.dev = led->cdev.dev;
704401dea7fSJohan Hovold 
705401dea7fSJohan Hovold 	ret = lm3533_led_setup(led, pdata);
706401dea7fSJohan Hovold 	if (ret)
707d584221eSJohan Hovold 		goto err_deregister;
708401dea7fSJohan Hovold 
709401dea7fSJohan Hovold 	ret = lm3533_ctrlbank_enable(&led->cb);
710401dea7fSJohan Hovold 	if (ret)
711d584221eSJohan Hovold 		goto err_deregister;
712401dea7fSJohan Hovold 
713401dea7fSJohan Hovold 	return 0;
714d584221eSJohan Hovold 
715d584221eSJohan Hovold err_deregister:
716d584221eSJohan Hovold 	led_classdev_unregister(&led->cdev);
717d584221eSJohan Hovold 
718d584221eSJohan Hovold 	return ret;
719401dea7fSJohan Hovold }
720401dea7fSJohan Hovold 
lm3533_led_remove(struct platform_device * pdev)721678e8a6bSBill Pemberton static int lm3533_led_remove(struct platform_device *pdev)
722401dea7fSJohan Hovold {
723401dea7fSJohan Hovold 	struct lm3533_led *led = platform_get_drvdata(pdev);
724401dea7fSJohan Hovold 
725401dea7fSJohan Hovold 	dev_dbg(&pdev->dev, "%s\n", __func__);
726401dea7fSJohan Hovold 
727401dea7fSJohan Hovold 	lm3533_ctrlbank_disable(&led->cb);
728d584221eSJohan Hovold 	led_classdev_unregister(&led->cdev);
729401dea7fSJohan Hovold 
730401dea7fSJohan Hovold 	return 0;
731401dea7fSJohan Hovold }
732401dea7fSJohan Hovold 
lm3533_led_shutdown(struct platform_device * pdev)733401dea7fSJohan Hovold static void lm3533_led_shutdown(struct platform_device *pdev)
734401dea7fSJohan Hovold {
735401dea7fSJohan Hovold 
736401dea7fSJohan Hovold 	struct lm3533_led *led = platform_get_drvdata(pdev);
737401dea7fSJohan Hovold 
738401dea7fSJohan Hovold 	dev_dbg(&pdev->dev, "%s\n", __func__);
739401dea7fSJohan Hovold 
740401dea7fSJohan Hovold 	lm3533_ctrlbank_disable(&led->cb);
741401dea7fSJohan Hovold 	lm3533_led_set(&led->cdev, LED_OFF);		/* disable blink */
742401dea7fSJohan Hovold }
743401dea7fSJohan Hovold 
744401dea7fSJohan Hovold static struct platform_driver lm3533_led_driver = {
745401dea7fSJohan Hovold 	.driver = {
746401dea7fSJohan Hovold 		.name = "lm3533-leds",
747401dea7fSJohan Hovold 	},
748401dea7fSJohan Hovold 	.probe		= lm3533_led_probe,
749df07cf81SBill Pemberton 	.remove		= lm3533_led_remove,
750401dea7fSJohan Hovold 	.shutdown	= lm3533_led_shutdown,
751401dea7fSJohan Hovold };
752401dea7fSJohan Hovold module_platform_driver(lm3533_led_driver);
753401dea7fSJohan Hovold 
754401dea7fSJohan Hovold MODULE_AUTHOR("Johan Hovold <jhovold@gmail.com>");
755401dea7fSJohan Hovold MODULE_DESCRIPTION("LM3533 LED driver");
756401dea7fSJohan Hovold MODULE_LICENSE("GPL");
757401dea7fSJohan Hovold MODULE_ALIAS("platform:lm3533-leds");
758