xref: /OK3568_Linux_fs/kernel/drivers/leds/leds-lp5523.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * lp5523.c - LP5523, LP55231 LED Driver
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2010 Nokia Corporation
6*4882a593Smuzhiyun  * Copyright (C) 2012 Texas Instruments
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * Contact: Samu Onkalo <samu.p.onkalo@nokia.com>
9*4882a593Smuzhiyun  *          Milo(Woogyom) Kim <milo.kim@ti.com>
10*4882a593Smuzhiyun  */
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #include <linux/delay.h>
13*4882a593Smuzhiyun #include <linux/firmware.h>
14*4882a593Smuzhiyun #include <linux/i2c.h>
15*4882a593Smuzhiyun #include <linux/leds.h>
16*4882a593Smuzhiyun #include <linux/module.h>
17*4882a593Smuzhiyun #include <linux/mutex.h>
18*4882a593Smuzhiyun #include <linux/of.h>
19*4882a593Smuzhiyun #include <linux/platform_data/leds-lp55xx.h>
20*4882a593Smuzhiyun #include <linux/slab.h>
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #include "leds-lp55xx-common.h"
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun #define LP5523_PROGRAM_LENGTH		32	/* bytes */
25*4882a593Smuzhiyun /* Memory is used like this:
26*4882a593Smuzhiyun  * 0x00 engine 1 program
27*4882a593Smuzhiyun  * 0x10 engine 2 program
28*4882a593Smuzhiyun  * 0x20 engine 3 program
29*4882a593Smuzhiyun  * 0x30 engine 1 muxing info
30*4882a593Smuzhiyun  * 0x40 engine 2 muxing info
31*4882a593Smuzhiyun  * 0x50 engine 3 muxing info
32*4882a593Smuzhiyun  */
33*4882a593Smuzhiyun #define LP5523_MAX_LEDS			9
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun /* Registers */
36*4882a593Smuzhiyun #define LP5523_REG_ENABLE		0x00
37*4882a593Smuzhiyun #define LP5523_REG_OP_MODE		0x01
38*4882a593Smuzhiyun #define LP5523_REG_ENABLE_LEDS_MSB	0x04
39*4882a593Smuzhiyun #define LP5523_REG_ENABLE_LEDS_LSB	0x05
40*4882a593Smuzhiyun #define LP5523_REG_LED_CTRL_BASE	0x06
41*4882a593Smuzhiyun #define LP5523_REG_LED_PWM_BASE		0x16
42*4882a593Smuzhiyun #define LP5523_REG_LED_CURRENT_BASE	0x26
43*4882a593Smuzhiyun #define LP5523_REG_CONFIG		0x36
44*4882a593Smuzhiyun #define LP5523_REG_STATUS		0x3A
45*4882a593Smuzhiyun #define LP5523_REG_RESET		0x3D
46*4882a593Smuzhiyun #define LP5523_REG_LED_TEST_CTRL	0x41
47*4882a593Smuzhiyun #define LP5523_REG_LED_TEST_ADC		0x42
48*4882a593Smuzhiyun #define LP5523_REG_MASTER_FADER_BASE	0x48
49*4882a593Smuzhiyun #define LP5523_REG_CH1_PROG_START	0x4C
50*4882a593Smuzhiyun #define LP5523_REG_CH2_PROG_START	0x4D
51*4882a593Smuzhiyun #define LP5523_REG_CH3_PROG_START	0x4E
52*4882a593Smuzhiyun #define LP5523_REG_PROG_PAGE_SEL	0x4F
53*4882a593Smuzhiyun #define LP5523_REG_PROG_MEM		0x50
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun /* Bit description in registers */
56*4882a593Smuzhiyun #define LP5523_ENABLE			0x40
57*4882a593Smuzhiyun #define LP5523_AUTO_INC			0x40
58*4882a593Smuzhiyun #define LP5523_PWR_SAVE			0x20
59*4882a593Smuzhiyun #define LP5523_PWM_PWR_SAVE		0x04
60*4882a593Smuzhiyun #define LP5523_CP_AUTO			0x18
61*4882a593Smuzhiyun #define LP5523_AUTO_CLK			0x02
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun #define LP5523_EN_LEDTEST		0x80
64*4882a593Smuzhiyun #define LP5523_LEDTEST_DONE		0x80
65*4882a593Smuzhiyun #define LP5523_RESET			0xFF
66*4882a593Smuzhiyun #define LP5523_ADC_SHORTCIRC_LIM	80
67*4882a593Smuzhiyun #define LP5523_EXT_CLK_USED		0x08
68*4882a593Smuzhiyun #define LP5523_ENG_STATUS_MASK		0x07
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun #define LP5523_FADER_MAPPING_MASK	0xC0
71*4882a593Smuzhiyun #define LP5523_FADER_MAPPING_SHIFT	6
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun /* Memory Page Selection */
74*4882a593Smuzhiyun #define LP5523_PAGE_ENG1		0
75*4882a593Smuzhiyun #define LP5523_PAGE_ENG2		1
76*4882a593Smuzhiyun #define LP5523_PAGE_ENG3		2
77*4882a593Smuzhiyun #define LP5523_PAGE_MUX1		3
78*4882a593Smuzhiyun #define LP5523_PAGE_MUX2		4
79*4882a593Smuzhiyun #define LP5523_PAGE_MUX3		5
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun /* Program Memory Operations */
82*4882a593Smuzhiyun #define LP5523_MODE_ENG1_M		0x30	/* Operation Mode Register */
83*4882a593Smuzhiyun #define LP5523_MODE_ENG2_M		0x0C
84*4882a593Smuzhiyun #define LP5523_MODE_ENG3_M		0x03
85*4882a593Smuzhiyun #define LP5523_LOAD_ENG1		0x10
86*4882a593Smuzhiyun #define LP5523_LOAD_ENG2		0x04
87*4882a593Smuzhiyun #define LP5523_LOAD_ENG3		0x01
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun #define LP5523_ENG1_IS_LOADING(mode)	\
90*4882a593Smuzhiyun 	((mode & LP5523_MODE_ENG1_M) == LP5523_LOAD_ENG1)
91*4882a593Smuzhiyun #define LP5523_ENG2_IS_LOADING(mode)	\
92*4882a593Smuzhiyun 	((mode & LP5523_MODE_ENG2_M) == LP5523_LOAD_ENG2)
93*4882a593Smuzhiyun #define LP5523_ENG3_IS_LOADING(mode)	\
94*4882a593Smuzhiyun 	((mode & LP5523_MODE_ENG3_M) == LP5523_LOAD_ENG3)
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun #define LP5523_EXEC_ENG1_M		0x30	/* Enable Register */
97*4882a593Smuzhiyun #define LP5523_EXEC_ENG2_M		0x0C
98*4882a593Smuzhiyun #define LP5523_EXEC_ENG3_M		0x03
99*4882a593Smuzhiyun #define LP5523_EXEC_M			0x3F
100*4882a593Smuzhiyun #define LP5523_RUN_ENG1			0x20
101*4882a593Smuzhiyun #define LP5523_RUN_ENG2			0x08
102*4882a593Smuzhiyun #define LP5523_RUN_ENG3			0x02
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun #define LED_ACTIVE(mux, led)		(!!(mux & (0x0001 << led)))
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun enum lp5523_chip_id {
107*4882a593Smuzhiyun 	LP5523,
108*4882a593Smuzhiyun 	LP55231,
109*4882a593Smuzhiyun };
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun static int lp5523_init_program_engine(struct lp55xx_chip *chip);
112*4882a593Smuzhiyun 
lp5523_wait_opmode_done(void)113*4882a593Smuzhiyun static inline void lp5523_wait_opmode_done(void)
114*4882a593Smuzhiyun {
115*4882a593Smuzhiyun 	usleep_range(1000, 2000);
116*4882a593Smuzhiyun }
117*4882a593Smuzhiyun 
lp5523_set_led_current(struct lp55xx_led * led,u8 led_current)118*4882a593Smuzhiyun static void lp5523_set_led_current(struct lp55xx_led *led, u8 led_current)
119*4882a593Smuzhiyun {
120*4882a593Smuzhiyun 	led->led_current = led_current;
121*4882a593Smuzhiyun 	lp55xx_write(led->chip, LP5523_REG_LED_CURRENT_BASE + led->chan_nr,
122*4882a593Smuzhiyun 		led_current);
123*4882a593Smuzhiyun }
124*4882a593Smuzhiyun 
lp5523_post_init_device(struct lp55xx_chip * chip)125*4882a593Smuzhiyun static int lp5523_post_init_device(struct lp55xx_chip *chip)
126*4882a593Smuzhiyun {
127*4882a593Smuzhiyun 	int ret;
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun 	ret = lp55xx_write(chip, LP5523_REG_ENABLE, LP5523_ENABLE);
130*4882a593Smuzhiyun 	if (ret)
131*4882a593Smuzhiyun 		return ret;
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun 	/* Chip startup time is 500 us, 1 - 2 ms gives some margin */
134*4882a593Smuzhiyun 	usleep_range(1000, 2000);
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 	ret = lp55xx_write(chip, LP5523_REG_CONFIG,
137*4882a593Smuzhiyun 			    LP5523_AUTO_INC | LP5523_PWR_SAVE |
138*4882a593Smuzhiyun 			    LP5523_CP_AUTO | LP5523_AUTO_CLK |
139*4882a593Smuzhiyun 			    LP5523_PWM_PWR_SAVE);
140*4882a593Smuzhiyun 	if (ret)
141*4882a593Smuzhiyun 		return ret;
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	/* turn on all leds */
144*4882a593Smuzhiyun 	ret = lp55xx_write(chip, LP5523_REG_ENABLE_LEDS_MSB, 0x01);
145*4882a593Smuzhiyun 	if (ret)
146*4882a593Smuzhiyun 		return ret;
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 	ret = lp55xx_write(chip, LP5523_REG_ENABLE_LEDS_LSB, 0xff);
149*4882a593Smuzhiyun 	if (ret)
150*4882a593Smuzhiyun 		return ret;
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 	return lp5523_init_program_engine(chip);
153*4882a593Smuzhiyun }
154*4882a593Smuzhiyun 
lp5523_load_engine(struct lp55xx_chip * chip)155*4882a593Smuzhiyun static void lp5523_load_engine(struct lp55xx_chip *chip)
156*4882a593Smuzhiyun {
157*4882a593Smuzhiyun 	enum lp55xx_engine_index idx = chip->engine_idx;
158*4882a593Smuzhiyun 	static const u8 mask[] = {
159*4882a593Smuzhiyun 		[LP55XX_ENGINE_1] = LP5523_MODE_ENG1_M,
160*4882a593Smuzhiyun 		[LP55XX_ENGINE_2] = LP5523_MODE_ENG2_M,
161*4882a593Smuzhiyun 		[LP55XX_ENGINE_3] = LP5523_MODE_ENG3_M,
162*4882a593Smuzhiyun 	};
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	static const u8 val[] = {
165*4882a593Smuzhiyun 		[LP55XX_ENGINE_1] = LP5523_LOAD_ENG1,
166*4882a593Smuzhiyun 		[LP55XX_ENGINE_2] = LP5523_LOAD_ENG2,
167*4882a593Smuzhiyun 		[LP55XX_ENGINE_3] = LP5523_LOAD_ENG3,
168*4882a593Smuzhiyun 	};
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 	lp55xx_update_bits(chip, LP5523_REG_OP_MODE, mask[idx], val[idx]);
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 	lp5523_wait_opmode_done();
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun 
lp5523_load_engine_and_select_page(struct lp55xx_chip * chip)175*4882a593Smuzhiyun static void lp5523_load_engine_and_select_page(struct lp55xx_chip *chip)
176*4882a593Smuzhiyun {
177*4882a593Smuzhiyun 	enum lp55xx_engine_index idx = chip->engine_idx;
178*4882a593Smuzhiyun 	static const u8 page_sel[] = {
179*4882a593Smuzhiyun 		[LP55XX_ENGINE_1] = LP5523_PAGE_ENG1,
180*4882a593Smuzhiyun 		[LP55XX_ENGINE_2] = LP5523_PAGE_ENG2,
181*4882a593Smuzhiyun 		[LP55XX_ENGINE_3] = LP5523_PAGE_ENG3,
182*4882a593Smuzhiyun 	};
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 	lp5523_load_engine(chip);
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun 	lp55xx_write(chip, LP5523_REG_PROG_PAGE_SEL, page_sel[idx]);
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun 
lp5523_stop_all_engines(struct lp55xx_chip * chip)189*4882a593Smuzhiyun static void lp5523_stop_all_engines(struct lp55xx_chip *chip)
190*4882a593Smuzhiyun {
191*4882a593Smuzhiyun 	lp55xx_write(chip, LP5523_REG_OP_MODE, 0);
192*4882a593Smuzhiyun 	lp5523_wait_opmode_done();
193*4882a593Smuzhiyun }
194*4882a593Smuzhiyun 
lp5523_stop_engine(struct lp55xx_chip * chip)195*4882a593Smuzhiyun static void lp5523_stop_engine(struct lp55xx_chip *chip)
196*4882a593Smuzhiyun {
197*4882a593Smuzhiyun 	enum lp55xx_engine_index idx = chip->engine_idx;
198*4882a593Smuzhiyun 	static const u8 mask[] = {
199*4882a593Smuzhiyun 		[LP55XX_ENGINE_1] = LP5523_MODE_ENG1_M,
200*4882a593Smuzhiyun 		[LP55XX_ENGINE_2] = LP5523_MODE_ENG2_M,
201*4882a593Smuzhiyun 		[LP55XX_ENGINE_3] = LP5523_MODE_ENG3_M,
202*4882a593Smuzhiyun 	};
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun 	lp55xx_update_bits(chip, LP5523_REG_OP_MODE, mask[idx], 0);
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 	lp5523_wait_opmode_done();
207*4882a593Smuzhiyun }
208*4882a593Smuzhiyun 
lp5523_turn_off_channels(struct lp55xx_chip * chip)209*4882a593Smuzhiyun static void lp5523_turn_off_channels(struct lp55xx_chip *chip)
210*4882a593Smuzhiyun {
211*4882a593Smuzhiyun 	int i;
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 	for (i = 0; i < LP5523_MAX_LEDS; i++)
214*4882a593Smuzhiyun 		lp55xx_write(chip, LP5523_REG_LED_PWM_BASE + i, 0);
215*4882a593Smuzhiyun }
216*4882a593Smuzhiyun 
lp5523_run_engine(struct lp55xx_chip * chip,bool start)217*4882a593Smuzhiyun static void lp5523_run_engine(struct lp55xx_chip *chip, bool start)
218*4882a593Smuzhiyun {
219*4882a593Smuzhiyun 	int ret;
220*4882a593Smuzhiyun 	u8 mode;
221*4882a593Smuzhiyun 	u8 exec;
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun 	/* stop engine */
224*4882a593Smuzhiyun 	if (!start) {
225*4882a593Smuzhiyun 		lp5523_stop_engine(chip);
226*4882a593Smuzhiyun 		lp5523_turn_off_channels(chip);
227*4882a593Smuzhiyun 		return;
228*4882a593Smuzhiyun 	}
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 	/*
231*4882a593Smuzhiyun 	 * To run the engine,
232*4882a593Smuzhiyun 	 * operation mode and enable register should updated at the same time
233*4882a593Smuzhiyun 	 */
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun 	ret = lp55xx_read(chip, LP5523_REG_OP_MODE, &mode);
236*4882a593Smuzhiyun 	if (ret)
237*4882a593Smuzhiyun 		return;
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	ret = lp55xx_read(chip, LP5523_REG_ENABLE, &exec);
240*4882a593Smuzhiyun 	if (ret)
241*4882a593Smuzhiyun 		return;
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 	/* change operation mode to RUN only when each engine is loading */
244*4882a593Smuzhiyun 	if (LP5523_ENG1_IS_LOADING(mode)) {
245*4882a593Smuzhiyun 		mode = (mode & ~LP5523_MODE_ENG1_M) | LP5523_RUN_ENG1;
246*4882a593Smuzhiyun 		exec = (exec & ~LP5523_EXEC_ENG1_M) | LP5523_RUN_ENG1;
247*4882a593Smuzhiyun 	}
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun 	if (LP5523_ENG2_IS_LOADING(mode)) {
250*4882a593Smuzhiyun 		mode = (mode & ~LP5523_MODE_ENG2_M) | LP5523_RUN_ENG2;
251*4882a593Smuzhiyun 		exec = (exec & ~LP5523_EXEC_ENG2_M) | LP5523_RUN_ENG2;
252*4882a593Smuzhiyun 	}
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun 	if (LP5523_ENG3_IS_LOADING(mode)) {
255*4882a593Smuzhiyun 		mode = (mode & ~LP5523_MODE_ENG3_M) | LP5523_RUN_ENG3;
256*4882a593Smuzhiyun 		exec = (exec & ~LP5523_EXEC_ENG3_M) | LP5523_RUN_ENG3;
257*4882a593Smuzhiyun 	}
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 	lp55xx_write(chip, LP5523_REG_OP_MODE, mode);
260*4882a593Smuzhiyun 	lp5523_wait_opmode_done();
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun 	lp55xx_update_bits(chip, LP5523_REG_ENABLE, LP5523_EXEC_M, exec);
263*4882a593Smuzhiyun }
264*4882a593Smuzhiyun 
lp5523_init_program_engine(struct lp55xx_chip * chip)265*4882a593Smuzhiyun static int lp5523_init_program_engine(struct lp55xx_chip *chip)
266*4882a593Smuzhiyun {
267*4882a593Smuzhiyun 	int i;
268*4882a593Smuzhiyun 	int j;
269*4882a593Smuzhiyun 	int ret;
270*4882a593Smuzhiyun 	u8 status;
271*4882a593Smuzhiyun 	/* one pattern per engine setting LED MUX start and stop addresses */
272*4882a593Smuzhiyun 	static const u8 pattern[][LP5523_PROGRAM_LENGTH] =  {
273*4882a593Smuzhiyun 		{ 0x9c, 0x30, 0x9c, 0xb0, 0x9d, 0x80, 0xd8, 0x00, 0},
274*4882a593Smuzhiyun 		{ 0x9c, 0x40, 0x9c, 0xc0, 0x9d, 0x80, 0xd8, 0x00, 0},
275*4882a593Smuzhiyun 		{ 0x9c, 0x50, 0x9c, 0xd0, 0x9d, 0x80, 0xd8, 0x00, 0},
276*4882a593Smuzhiyun 	};
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun 	/* hardcode 32 bytes of memory for each engine from program memory */
279*4882a593Smuzhiyun 	ret = lp55xx_write(chip, LP5523_REG_CH1_PROG_START, 0x00);
280*4882a593Smuzhiyun 	if (ret)
281*4882a593Smuzhiyun 		return ret;
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 	ret = lp55xx_write(chip, LP5523_REG_CH2_PROG_START, 0x10);
284*4882a593Smuzhiyun 	if (ret)
285*4882a593Smuzhiyun 		return ret;
286*4882a593Smuzhiyun 
287*4882a593Smuzhiyun 	ret = lp55xx_write(chip, LP5523_REG_CH3_PROG_START, 0x20);
288*4882a593Smuzhiyun 	if (ret)
289*4882a593Smuzhiyun 		return ret;
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun 	/* write LED MUX address space for each engine */
292*4882a593Smuzhiyun 	for (i = LP55XX_ENGINE_1; i <= LP55XX_ENGINE_3; i++) {
293*4882a593Smuzhiyun 		chip->engine_idx = i;
294*4882a593Smuzhiyun 		lp5523_load_engine_and_select_page(chip);
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun 		for (j = 0; j < LP5523_PROGRAM_LENGTH; j++) {
297*4882a593Smuzhiyun 			ret = lp55xx_write(chip, LP5523_REG_PROG_MEM + j,
298*4882a593Smuzhiyun 					pattern[i - 1][j]);
299*4882a593Smuzhiyun 			if (ret)
300*4882a593Smuzhiyun 				goto out;
301*4882a593Smuzhiyun 		}
302*4882a593Smuzhiyun 	}
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 	lp5523_run_engine(chip, true);
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun 	/* Let the programs run for couple of ms and check the engine status */
307*4882a593Smuzhiyun 	usleep_range(3000, 6000);
308*4882a593Smuzhiyun 	ret = lp55xx_read(chip, LP5523_REG_STATUS, &status);
309*4882a593Smuzhiyun 	if (ret)
310*4882a593Smuzhiyun 		goto out;
311*4882a593Smuzhiyun 	status &= LP5523_ENG_STATUS_MASK;
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun 	if (status != LP5523_ENG_STATUS_MASK) {
314*4882a593Smuzhiyun 		dev_err(&chip->cl->dev,
315*4882a593Smuzhiyun 			"could not configure LED engine, status = 0x%.2x\n",
316*4882a593Smuzhiyun 			status);
317*4882a593Smuzhiyun 		ret = -1;
318*4882a593Smuzhiyun 	}
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun out:
321*4882a593Smuzhiyun 	lp5523_stop_all_engines(chip);
322*4882a593Smuzhiyun 	return ret;
323*4882a593Smuzhiyun }
324*4882a593Smuzhiyun 
lp5523_update_program_memory(struct lp55xx_chip * chip,const u8 * data,size_t size)325*4882a593Smuzhiyun static int lp5523_update_program_memory(struct lp55xx_chip *chip,
326*4882a593Smuzhiyun 					const u8 *data, size_t size)
327*4882a593Smuzhiyun {
328*4882a593Smuzhiyun 	u8 pattern[LP5523_PROGRAM_LENGTH] = {0};
329*4882a593Smuzhiyun 	unsigned int cmd;
330*4882a593Smuzhiyun 	char c[3];
331*4882a593Smuzhiyun 	int nrchars;
332*4882a593Smuzhiyun 	int ret;
333*4882a593Smuzhiyun 	int offset = 0;
334*4882a593Smuzhiyun 	int i = 0;
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun 	while ((offset < size - 1) && (i < LP5523_PROGRAM_LENGTH)) {
337*4882a593Smuzhiyun 		/* separate sscanfs because length is working only for %s */
338*4882a593Smuzhiyun 		ret = sscanf(data + offset, "%2s%n ", c, &nrchars);
339*4882a593Smuzhiyun 		if (ret != 1)
340*4882a593Smuzhiyun 			goto err;
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun 		ret = sscanf(c, "%2x", &cmd);
343*4882a593Smuzhiyun 		if (ret != 1)
344*4882a593Smuzhiyun 			goto err;
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun 		pattern[i] = (u8)cmd;
347*4882a593Smuzhiyun 		offset += nrchars;
348*4882a593Smuzhiyun 		i++;
349*4882a593Smuzhiyun 	}
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun 	/* Each instruction is 16bit long. Check that length is even */
352*4882a593Smuzhiyun 	if (i % 2)
353*4882a593Smuzhiyun 		goto err;
354*4882a593Smuzhiyun 
355*4882a593Smuzhiyun 	for (i = 0; i < LP5523_PROGRAM_LENGTH; i++) {
356*4882a593Smuzhiyun 		ret = lp55xx_write(chip, LP5523_REG_PROG_MEM + i, pattern[i]);
357*4882a593Smuzhiyun 		if (ret)
358*4882a593Smuzhiyun 			return -EINVAL;
359*4882a593Smuzhiyun 	}
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun 	return size;
362*4882a593Smuzhiyun 
363*4882a593Smuzhiyun err:
364*4882a593Smuzhiyun 	dev_err(&chip->cl->dev, "wrong pattern format\n");
365*4882a593Smuzhiyun 	return -EINVAL;
366*4882a593Smuzhiyun }
367*4882a593Smuzhiyun 
lp5523_firmware_loaded(struct lp55xx_chip * chip)368*4882a593Smuzhiyun static void lp5523_firmware_loaded(struct lp55xx_chip *chip)
369*4882a593Smuzhiyun {
370*4882a593Smuzhiyun 	const struct firmware *fw = chip->fw;
371*4882a593Smuzhiyun 
372*4882a593Smuzhiyun 	if (fw->size > LP5523_PROGRAM_LENGTH) {
373*4882a593Smuzhiyun 		dev_err(&chip->cl->dev, "firmware data size overflow: %zu\n",
374*4882a593Smuzhiyun 			fw->size);
375*4882a593Smuzhiyun 		return;
376*4882a593Smuzhiyun 	}
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 	/*
379*4882a593Smuzhiyun 	 * Program memory sequence
380*4882a593Smuzhiyun 	 *  1) set engine mode to "LOAD"
381*4882a593Smuzhiyun 	 *  2) write firmware data into program memory
382*4882a593Smuzhiyun 	 */
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun 	lp5523_load_engine_and_select_page(chip);
385*4882a593Smuzhiyun 	lp5523_update_program_memory(chip, fw->data, fw->size);
386*4882a593Smuzhiyun }
387*4882a593Smuzhiyun 
show_engine_mode(struct device * dev,struct device_attribute * attr,char * buf,int nr)388*4882a593Smuzhiyun static ssize_t show_engine_mode(struct device *dev,
389*4882a593Smuzhiyun 				struct device_attribute *attr,
390*4882a593Smuzhiyun 				char *buf, int nr)
391*4882a593Smuzhiyun {
392*4882a593Smuzhiyun 	struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev));
393*4882a593Smuzhiyun 	struct lp55xx_chip *chip = led->chip;
394*4882a593Smuzhiyun 	enum lp55xx_engine_mode mode = chip->engines[nr - 1].mode;
395*4882a593Smuzhiyun 
396*4882a593Smuzhiyun 	switch (mode) {
397*4882a593Smuzhiyun 	case LP55XX_ENGINE_RUN:
398*4882a593Smuzhiyun 		return sprintf(buf, "run\n");
399*4882a593Smuzhiyun 	case LP55XX_ENGINE_LOAD:
400*4882a593Smuzhiyun 		return sprintf(buf, "load\n");
401*4882a593Smuzhiyun 	case LP55XX_ENGINE_DISABLED:
402*4882a593Smuzhiyun 	default:
403*4882a593Smuzhiyun 		return sprintf(buf, "disabled\n");
404*4882a593Smuzhiyun 	}
405*4882a593Smuzhiyun }
406*4882a593Smuzhiyun show_mode(1)
407*4882a593Smuzhiyun show_mode(2)
408*4882a593Smuzhiyun show_mode(3)
409*4882a593Smuzhiyun 
store_engine_mode(struct device * dev,struct device_attribute * attr,const char * buf,size_t len,int nr)410*4882a593Smuzhiyun static ssize_t store_engine_mode(struct device *dev,
411*4882a593Smuzhiyun 				 struct device_attribute *attr,
412*4882a593Smuzhiyun 				 const char *buf, size_t len, int nr)
413*4882a593Smuzhiyun {
414*4882a593Smuzhiyun 	struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev));
415*4882a593Smuzhiyun 	struct lp55xx_chip *chip = led->chip;
416*4882a593Smuzhiyun 	struct lp55xx_engine *engine = &chip->engines[nr - 1];
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun 	mutex_lock(&chip->lock);
419*4882a593Smuzhiyun 
420*4882a593Smuzhiyun 	chip->engine_idx = nr;
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun 	if (!strncmp(buf, "run", 3)) {
423*4882a593Smuzhiyun 		lp5523_run_engine(chip, true);
424*4882a593Smuzhiyun 		engine->mode = LP55XX_ENGINE_RUN;
425*4882a593Smuzhiyun 	} else if (!strncmp(buf, "load", 4)) {
426*4882a593Smuzhiyun 		lp5523_stop_engine(chip);
427*4882a593Smuzhiyun 		lp5523_load_engine(chip);
428*4882a593Smuzhiyun 		engine->mode = LP55XX_ENGINE_LOAD;
429*4882a593Smuzhiyun 	} else if (!strncmp(buf, "disabled", 8)) {
430*4882a593Smuzhiyun 		lp5523_stop_engine(chip);
431*4882a593Smuzhiyun 		engine->mode = LP55XX_ENGINE_DISABLED;
432*4882a593Smuzhiyun 	}
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun 	mutex_unlock(&chip->lock);
435*4882a593Smuzhiyun 
436*4882a593Smuzhiyun 	return len;
437*4882a593Smuzhiyun }
438*4882a593Smuzhiyun store_mode(1)
439*4882a593Smuzhiyun store_mode(2)
440*4882a593Smuzhiyun store_mode(3)
441*4882a593Smuzhiyun 
lp5523_mux_parse(const char * buf,u16 * mux,size_t len)442*4882a593Smuzhiyun static int lp5523_mux_parse(const char *buf, u16 *mux, size_t len)
443*4882a593Smuzhiyun {
444*4882a593Smuzhiyun 	u16 tmp_mux = 0;
445*4882a593Smuzhiyun 	int i;
446*4882a593Smuzhiyun 
447*4882a593Smuzhiyun 	len = min_t(int, len, LP5523_MAX_LEDS);
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun 	for (i = 0; i < len; i++) {
450*4882a593Smuzhiyun 		switch (buf[i]) {
451*4882a593Smuzhiyun 		case '1':
452*4882a593Smuzhiyun 			tmp_mux |= (1 << i);
453*4882a593Smuzhiyun 			break;
454*4882a593Smuzhiyun 		case '0':
455*4882a593Smuzhiyun 			break;
456*4882a593Smuzhiyun 		case '\n':
457*4882a593Smuzhiyun 			i = len;
458*4882a593Smuzhiyun 			break;
459*4882a593Smuzhiyun 		default:
460*4882a593Smuzhiyun 			return -1;
461*4882a593Smuzhiyun 		}
462*4882a593Smuzhiyun 	}
463*4882a593Smuzhiyun 	*mux = tmp_mux;
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun 	return 0;
466*4882a593Smuzhiyun }
467*4882a593Smuzhiyun 
lp5523_mux_to_array(u16 led_mux,char * array)468*4882a593Smuzhiyun static void lp5523_mux_to_array(u16 led_mux, char *array)
469*4882a593Smuzhiyun {
470*4882a593Smuzhiyun 	int i, pos = 0;
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun 	for (i = 0; i < LP5523_MAX_LEDS; i++)
473*4882a593Smuzhiyun 		pos += sprintf(array + pos, "%x", LED_ACTIVE(led_mux, i));
474*4882a593Smuzhiyun 
475*4882a593Smuzhiyun 	array[pos] = '\0';
476*4882a593Smuzhiyun }
477*4882a593Smuzhiyun 
show_engine_leds(struct device * dev,struct device_attribute * attr,char * buf,int nr)478*4882a593Smuzhiyun static ssize_t show_engine_leds(struct device *dev,
479*4882a593Smuzhiyun 			    struct device_attribute *attr,
480*4882a593Smuzhiyun 			    char *buf, int nr)
481*4882a593Smuzhiyun {
482*4882a593Smuzhiyun 	struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev));
483*4882a593Smuzhiyun 	struct lp55xx_chip *chip = led->chip;
484*4882a593Smuzhiyun 	char mux[LP5523_MAX_LEDS + 1];
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun 	lp5523_mux_to_array(chip->engines[nr - 1].led_mux, mux);
487*4882a593Smuzhiyun 
488*4882a593Smuzhiyun 	return sprintf(buf, "%s\n", mux);
489*4882a593Smuzhiyun }
490*4882a593Smuzhiyun show_leds(1)
491*4882a593Smuzhiyun show_leds(2)
492*4882a593Smuzhiyun show_leds(3)
493*4882a593Smuzhiyun 
lp5523_load_mux(struct lp55xx_chip * chip,u16 mux,int nr)494*4882a593Smuzhiyun static int lp5523_load_mux(struct lp55xx_chip *chip, u16 mux, int nr)
495*4882a593Smuzhiyun {
496*4882a593Smuzhiyun 	struct lp55xx_engine *engine = &chip->engines[nr - 1];
497*4882a593Smuzhiyun 	int ret;
498*4882a593Smuzhiyun 	static const u8 mux_page[] = {
499*4882a593Smuzhiyun 		[LP55XX_ENGINE_1] = LP5523_PAGE_MUX1,
500*4882a593Smuzhiyun 		[LP55XX_ENGINE_2] = LP5523_PAGE_MUX2,
501*4882a593Smuzhiyun 		[LP55XX_ENGINE_3] = LP5523_PAGE_MUX3,
502*4882a593Smuzhiyun 	};
503*4882a593Smuzhiyun 
504*4882a593Smuzhiyun 	lp5523_load_engine(chip);
505*4882a593Smuzhiyun 
506*4882a593Smuzhiyun 	ret = lp55xx_write(chip, LP5523_REG_PROG_PAGE_SEL, mux_page[nr]);
507*4882a593Smuzhiyun 	if (ret)
508*4882a593Smuzhiyun 		return ret;
509*4882a593Smuzhiyun 
510*4882a593Smuzhiyun 	ret = lp55xx_write(chip, LP5523_REG_PROG_MEM, (u8)(mux >> 8));
511*4882a593Smuzhiyun 	if (ret)
512*4882a593Smuzhiyun 		return ret;
513*4882a593Smuzhiyun 
514*4882a593Smuzhiyun 	ret = lp55xx_write(chip, LP5523_REG_PROG_MEM + 1, (u8)(mux));
515*4882a593Smuzhiyun 	if (ret)
516*4882a593Smuzhiyun 		return ret;
517*4882a593Smuzhiyun 
518*4882a593Smuzhiyun 	engine->led_mux = mux;
519*4882a593Smuzhiyun 	return 0;
520*4882a593Smuzhiyun }
521*4882a593Smuzhiyun 
store_engine_leds(struct device * dev,struct device_attribute * attr,const char * buf,size_t len,int nr)522*4882a593Smuzhiyun static ssize_t store_engine_leds(struct device *dev,
523*4882a593Smuzhiyun 			     struct device_attribute *attr,
524*4882a593Smuzhiyun 			     const char *buf, size_t len, int nr)
525*4882a593Smuzhiyun {
526*4882a593Smuzhiyun 	struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev));
527*4882a593Smuzhiyun 	struct lp55xx_chip *chip = led->chip;
528*4882a593Smuzhiyun 	struct lp55xx_engine *engine = &chip->engines[nr - 1];
529*4882a593Smuzhiyun 	u16 mux = 0;
530*4882a593Smuzhiyun 	ssize_t ret;
531*4882a593Smuzhiyun 
532*4882a593Smuzhiyun 	if (lp5523_mux_parse(buf, &mux, len))
533*4882a593Smuzhiyun 		return -EINVAL;
534*4882a593Smuzhiyun 
535*4882a593Smuzhiyun 	mutex_lock(&chip->lock);
536*4882a593Smuzhiyun 
537*4882a593Smuzhiyun 	chip->engine_idx = nr;
538*4882a593Smuzhiyun 	ret = -EINVAL;
539*4882a593Smuzhiyun 
540*4882a593Smuzhiyun 	if (engine->mode != LP55XX_ENGINE_LOAD)
541*4882a593Smuzhiyun 		goto leave;
542*4882a593Smuzhiyun 
543*4882a593Smuzhiyun 	if (lp5523_load_mux(chip, mux, nr))
544*4882a593Smuzhiyun 		goto leave;
545*4882a593Smuzhiyun 
546*4882a593Smuzhiyun 	ret = len;
547*4882a593Smuzhiyun leave:
548*4882a593Smuzhiyun 	mutex_unlock(&chip->lock);
549*4882a593Smuzhiyun 	return ret;
550*4882a593Smuzhiyun }
551*4882a593Smuzhiyun store_leds(1)
552*4882a593Smuzhiyun store_leds(2)
553*4882a593Smuzhiyun store_leds(3)
554*4882a593Smuzhiyun 
store_engine_load(struct device * dev,struct device_attribute * attr,const char * buf,size_t len,int nr)555*4882a593Smuzhiyun static ssize_t store_engine_load(struct device *dev,
556*4882a593Smuzhiyun 			     struct device_attribute *attr,
557*4882a593Smuzhiyun 			     const char *buf, size_t len, int nr)
558*4882a593Smuzhiyun {
559*4882a593Smuzhiyun 	struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev));
560*4882a593Smuzhiyun 	struct lp55xx_chip *chip = led->chip;
561*4882a593Smuzhiyun 	int ret;
562*4882a593Smuzhiyun 
563*4882a593Smuzhiyun 	mutex_lock(&chip->lock);
564*4882a593Smuzhiyun 
565*4882a593Smuzhiyun 	chip->engine_idx = nr;
566*4882a593Smuzhiyun 	lp5523_load_engine_and_select_page(chip);
567*4882a593Smuzhiyun 	ret = lp5523_update_program_memory(chip, buf, len);
568*4882a593Smuzhiyun 
569*4882a593Smuzhiyun 	mutex_unlock(&chip->lock);
570*4882a593Smuzhiyun 
571*4882a593Smuzhiyun 	return ret;
572*4882a593Smuzhiyun }
573*4882a593Smuzhiyun store_load(1)
574*4882a593Smuzhiyun store_load(2)
575*4882a593Smuzhiyun store_load(3)
576*4882a593Smuzhiyun 
lp5523_selftest(struct device * dev,struct device_attribute * attr,char * buf)577*4882a593Smuzhiyun static ssize_t lp5523_selftest(struct device *dev,
578*4882a593Smuzhiyun 			       struct device_attribute *attr,
579*4882a593Smuzhiyun 			       char *buf)
580*4882a593Smuzhiyun {
581*4882a593Smuzhiyun 	struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev));
582*4882a593Smuzhiyun 	struct lp55xx_chip *chip = led->chip;
583*4882a593Smuzhiyun 	struct lp55xx_platform_data *pdata = chip->pdata;
584*4882a593Smuzhiyun 	int i, ret, pos = 0;
585*4882a593Smuzhiyun 	u8 status, adc, vdd;
586*4882a593Smuzhiyun 
587*4882a593Smuzhiyun 	mutex_lock(&chip->lock);
588*4882a593Smuzhiyun 
589*4882a593Smuzhiyun 	ret = lp55xx_read(chip, LP5523_REG_STATUS, &status);
590*4882a593Smuzhiyun 	if (ret < 0)
591*4882a593Smuzhiyun 		goto fail;
592*4882a593Smuzhiyun 
593*4882a593Smuzhiyun 	/* Check that ext clock is really in use if requested */
594*4882a593Smuzhiyun 	if (pdata->clock_mode == LP55XX_CLOCK_EXT) {
595*4882a593Smuzhiyun 		if  ((status & LP5523_EXT_CLK_USED) == 0)
596*4882a593Smuzhiyun 			goto fail;
597*4882a593Smuzhiyun 	}
598*4882a593Smuzhiyun 
599*4882a593Smuzhiyun 	/* Measure VDD (i.e. VBAT) first (channel 16 corresponds to VDD) */
600*4882a593Smuzhiyun 	lp55xx_write(chip, LP5523_REG_LED_TEST_CTRL, LP5523_EN_LEDTEST | 16);
601*4882a593Smuzhiyun 	usleep_range(3000, 6000); /* ADC conversion time is typically 2.7 ms */
602*4882a593Smuzhiyun 	ret = lp55xx_read(chip, LP5523_REG_STATUS, &status);
603*4882a593Smuzhiyun 	if (ret < 0)
604*4882a593Smuzhiyun 		goto fail;
605*4882a593Smuzhiyun 
606*4882a593Smuzhiyun 	if (!(status & LP5523_LEDTEST_DONE))
607*4882a593Smuzhiyun 		usleep_range(3000, 6000); /* Was not ready. Wait little bit */
608*4882a593Smuzhiyun 
609*4882a593Smuzhiyun 	ret = lp55xx_read(chip, LP5523_REG_LED_TEST_ADC, &vdd);
610*4882a593Smuzhiyun 	if (ret < 0)
611*4882a593Smuzhiyun 		goto fail;
612*4882a593Smuzhiyun 
613*4882a593Smuzhiyun 	vdd--;	/* There may be some fluctuation in measurement */
614*4882a593Smuzhiyun 
615*4882a593Smuzhiyun 	for (i = 0; i < LP5523_MAX_LEDS; i++) {
616*4882a593Smuzhiyun 		/* Skip non-existing channels */
617*4882a593Smuzhiyun 		if (pdata->led_config[i].led_current == 0)
618*4882a593Smuzhiyun 			continue;
619*4882a593Smuzhiyun 
620*4882a593Smuzhiyun 		/* Set default current */
621*4882a593Smuzhiyun 		lp55xx_write(chip, LP5523_REG_LED_CURRENT_BASE + i,
622*4882a593Smuzhiyun 			pdata->led_config[i].led_current);
623*4882a593Smuzhiyun 
624*4882a593Smuzhiyun 		lp55xx_write(chip, LP5523_REG_LED_PWM_BASE + i, 0xff);
625*4882a593Smuzhiyun 		/* let current stabilize 2 - 4ms before measurements start */
626*4882a593Smuzhiyun 		usleep_range(2000, 4000);
627*4882a593Smuzhiyun 		lp55xx_write(chip, LP5523_REG_LED_TEST_CTRL,
628*4882a593Smuzhiyun 			     LP5523_EN_LEDTEST | i);
629*4882a593Smuzhiyun 		/* ADC conversion time is 2.7 ms typically */
630*4882a593Smuzhiyun 		usleep_range(3000, 6000);
631*4882a593Smuzhiyun 		ret = lp55xx_read(chip, LP5523_REG_STATUS, &status);
632*4882a593Smuzhiyun 		if (ret < 0)
633*4882a593Smuzhiyun 			goto fail;
634*4882a593Smuzhiyun 
635*4882a593Smuzhiyun 		if (!(status & LP5523_LEDTEST_DONE))
636*4882a593Smuzhiyun 			usleep_range(3000, 6000);/* Was not ready. Wait. */
637*4882a593Smuzhiyun 
638*4882a593Smuzhiyun 		ret = lp55xx_read(chip, LP5523_REG_LED_TEST_ADC, &adc);
639*4882a593Smuzhiyun 		if (ret < 0)
640*4882a593Smuzhiyun 			goto fail;
641*4882a593Smuzhiyun 
642*4882a593Smuzhiyun 		if (adc >= vdd || adc < LP5523_ADC_SHORTCIRC_LIM)
643*4882a593Smuzhiyun 			pos += sprintf(buf + pos, "LED %d FAIL\n", i);
644*4882a593Smuzhiyun 
645*4882a593Smuzhiyun 		lp55xx_write(chip, LP5523_REG_LED_PWM_BASE + i, 0x00);
646*4882a593Smuzhiyun 
647*4882a593Smuzhiyun 		/* Restore current */
648*4882a593Smuzhiyun 		lp55xx_write(chip, LP5523_REG_LED_CURRENT_BASE + i,
649*4882a593Smuzhiyun 			led->led_current);
650*4882a593Smuzhiyun 		led++;
651*4882a593Smuzhiyun 	}
652*4882a593Smuzhiyun 	if (pos == 0)
653*4882a593Smuzhiyun 		pos = sprintf(buf, "OK\n");
654*4882a593Smuzhiyun 	goto release_lock;
655*4882a593Smuzhiyun fail:
656*4882a593Smuzhiyun 	pos = sprintf(buf, "FAIL\n");
657*4882a593Smuzhiyun 
658*4882a593Smuzhiyun release_lock:
659*4882a593Smuzhiyun 	mutex_unlock(&chip->lock);
660*4882a593Smuzhiyun 
661*4882a593Smuzhiyun 	return pos;
662*4882a593Smuzhiyun }
663*4882a593Smuzhiyun 
664*4882a593Smuzhiyun #define show_fader(nr)						\
665*4882a593Smuzhiyun static ssize_t show_master_fader##nr(struct device *dev,	\
666*4882a593Smuzhiyun 			    struct device_attribute *attr,	\
667*4882a593Smuzhiyun 			    char *buf)				\
668*4882a593Smuzhiyun {								\
669*4882a593Smuzhiyun 	return show_master_fader(dev, attr, buf, nr);		\
670*4882a593Smuzhiyun }
671*4882a593Smuzhiyun 
672*4882a593Smuzhiyun #define store_fader(nr)						\
673*4882a593Smuzhiyun static ssize_t store_master_fader##nr(struct device *dev,	\
674*4882a593Smuzhiyun 			     struct device_attribute *attr,	\
675*4882a593Smuzhiyun 			     const char *buf, size_t len)	\
676*4882a593Smuzhiyun {								\
677*4882a593Smuzhiyun 	return store_master_fader(dev, attr, buf, len, nr);	\
678*4882a593Smuzhiyun }
679*4882a593Smuzhiyun 
show_master_fader(struct device * dev,struct device_attribute * attr,char * buf,int nr)680*4882a593Smuzhiyun static ssize_t show_master_fader(struct device *dev,
681*4882a593Smuzhiyun 				 struct device_attribute *attr,
682*4882a593Smuzhiyun 				 char *buf, int nr)
683*4882a593Smuzhiyun {
684*4882a593Smuzhiyun 	struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev));
685*4882a593Smuzhiyun 	struct lp55xx_chip *chip = led->chip;
686*4882a593Smuzhiyun 	int ret;
687*4882a593Smuzhiyun 	u8 val;
688*4882a593Smuzhiyun 
689*4882a593Smuzhiyun 	mutex_lock(&chip->lock);
690*4882a593Smuzhiyun 	ret = lp55xx_read(chip, LP5523_REG_MASTER_FADER_BASE + nr - 1, &val);
691*4882a593Smuzhiyun 	mutex_unlock(&chip->lock);
692*4882a593Smuzhiyun 
693*4882a593Smuzhiyun 	if (ret == 0)
694*4882a593Smuzhiyun 		ret = sprintf(buf, "%u\n", val);
695*4882a593Smuzhiyun 
696*4882a593Smuzhiyun 	return ret;
697*4882a593Smuzhiyun }
698*4882a593Smuzhiyun show_fader(1)
699*4882a593Smuzhiyun show_fader(2)
700*4882a593Smuzhiyun show_fader(3)
701*4882a593Smuzhiyun 
store_master_fader(struct device * dev,struct device_attribute * attr,const char * buf,size_t len,int nr)702*4882a593Smuzhiyun static ssize_t store_master_fader(struct device *dev,
703*4882a593Smuzhiyun 				  struct device_attribute *attr,
704*4882a593Smuzhiyun 				  const char *buf, size_t len, int nr)
705*4882a593Smuzhiyun {
706*4882a593Smuzhiyun 	struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev));
707*4882a593Smuzhiyun 	struct lp55xx_chip *chip = led->chip;
708*4882a593Smuzhiyun 	int ret;
709*4882a593Smuzhiyun 	unsigned long val;
710*4882a593Smuzhiyun 
711*4882a593Smuzhiyun 	if (kstrtoul(buf, 0, &val))
712*4882a593Smuzhiyun 		return -EINVAL;
713*4882a593Smuzhiyun 
714*4882a593Smuzhiyun 	if (val > 0xff)
715*4882a593Smuzhiyun 		return -EINVAL;
716*4882a593Smuzhiyun 
717*4882a593Smuzhiyun 	mutex_lock(&chip->lock);
718*4882a593Smuzhiyun 	ret = lp55xx_write(chip, LP5523_REG_MASTER_FADER_BASE + nr - 1,
719*4882a593Smuzhiyun 			   (u8)val);
720*4882a593Smuzhiyun 	mutex_unlock(&chip->lock);
721*4882a593Smuzhiyun 
722*4882a593Smuzhiyun 	if (ret == 0)
723*4882a593Smuzhiyun 		ret = len;
724*4882a593Smuzhiyun 
725*4882a593Smuzhiyun 	return ret;
726*4882a593Smuzhiyun }
727*4882a593Smuzhiyun store_fader(1)
728*4882a593Smuzhiyun store_fader(2)
729*4882a593Smuzhiyun store_fader(3)
730*4882a593Smuzhiyun 
show_master_fader_leds(struct device * dev,struct device_attribute * attr,char * buf)731*4882a593Smuzhiyun static ssize_t show_master_fader_leds(struct device *dev,
732*4882a593Smuzhiyun 				      struct device_attribute *attr,
733*4882a593Smuzhiyun 				      char *buf)
734*4882a593Smuzhiyun {
735*4882a593Smuzhiyun 	struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev));
736*4882a593Smuzhiyun 	struct lp55xx_chip *chip = led->chip;
737*4882a593Smuzhiyun 	int i, ret, pos = 0;
738*4882a593Smuzhiyun 	u8 val;
739*4882a593Smuzhiyun 
740*4882a593Smuzhiyun 	mutex_lock(&chip->lock);
741*4882a593Smuzhiyun 
742*4882a593Smuzhiyun 	for (i = 0; i < LP5523_MAX_LEDS; i++) {
743*4882a593Smuzhiyun 		ret = lp55xx_read(chip, LP5523_REG_LED_CTRL_BASE + i, &val);
744*4882a593Smuzhiyun 		if (ret)
745*4882a593Smuzhiyun 			goto leave;
746*4882a593Smuzhiyun 
747*4882a593Smuzhiyun 		val = (val & LP5523_FADER_MAPPING_MASK)
748*4882a593Smuzhiyun 			>> LP5523_FADER_MAPPING_SHIFT;
749*4882a593Smuzhiyun 		if (val > 3) {
750*4882a593Smuzhiyun 			ret = -EINVAL;
751*4882a593Smuzhiyun 			goto leave;
752*4882a593Smuzhiyun 		}
753*4882a593Smuzhiyun 		buf[pos++] = val + '0';
754*4882a593Smuzhiyun 	}
755*4882a593Smuzhiyun 	buf[pos++] = '\n';
756*4882a593Smuzhiyun 	ret = pos;
757*4882a593Smuzhiyun leave:
758*4882a593Smuzhiyun 	mutex_unlock(&chip->lock);
759*4882a593Smuzhiyun 	return ret;
760*4882a593Smuzhiyun }
761*4882a593Smuzhiyun 
store_master_fader_leds(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)762*4882a593Smuzhiyun static ssize_t store_master_fader_leds(struct device *dev,
763*4882a593Smuzhiyun 				       struct device_attribute *attr,
764*4882a593Smuzhiyun 				       const char *buf, size_t len)
765*4882a593Smuzhiyun {
766*4882a593Smuzhiyun 	struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev));
767*4882a593Smuzhiyun 	struct lp55xx_chip *chip = led->chip;
768*4882a593Smuzhiyun 	int i, n, ret;
769*4882a593Smuzhiyun 	u8 val;
770*4882a593Smuzhiyun 
771*4882a593Smuzhiyun 	n = min_t(int, len, LP5523_MAX_LEDS);
772*4882a593Smuzhiyun 
773*4882a593Smuzhiyun 	mutex_lock(&chip->lock);
774*4882a593Smuzhiyun 
775*4882a593Smuzhiyun 	for (i = 0; i < n; i++) {
776*4882a593Smuzhiyun 		if (buf[i] >= '0' && buf[i] <= '3') {
777*4882a593Smuzhiyun 			val = (buf[i] - '0') << LP5523_FADER_MAPPING_SHIFT;
778*4882a593Smuzhiyun 			ret = lp55xx_update_bits(chip,
779*4882a593Smuzhiyun 						 LP5523_REG_LED_CTRL_BASE + i,
780*4882a593Smuzhiyun 						 LP5523_FADER_MAPPING_MASK,
781*4882a593Smuzhiyun 						 val);
782*4882a593Smuzhiyun 			if (ret)
783*4882a593Smuzhiyun 				goto leave;
784*4882a593Smuzhiyun 		} else {
785*4882a593Smuzhiyun 			ret = -EINVAL;
786*4882a593Smuzhiyun 			goto leave;
787*4882a593Smuzhiyun 		}
788*4882a593Smuzhiyun 	}
789*4882a593Smuzhiyun 	ret = len;
790*4882a593Smuzhiyun leave:
791*4882a593Smuzhiyun 	mutex_unlock(&chip->lock);
792*4882a593Smuzhiyun 	return ret;
793*4882a593Smuzhiyun }
794*4882a593Smuzhiyun 
lp5523_multicolor_brightness(struct lp55xx_led * led)795*4882a593Smuzhiyun static int lp5523_multicolor_brightness(struct lp55xx_led *led)
796*4882a593Smuzhiyun {
797*4882a593Smuzhiyun 	struct lp55xx_chip *chip = led->chip;
798*4882a593Smuzhiyun 	int ret;
799*4882a593Smuzhiyun 	int i;
800*4882a593Smuzhiyun 
801*4882a593Smuzhiyun 	mutex_lock(&chip->lock);
802*4882a593Smuzhiyun 	for (i = 0; i < led->mc_cdev.num_colors; i++) {
803*4882a593Smuzhiyun 		ret = lp55xx_write(chip,
804*4882a593Smuzhiyun 				   LP5523_REG_LED_PWM_BASE +
805*4882a593Smuzhiyun 				   led->mc_cdev.subled_info[i].channel,
806*4882a593Smuzhiyun 				   led->mc_cdev.subled_info[i].brightness);
807*4882a593Smuzhiyun 		if (ret)
808*4882a593Smuzhiyun 			break;
809*4882a593Smuzhiyun 	}
810*4882a593Smuzhiyun 	mutex_unlock(&chip->lock);
811*4882a593Smuzhiyun 	return ret;
812*4882a593Smuzhiyun }
813*4882a593Smuzhiyun 
lp5523_led_brightness(struct lp55xx_led * led)814*4882a593Smuzhiyun static int lp5523_led_brightness(struct lp55xx_led *led)
815*4882a593Smuzhiyun {
816*4882a593Smuzhiyun 	struct lp55xx_chip *chip = led->chip;
817*4882a593Smuzhiyun 	int ret;
818*4882a593Smuzhiyun 
819*4882a593Smuzhiyun 	mutex_lock(&chip->lock);
820*4882a593Smuzhiyun 	ret = lp55xx_write(chip, LP5523_REG_LED_PWM_BASE + led->chan_nr,
821*4882a593Smuzhiyun 		     led->brightness);
822*4882a593Smuzhiyun 	mutex_unlock(&chip->lock);
823*4882a593Smuzhiyun 	return ret;
824*4882a593Smuzhiyun }
825*4882a593Smuzhiyun 
826*4882a593Smuzhiyun static LP55XX_DEV_ATTR_RW(engine1_mode, show_engine1_mode, store_engine1_mode);
827*4882a593Smuzhiyun static LP55XX_DEV_ATTR_RW(engine2_mode, show_engine2_mode, store_engine2_mode);
828*4882a593Smuzhiyun static LP55XX_DEV_ATTR_RW(engine3_mode, show_engine3_mode, store_engine3_mode);
829*4882a593Smuzhiyun static LP55XX_DEV_ATTR_RW(engine1_leds, show_engine1_leds, store_engine1_leds);
830*4882a593Smuzhiyun static LP55XX_DEV_ATTR_RW(engine2_leds, show_engine2_leds, store_engine2_leds);
831*4882a593Smuzhiyun static LP55XX_DEV_ATTR_RW(engine3_leds, show_engine3_leds, store_engine3_leds);
832*4882a593Smuzhiyun static LP55XX_DEV_ATTR_WO(engine1_load, store_engine1_load);
833*4882a593Smuzhiyun static LP55XX_DEV_ATTR_WO(engine2_load, store_engine2_load);
834*4882a593Smuzhiyun static LP55XX_DEV_ATTR_WO(engine3_load, store_engine3_load);
835*4882a593Smuzhiyun static LP55XX_DEV_ATTR_RO(selftest, lp5523_selftest);
836*4882a593Smuzhiyun static LP55XX_DEV_ATTR_RW(master_fader1, show_master_fader1,
837*4882a593Smuzhiyun 			  store_master_fader1);
838*4882a593Smuzhiyun static LP55XX_DEV_ATTR_RW(master_fader2, show_master_fader2,
839*4882a593Smuzhiyun 			  store_master_fader2);
840*4882a593Smuzhiyun static LP55XX_DEV_ATTR_RW(master_fader3, show_master_fader3,
841*4882a593Smuzhiyun 			  store_master_fader3);
842*4882a593Smuzhiyun static LP55XX_DEV_ATTR_RW(master_fader_leds, show_master_fader_leds,
843*4882a593Smuzhiyun 			  store_master_fader_leds);
844*4882a593Smuzhiyun 
845*4882a593Smuzhiyun static struct attribute *lp5523_attributes[] = {
846*4882a593Smuzhiyun 	&dev_attr_engine1_mode.attr,
847*4882a593Smuzhiyun 	&dev_attr_engine2_mode.attr,
848*4882a593Smuzhiyun 	&dev_attr_engine3_mode.attr,
849*4882a593Smuzhiyun 	&dev_attr_engine1_load.attr,
850*4882a593Smuzhiyun 	&dev_attr_engine2_load.attr,
851*4882a593Smuzhiyun 	&dev_attr_engine3_load.attr,
852*4882a593Smuzhiyun 	&dev_attr_engine1_leds.attr,
853*4882a593Smuzhiyun 	&dev_attr_engine2_leds.attr,
854*4882a593Smuzhiyun 	&dev_attr_engine3_leds.attr,
855*4882a593Smuzhiyun 	&dev_attr_selftest.attr,
856*4882a593Smuzhiyun 	&dev_attr_master_fader1.attr,
857*4882a593Smuzhiyun 	&dev_attr_master_fader2.attr,
858*4882a593Smuzhiyun 	&dev_attr_master_fader3.attr,
859*4882a593Smuzhiyun 	&dev_attr_master_fader_leds.attr,
860*4882a593Smuzhiyun 	NULL,
861*4882a593Smuzhiyun };
862*4882a593Smuzhiyun 
863*4882a593Smuzhiyun static const struct attribute_group lp5523_group = {
864*4882a593Smuzhiyun 	.attrs = lp5523_attributes,
865*4882a593Smuzhiyun };
866*4882a593Smuzhiyun 
867*4882a593Smuzhiyun /* Chip specific configurations */
868*4882a593Smuzhiyun static struct lp55xx_device_config lp5523_cfg = {
869*4882a593Smuzhiyun 	.reset = {
870*4882a593Smuzhiyun 		.addr = LP5523_REG_RESET,
871*4882a593Smuzhiyun 		.val  = LP5523_RESET,
872*4882a593Smuzhiyun 	},
873*4882a593Smuzhiyun 	.enable = {
874*4882a593Smuzhiyun 		.addr = LP5523_REG_ENABLE,
875*4882a593Smuzhiyun 		.val  = LP5523_ENABLE,
876*4882a593Smuzhiyun 	},
877*4882a593Smuzhiyun 	.max_channel  = LP5523_MAX_LEDS,
878*4882a593Smuzhiyun 	.post_init_device   = lp5523_post_init_device,
879*4882a593Smuzhiyun 	.brightness_fn      = lp5523_led_brightness,
880*4882a593Smuzhiyun 	.multicolor_brightness_fn = lp5523_multicolor_brightness,
881*4882a593Smuzhiyun 	.set_led_current    = lp5523_set_led_current,
882*4882a593Smuzhiyun 	.firmware_cb        = lp5523_firmware_loaded,
883*4882a593Smuzhiyun 	.run_engine         = lp5523_run_engine,
884*4882a593Smuzhiyun 	.dev_attr_group     = &lp5523_group,
885*4882a593Smuzhiyun };
886*4882a593Smuzhiyun 
lp5523_probe(struct i2c_client * client,const struct i2c_device_id * id)887*4882a593Smuzhiyun static int lp5523_probe(struct i2c_client *client,
888*4882a593Smuzhiyun 			const struct i2c_device_id *id)
889*4882a593Smuzhiyun {
890*4882a593Smuzhiyun 	int ret;
891*4882a593Smuzhiyun 	struct lp55xx_chip *chip;
892*4882a593Smuzhiyun 	struct lp55xx_led *led;
893*4882a593Smuzhiyun 	struct lp55xx_platform_data *pdata = dev_get_platdata(&client->dev);
894*4882a593Smuzhiyun 	struct device_node *np = dev_of_node(&client->dev);
895*4882a593Smuzhiyun 
896*4882a593Smuzhiyun 	chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
897*4882a593Smuzhiyun 	if (!chip)
898*4882a593Smuzhiyun 		return -ENOMEM;
899*4882a593Smuzhiyun 
900*4882a593Smuzhiyun 	chip->cfg = &lp5523_cfg;
901*4882a593Smuzhiyun 
902*4882a593Smuzhiyun 	if (!pdata) {
903*4882a593Smuzhiyun 		if (np) {
904*4882a593Smuzhiyun 			pdata = lp55xx_of_populate_pdata(&client->dev, np,
905*4882a593Smuzhiyun 							 chip);
906*4882a593Smuzhiyun 			if (IS_ERR(pdata))
907*4882a593Smuzhiyun 				return PTR_ERR(pdata);
908*4882a593Smuzhiyun 		} else {
909*4882a593Smuzhiyun 			dev_err(&client->dev, "no platform data\n");
910*4882a593Smuzhiyun 			return -EINVAL;
911*4882a593Smuzhiyun 		}
912*4882a593Smuzhiyun 	}
913*4882a593Smuzhiyun 
914*4882a593Smuzhiyun 	led = devm_kcalloc(&client->dev,
915*4882a593Smuzhiyun 			pdata->num_channels, sizeof(*led), GFP_KERNEL);
916*4882a593Smuzhiyun 	if (!led)
917*4882a593Smuzhiyun 		return -ENOMEM;
918*4882a593Smuzhiyun 
919*4882a593Smuzhiyun 	chip->cl = client;
920*4882a593Smuzhiyun 	chip->pdata = pdata;
921*4882a593Smuzhiyun 
922*4882a593Smuzhiyun 	mutex_init(&chip->lock);
923*4882a593Smuzhiyun 
924*4882a593Smuzhiyun 	i2c_set_clientdata(client, led);
925*4882a593Smuzhiyun 
926*4882a593Smuzhiyun 	ret = lp55xx_init_device(chip);
927*4882a593Smuzhiyun 	if (ret)
928*4882a593Smuzhiyun 		goto err_init;
929*4882a593Smuzhiyun 
930*4882a593Smuzhiyun 	dev_info(&client->dev, "%s Programmable led chip found\n", id->name);
931*4882a593Smuzhiyun 
932*4882a593Smuzhiyun 	ret = lp55xx_register_leds(led, chip);
933*4882a593Smuzhiyun 	if (ret)
934*4882a593Smuzhiyun 		goto err_out;
935*4882a593Smuzhiyun 
936*4882a593Smuzhiyun 	ret = lp55xx_register_sysfs(chip);
937*4882a593Smuzhiyun 	if (ret) {
938*4882a593Smuzhiyun 		dev_err(&client->dev, "registering sysfs failed\n");
939*4882a593Smuzhiyun 		goto err_out;
940*4882a593Smuzhiyun 	}
941*4882a593Smuzhiyun 
942*4882a593Smuzhiyun 	return 0;
943*4882a593Smuzhiyun 
944*4882a593Smuzhiyun err_out:
945*4882a593Smuzhiyun 	lp55xx_deinit_device(chip);
946*4882a593Smuzhiyun err_init:
947*4882a593Smuzhiyun 	return ret;
948*4882a593Smuzhiyun }
949*4882a593Smuzhiyun 
lp5523_remove(struct i2c_client * client)950*4882a593Smuzhiyun static int lp5523_remove(struct i2c_client *client)
951*4882a593Smuzhiyun {
952*4882a593Smuzhiyun 	struct lp55xx_led *led = i2c_get_clientdata(client);
953*4882a593Smuzhiyun 	struct lp55xx_chip *chip = led->chip;
954*4882a593Smuzhiyun 
955*4882a593Smuzhiyun 	lp5523_stop_all_engines(chip);
956*4882a593Smuzhiyun 	lp55xx_unregister_sysfs(chip);
957*4882a593Smuzhiyun 	lp55xx_deinit_device(chip);
958*4882a593Smuzhiyun 
959*4882a593Smuzhiyun 	return 0;
960*4882a593Smuzhiyun }
961*4882a593Smuzhiyun 
962*4882a593Smuzhiyun static const struct i2c_device_id lp5523_id[] = {
963*4882a593Smuzhiyun 	{ "lp5523",  LP5523 },
964*4882a593Smuzhiyun 	{ "lp55231", LP55231 },
965*4882a593Smuzhiyun 	{ }
966*4882a593Smuzhiyun };
967*4882a593Smuzhiyun 
968*4882a593Smuzhiyun MODULE_DEVICE_TABLE(i2c, lp5523_id);
969*4882a593Smuzhiyun 
970*4882a593Smuzhiyun #ifdef CONFIG_OF
971*4882a593Smuzhiyun static const struct of_device_id of_lp5523_leds_match[] = {
972*4882a593Smuzhiyun 	{ .compatible = "national,lp5523", },
973*4882a593Smuzhiyun 	{ .compatible = "ti,lp55231", },
974*4882a593Smuzhiyun 	{},
975*4882a593Smuzhiyun };
976*4882a593Smuzhiyun 
977*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, of_lp5523_leds_match);
978*4882a593Smuzhiyun #endif
979*4882a593Smuzhiyun 
980*4882a593Smuzhiyun static struct i2c_driver lp5523_driver = {
981*4882a593Smuzhiyun 	.driver = {
982*4882a593Smuzhiyun 		.name	= "lp5523x",
983*4882a593Smuzhiyun 		.of_match_table = of_match_ptr(of_lp5523_leds_match),
984*4882a593Smuzhiyun 	},
985*4882a593Smuzhiyun 	.probe		= lp5523_probe,
986*4882a593Smuzhiyun 	.remove		= lp5523_remove,
987*4882a593Smuzhiyun 	.id_table	= lp5523_id,
988*4882a593Smuzhiyun };
989*4882a593Smuzhiyun 
990*4882a593Smuzhiyun module_i2c_driver(lp5523_driver);
991*4882a593Smuzhiyun 
992*4882a593Smuzhiyun MODULE_AUTHOR("Mathias Nyman <mathias.nyman@nokia.com>");
993*4882a593Smuzhiyun MODULE_AUTHOR("Milo Kim <milo.kim@ti.com>");
994*4882a593Smuzhiyun MODULE_DESCRIPTION("LP5523 LED engine");
995*4882a593Smuzhiyun MODULE_LICENSE("GPL");
996