xref: /OK3568_Linux_fs/kernel/drivers/leds/leds-lp8860.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * TI LP8860 4-Channel LED Driver
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2014 Texas Instruments
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Author: Dan Murphy <dmurphy@ti.com>
8*4882a593Smuzhiyun  */
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include <linux/i2c.h>
11*4882a593Smuzhiyun #include <linux/init.h>
12*4882a593Smuzhiyun #include <linux/leds.h>
13*4882a593Smuzhiyun #include <linux/regmap.h>
14*4882a593Smuzhiyun #include <linux/regulator/consumer.h>
15*4882a593Smuzhiyun #include <linux/module.h>
16*4882a593Smuzhiyun #include <linux/mutex.h>
17*4882a593Smuzhiyun #include <linux/of.h>
18*4882a593Smuzhiyun #include <linux/of_gpio.h>
19*4882a593Smuzhiyun #include <linux/gpio/consumer.h>
20*4882a593Smuzhiyun #include <linux/slab.h>
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #define LP8860_DISP_CL1_BRT_MSB		0x00
23*4882a593Smuzhiyun #define LP8860_DISP_CL1_BRT_LSB		0x01
24*4882a593Smuzhiyun #define LP8860_DISP_CL1_CURR_MSB	0x02
25*4882a593Smuzhiyun #define LP8860_DISP_CL1_CURR_LSB	0x03
26*4882a593Smuzhiyun #define LP8860_CL2_BRT_MSB		0x04
27*4882a593Smuzhiyun #define LP8860_CL2_BRT_LSB		0x05
28*4882a593Smuzhiyun #define LP8860_CL2_CURRENT		0x06
29*4882a593Smuzhiyun #define LP8860_CL3_BRT_MSB		0x07
30*4882a593Smuzhiyun #define LP8860_CL3_BRT_LSB		0x08
31*4882a593Smuzhiyun #define LP8860_CL3_CURRENT		0x09
32*4882a593Smuzhiyun #define LP8860_CL4_BRT_MSB		0x0a
33*4882a593Smuzhiyun #define LP8860_CL4_BRT_LSB		0x0b
34*4882a593Smuzhiyun #define LP8860_CL4_CURRENT		0x0c
35*4882a593Smuzhiyun #define LP8860_CONFIG			0x0d
36*4882a593Smuzhiyun #define LP8860_STATUS			0x0e
37*4882a593Smuzhiyun #define LP8860_FAULT			0x0f
38*4882a593Smuzhiyun #define LP8860_LED_FAULT		0x10
39*4882a593Smuzhiyun #define LP8860_FAULT_CLEAR		0x11
40*4882a593Smuzhiyun #define LP8860_ID			0x12
41*4882a593Smuzhiyun #define LP8860_TEMP_MSB			0x13
42*4882a593Smuzhiyun #define LP8860_TEMP_LSB			0x14
43*4882a593Smuzhiyun #define LP8860_DISP_LED_CURR_MSB	0x15
44*4882a593Smuzhiyun #define LP8860_DISP_LED_CURR_LSB	0x16
45*4882a593Smuzhiyun #define LP8860_DISP_LED_PWM_MSB		0x17
46*4882a593Smuzhiyun #define LP8860_DISP_LED_PWM_LSB		0x18
47*4882a593Smuzhiyun #define LP8860_EEPROM_CNTRL		0x19
48*4882a593Smuzhiyun #define LP8860_EEPROM_UNLOCK		0x1a
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun #define LP8860_EEPROM_REG_0		0x60
51*4882a593Smuzhiyun #define LP8860_EEPROM_REG_1		0x61
52*4882a593Smuzhiyun #define LP8860_EEPROM_REG_2		0x62
53*4882a593Smuzhiyun #define LP8860_EEPROM_REG_3		0x63
54*4882a593Smuzhiyun #define LP8860_EEPROM_REG_4		0x64
55*4882a593Smuzhiyun #define LP8860_EEPROM_REG_5		0x65
56*4882a593Smuzhiyun #define LP8860_EEPROM_REG_6		0x66
57*4882a593Smuzhiyun #define LP8860_EEPROM_REG_7		0x67
58*4882a593Smuzhiyun #define LP8860_EEPROM_REG_8		0x68
59*4882a593Smuzhiyun #define LP8860_EEPROM_REG_9		0x69
60*4882a593Smuzhiyun #define LP8860_EEPROM_REG_10		0x6a
61*4882a593Smuzhiyun #define LP8860_EEPROM_REG_11		0x6b
62*4882a593Smuzhiyun #define LP8860_EEPROM_REG_12		0x6c
63*4882a593Smuzhiyun #define LP8860_EEPROM_REG_13		0x6d
64*4882a593Smuzhiyun #define LP8860_EEPROM_REG_14		0x6e
65*4882a593Smuzhiyun #define LP8860_EEPROM_REG_15		0x6f
66*4882a593Smuzhiyun #define LP8860_EEPROM_REG_16		0x70
67*4882a593Smuzhiyun #define LP8860_EEPROM_REG_17		0x71
68*4882a593Smuzhiyun #define LP8860_EEPROM_REG_18		0x72
69*4882a593Smuzhiyun #define LP8860_EEPROM_REG_19		0x73
70*4882a593Smuzhiyun #define LP8860_EEPROM_REG_20		0x74
71*4882a593Smuzhiyun #define LP8860_EEPROM_REG_21		0x75
72*4882a593Smuzhiyun #define LP8860_EEPROM_REG_22		0x76
73*4882a593Smuzhiyun #define LP8860_EEPROM_REG_23		0x77
74*4882a593Smuzhiyun #define LP8860_EEPROM_REG_24		0x78
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun #define LP8860_LOCK_EEPROM		0x00
77*4882a593Smuzhiyun #define LP8860_UNLOCK_EEPROM		0x01
78*4882a593Smuzhiyun #define LP8860_PROGRAM_EEPROM		0x02
79*4882a593Smuzhiyun #define LP8860_EEPROM_CODE_1		0x08
80*4882a593Smuzhiyun #define LP8860_EEPROM_CODE_2		0xba
81*4882a593Smuzhiyun #define LP8860_EEPROM_CODE_3		0xef
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun #define LP8860_CLEAR_FAULTS		0x01
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun #define LP8860_NAME			"lp8860"
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun /**
88*4882a593Smuzhiyun  * struct lp8860_led -
89*4882a593Smuzhiyun  * @lock - Lock for reading/writing the device
90*4882a593Smuzhiyun  * @client - Pointer to the I2C client
91*4882a593Smuzhiyun  * @led_dev - led class device pointer
92*4882a593Smuzhiyun  * @regmap - Devices register map
93*4882a593Smuzhiyun  * @eeprom_regmap - EEPROM register map
94*4882a593Smuzhiyun  * @enable_gpio - VDDIO/EN gpio to enable communication interface
95*4882a593Smuzhiyun  * @regulator - LED supply regulator pointer
96*4882a593Smuzhiyun  */
97*4882a593Smuzhiyun struct lp8860_led {
98*4882a593Smuzhiyun 	struct mutex lock;
99*4882a593Smuzhiyun 	struct i2c_client *client;
100*4882a593Smuzhiyun 	struct led_classdev led_dev;
101*4882a593Smuzhiyun 	struct regmap *regmap;
102*4882a593Smuzhiyun 	struct regmap *eeprom_regmap;
103*4882a593Smuzhiyun 	struct gpio_desc *enable_gpio;
104*4882a593Smuzhiyun 	struct regulator *regulator;
105*4882a593Smuzhiyun };
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun struct lp8860_eeprom_reg {
108*4882a593Smuzhiyun 	uint8_t reg;
109*4882a593Smuzhiyun 	uint8_t value;
110*4882a593Smuzhiyun };
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun static struct lp8860_eeprom_reg lp8860_eeprom_disp_regs[] = {
113*4882a593Smuzhiyun 	{ LP8860_EEPROM_REG_0, 0xed },
114*4882a593Smuzhiyun 	{ LP8860_EEPROM_REG_1, 0xdf },
115*4882a593Smuzhiyun 	{ LP8860_EEPROM_REG_2, 0xdc },
116*4882a593Smuzhiyun 	{ LP8860_EEPROM_REG_3, 0xf0 },
117*4882a593Smuzhiyun 	{ LP8860_EEPROM_REG_4, 0xdf },
118*4882a593Smuzhiyun 	{ LP8860_EEPROM_REG_5, 0xe5 },
119*4882a593Smuzhiyun 	{ LP8860_EEPROM_REG_6, 0xf2 },
120*4882a593Smuzhiyun 	{ LP8860_EEPROM_REG_7, 0x77 },
121*4882a593Smuzhiyun 	{ LP8860_EEPROM_REG_8, 0x77 },
122*4882a593Smuzhiyun 	{ LP8860_EEPROM_REG_9, 0x71 },
123*4882a593Smuzhiyun 	{ LP8860_EEPROM_REG_10, 0x3f },
124*4882a593Smuzhiyun 	{ LP8860_EEPROM_REG_11, 0xb7 },
125*4882a593Smuzhiyun 	{ LP8860_EEPROM_REG_12, 0x17 },
126*4882a593Smuzhiyun 	{ LP8860_EEPROM_REG_13, 0xef },
127*4882a593Smuzhiyun 	{ LP8860_EEPROM_REG_14, 0xb0 },
128*4882a593Smuzhiyun 	{ LP8860_EEPROM_REG_15, 0x87 },
129*4882a593Smuzhiyun 	{ LP8860_EEPROM_REG_16, 0xce },
130*4882a593Smuzhiyun 	{ LP8860_EEPROM_REG_17, 0x72 },
131*4882a593Smuzhiyun 	{ LP8860_EEPROM_REG_18, 0xe5 },
132*4882a593Smuzhiyun 	{ LP8860_EEPROM_REG_19, 0xdf },
133*4882a593Smuzhiyun 	{ LP8860_EEPROM_REG_20, 0x35 },
134*4882a593Smuzhiyun 	{ LP8860_EEPROM_REG_21, 0x06 },
135*4882a593Smuzhiyun 	{ LP8860_EEPROM_REG_22, 0xdc },
136*4882a593Smuzhiyun 	{ LP8860_EEPROM_REG_23, 0x88 },
137*4882a593Smuzhiyun 	{ LP8860_EEPROM_REG_24, 0x3E },
138*4882a593Smuzhiyun };
139*4882a593Smuzhiyun 
lp8860_unlock_eeprom(struct lp8860_led * led,int lock)140*4882a593Smuzhiyun static int lp8860_unlock_eeprom(struct lp8860_led *led, int lock)
141*4882a593Smuzhiyun {
142*4882a593Smuzhiyun 	int ret;
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 	mutex_lock(&led->lock);
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun 	if (lock == LP8860_UNLOCK_EEPROM) {
147*4882a593Smuzhiyun 		ret = regmap_write(led->regmap,
148*4882a593Smuzhiyun 			LP8860_EEPROM_UNLOCK,
149*4882a593Smuzhiyun 			LP8860_EEPROM_CODE_1);
150*4882a593Smuzhiyun 		if (ret) {
151*4882a593Smuzhiyun 			dev_err(&led->client->dev, "EEPROM Unlock failed\n");
152*4882a593Smuzhiyun 			goto out;
153*4882a593Smuzhiyun 		}
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 		ret = regmap_write(led->regmap,
156*4882a593Smuzhiyun 			LP8860_EEPROM_UNLOCK,
157*4882a593Smuzhiyun 			LP8860_EEPROM_CODE_2);
158*4882a593Smuzhiyun 		if (ret) {
159*4882a593Smuzhiyun 			dev_err(&led->client->dev, "EEPROM Unlock failed\n");
160*4882a593Smuzhiyun 			goto out;
161*4882a593Smuzhiyun 		}
162*4882a593Smuzhiyun 		ret = regmap_write(led->regmap,
163*4882a593Smuzhiyun 			LP8860_EEPROM_UNLOCK,
164*4882a593Smuzhiyun 			LP8860_EEPROM_CODE_3);
165*4882a593Smuzhiyun 		if (ret) {
166*4882a593Smuzhiyun 			dev_err(&led->client->dev, "EEPROM Unlock failed\n");
167*4882a593Smuzhiyun 			goto out;
168*4882a593Smuzhiyun 		}
169*4882a593Smuzhiyun 	} else {
170*4882a593Smuzhiyun 		ret = regmap_write(led->regmap,
171*4882a593Smuzhiyun 			LP8860_EEPROM_UNLOCK,
172*4882a593Smuzhiyun 			LP8860_LOCK_EEPROM);
173*4882a593Smuzhiyun 	}
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun out:
176*4882a593Smuzhiyun 	mutex_unlock(&led->lock);
177*4882a593Smuzhiyun 	return ret;
178*4882a593Smuzhiyun }
179*4882a593Smuzhiyun 
lp8860_fault_check(struct lp8860_led * led)180*4882a593Smuzhiyun static int lp8860_fault_check(struct lp8860_led *led)
181*4882a593Smuzhiyun {
182*4882a593Smuzhiyun 	int ret, fault;
183*4882a593Smuzhiyun 	unsigned int read_buf;
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 	ret = regmap_read(led->regmap, LP8860_LED_FAULT, &read_buf);
186*4882a593Smuzhiyun 	if (ret)
187*4882a593Smuzhiyun 		goto out;
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun 	fault = read_buf;
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 	ret = regmap_read(led->regmap, LP8860_FAULT, &read_buf);
192*4882a593Smuzhiyun 	if (ret)
193*4882a593Smuzhiyun 		goto out;
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun 	fault |= read_buf;
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun 	/* Attempt to clear any faults */
198*4882a593Smuzhiyun 	if (fault)
199*4882a593Smuzhiyun 		ret = regmap_write(led->regmap, LP8860_FAULT_CLEAR,
200*4882a593Smuzhiyun 			LP8860_CLEAR_FAULTS);
201*4882a593Smuzhiyun out:
202*4882a593Smuzhiyun 	return ret;
203*4882a593Smuzhiyun }
204*4882a593Smuzhiyun 
lp8860_brightness_set(struct led_classdev * led_cdev,enum led_brightness brt_val)205*4882a593Smuzhiyun static int lp8860_brightness_set(struct led_classdev *led_cdev,
206*4882a593Smuzhiyun 				enum led_brightness brt_val)
207*4882a593Smuzhiyun {
208*4882a593Smuzhiyun 	struct lp8860_led *led =
209*4882a593Smuzhiyun 			container_of(led_cdev, struct lp8860_led, led_dev);
210*4882a593Smuzhiyun 	int disp_brightness = brt_val * 255;
211*4882a593Smuzhiyun 	int ret;
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 	mutex_lock(&led->lock);
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 	ret = lp8860_fault_check(led);
216*4882a593Smuzhiyun 	if (ret) {
217*4882a593Smuzhiyun 		dev_err(&led->client->dev, "Cannot read/clear faults\n");
218*4882a593Smuzhiyun 		goto out;
219*4882a593Smuzhiyun 	}
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun 	ret = regmap_write(led->regmap, LP8860_DISP_CL1_BRT_MSB,
222*4882a593Smuzhiyun 			(disp_brightness & 0xff00) >> 8);
223*4882a593Smuzhiyun 	if (ret) {
224*4882a593Smuzhiyun 		dev_err(&led->client->dev, "Cannot write CL1 MSB\n");
225*4882a593Smuzhiyun 		goto out;
226*4882a593Smuzhiyun 	}
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun 	ret = regmap_write(led->regmap, LP8860_DISP_CL1_BRT_LSB,
229*4882a593Smuzhiyun 			disp_brightness & 0xff);
230*4882a593Smuzhiyun 	if (ret) {
231*4882a593Smuzhiyun 		dev_err(&led->client->dev, "Cannot write CL1 LSB\n");
232*4882a593Smuzhiyun 		goto out;
233*4882a593Smuzhiyun 	}
234*4882a593Smuzhiyun out:
235*4882a593Smuzhiyun 	mutex_unlock(&led->lock);
236*4882a593Smuzhiyun 	return ret;
237*4882a593Smuzhiyun }
238*4882a593Smuzhiyun 
lp8860_init(struct lp8860_led * led)239*4882a593Smuzhiyun static int lp8860_init(struct lp8860_led *led)
240*4882a593Smuzhiyun {
241*4882a593Smuzhiyun 	unsigned int read_buf;
242*4882a593Smuzhiyun 	int ret, i, reg_count;
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun 	if (led->regulator) {
245*4882a593Smuzhiyun 		ret = regulator_enable(led->regulator);
246*4882a593Smuzhiyun 		if (ret) {
247*4882a593Smuzhiyun 			dev_err(&led->client->dev,
248*4882a593Smuzhiyun 				"Failed to enable regulator\n");
249*4882a593Smuzhiyun 			return ret;
250*4882a593Smuzhiyun 		}
251*4882a593Smuzhiyun 	}
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 	if (led->enable_gpio)
254*4882a593Smuzhiyun 		gpiod_direction_output(led->enable_gpio, 1);
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun 	ret = lp8860_fault_check(led);
257*4882a593Smuzhiyun 	if (ret)
258*4882a593Smuzhiyun 		goto out;
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun 	ret = regmap_read(led->regmap, LP8860_STATUS, &read_buf);
261*4882a593Smuzhiyun 	if (ret)
262*4882a593Smuzhiyun 		goto out;
263*4882a593Smuzhiyun 
264*4882a593Smuzhiyun 	ret = lp8860_unlock_eeprom(led, LP8860_UNLOCK_EEPROM);
265*4882a593Smuzhiyun 	if (ret) {
266*4882a593Smuzhiyun 		dev_err(&led->client->dev, "Failed unlocking EEPROM\n");
267*4882a593Smuzhiyun 		goto out;
268*4882a593Smuzhiyun 	}
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun 	reg_count = ARRAY_SIZE(lp8860_eeprom_disp_regs) / sizeof(lp8860_eeprom_disp_regs[0]);
271*4882a593Smuzhiyun 	for (i = 0; i < reg_count; i++) {
272*4882a593Smuzhiyun 		ret = regmap_write(led->eeprom_regmap,
273*4882a593Smuzhiyun 				lp8860_eeprom_disp_regs[i].reg,
274*4882a593Smuzhiyun 				lp8860_eeprom_disp_regs[i].value);
275*4882a593Smuzhiyun 		if (ret) {
276*4882a593Smuzhiyun 			dev_err(&led->client->dev, "Failed writing EEPROM\n");
277*4882a593Smuzhiyun 			goto out;
278*4882a593Smuzhiyun 		}
279*4882a593Smuzhiyun 	}
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun 	ret = lp8860_unlock_eeprom(led, LP8860_LOCK_EEPROM);
282*4882a593Smuzhiyun 	if (ret)
283*4882a593Smuzhiyun 		goto out;
284*4882a593Smuzhiyun 
285*4882a593Smuzhiyun 	ret = regmap_write(led->regmap,
286*4882a593Smuzhiyun 			LP8860_EEPROM_CNTRL,
287*4882a593Smuzhiyun 			LP8860_PROGRAM_EEPROM);
288*4882a593Smuzhiyun 	if (ret) {
289*4882a593Smuzhiyun 		dev_err(&led->client->dev, "Failed programming EEPROM\n");
290*4882a593Smuzhiyun 		goto out;
291*4882a593Smuzhiyun 	}
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun 	return ret;
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun out:
296*4882a593Smuzhiyun 	if (ret)
297*4882a593Smuzhiyun 		if (led->enable_gpio)
298*4882a593Smuzhiyun 			gpiod_direction_output(led->enable_gpio, 0);
299*4882a593Smuzhiyun 
300*4882a593Smuzhiyun 	if (led->regulator) {
301*4882a593Smuzhiyun 		ret = regulator_disable(led->regulator);
302*4882a593Smuzhiyun 		if (ret)
303*4882a593Smuzhiyun 			dev_err(&led->client->dev,
304*4882a593Smuzhiyun 				"Failed to disable regulator\n");
305*4882a593Smuzhiyun 	}
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun 	return ret;
308*4882a593Smuzhiyun }
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun static const struct reg_default lp8860_reg_defs[] = {
311*4882a593Smuzhiyun 	{ LP8860_DISP_CL1_BRT_MSB, 0x00},
312*4882a593Smuzhiyun 	{ LP8860_DISP_CL1_BRT_LSB, 0x00},
313*4882a593Smuzhiyun 	{ LP8860_DISP_CL1_CURR_MSB, 0x00},
314*4882a593Smuzhiyun 	{ LP8860_DISP_CL1_CURR_LSB, 0x00},
315*4882a593Smuzhiyun 	{ LP8860_CL2_BRT_MSB, 0x00},
316*4882a593Smuzhiyun 	{ LP8860_CL2_BRT_LSB, 0x00},
317*4882a593Smuzhiyun 	{ LP8860_CL2_CURRENT, 0x00},
318*4882a593Smuzhiyun 	{ LP8860_CL3_BRT_MSB, 0x00},
319*4882a593Smuzhiyun 	{ LP8860_CL3_BRT_LSB, 0x00},
320*4882a593Smuzhiyun 	{ LP8860_CL3_CURRENT, 0x00},
321*4882a593Smuzhiyun 	{ LP8860_CL4_BRT_MSB, 0x00},
322*4882a593Smuzhiyun 	{ LP8860_CL4_BRT_LSB, 0x00},
323*4882a593Smuzhiyun 	{ LP8860_CL4_CURRENT, 0x00},
324*4882a593Smuzhiyun 	{ LP8860_CONFIG, 0x00},
325*4882a593Smuzhiyun 	{ LP8860_FAULT_CLEAR, 0x00},
326*4882a593Smuzhiyun 	{ LP8860_EEPROM_CNTRL, 0x80},
327*4882a593Smuzhiyun 	{ LP8860_EEPROM_UNLOCK, 0x00},
328*4882a593Smuzhiyun };
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun static const struct regmap_config lp8860_regmap_config = {
331*4882a593Smuzhiyun 	.reg_bits = 8,
332*4882a593Smuzhiyun 	.val_bits = 8,
333*4882a593Smuzhiyun 
334*4882a593Smuzhiyun 	.max_register = LP8860_EEPROM_UNLOCK,
335*4882a593Smuzhiyun 	.reg_defaults = lp8860_reg_defs,
336*4882a593Smuzhiyun 	.num_reg_defaults = ARRAY_SIZE(lp8860_reg_defs),
337*4882a593Smuzhiyun 	.cache_type = REGCACHE_NONE,
338*4882a593Smuzhiyun };
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun static const struct reg_default lp8860_eeprom_defs[] = {
341*4882a593Smuzhiyun 	{ LP8860_EEPROM_REG_0, 0x00 },
342*4882a593Smuzhiyun 	{ LP8860_EEPROM_REG_1, 0x00 },
343*4882a593Smuzhiyun 	{ LP8860_EEPROM_REG_2, 0x00 },
344*4882a593Smuzhiyun 	{ LP8860_EEPROM_REG_3, 0x00 },
345*4882a593Smuzhiyun 	{ LP8860_EEPROM_REG_4, 0x00 },
346*4882a593Smuzhiyun 	{ LP8860_EEPROM_REG_5, 0x00 },
347*4882a593Smuzhiyun 	{ LP8860_EEPROM_REG_6, 0x00 },
348*4882a593Smuzhiyun 	{ LP8860_EEPROM_REG_7, 0x00 },
349*4882a593Smuzhiyun 	{ LP8860_EEPROM_REG_8, 0x00 },
350*4882a593Smuzhiyun 	{ LP8860_EEPROM_REG_9, 0x00 },
351*4882a593Smuzhiyun 	{ LP8860_EEPROM_REG_10, 0x00 },
352*4882a593Smuzhiyun 	{ LP8860_EEPROM_REG_11, 0x00 },
353*4882a593Smuzhiyun 	{ LP8860_EEPROM_REG_12, 0x00 },
354*4882a593Smuzhiyun 	{ LP8860_EEPROM_REG_13, 0x00 },
355*4882a593Smuzhiyun 	{ LP8860_EEPROM_REG_14, 0x00 },
356*4882a593Smuzhiyun 	{ LP8860_EEPROM_REG_15, 0x00 },
357*4882a593Smuzhiyun 	{ LP8860_EEPROM_REG_16, 0x00 },
358*4882a593Smuzhiyun 	{ LP8860_EEPROM_REG_17, 0x00 },
359*4882a593Smuzhiyun 	{ LP8860_EEPROM_REG_18, 0x00 },
360*4882a593Smuzhiyun 	{ LP8860_EEPROM_REG_19, 0x00 },
361*4882a593Smuzhiyun 	{ LP8860_EEPROM_REG_20, 0x00 },
362*4882a593Smuzhiyun 	{ LP8860_EEPROM_REG_21, 0x00 },
363*4882a593Smuzhiyun 	{ LP8860_EEPROM_REG_22, 0x00 },
364*4882a593Smuzhiyun 	{ LP8860_EEPROM_REG_23, 0x00 },
365*4882a593Smuzhiyun 	{ LP8860_EEPROM_REG_24, 0x00 },
366*4882a593Smuzhiyun };
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun static const struct regmap_config lp8860_eeprom_regmap_config = {
369*4882a593Smuzhiyun 	.reg_bits = 8,
370*4882a593Smuzhiyun 	.val_bits = 8,
371*4882a593Smuzhiyun 
372*4882a593Smuzhiyun 	.max_register = LP8860_EEPROM_REG_24,
373*4882a593Smuzhiyun 	.reg_defaults = lp8860_eeprom_defs,
374*4882a593Smuzhiyun 	.num_reg_defaults = ARRAY_SIZE(lp8860_eeprom_defs),
375*4882a593Smuzhiyun 	.cache_type = REGCACHE_NONE,
376*4882a593Smuzhiyun };
377*4882a593Smuzhiyun 
lp8860_probe(struct i2c_client * client,const struct i2c_device_id * id)378*4882a593Smuzhiyun static int lp8860_probe(struct i2c_client *client,
379*4882a593Smuzhiyun 			const struct i2c_device_id *id)
380*4882a593Smuzhiyun {
381*4882a593Smuzhiyun 	int ret;
382*4882a593Smuzhiyun 	struct lp8860_led *led;
383*4882a593Smuzhiyun 	struct device_node *np = dev_of_node(&client->dev);
384*4882a593Smuzhiyun 	struct device_node *child_node;
385*4882a593Smuzhiyun 	struct led_init_data init_data = {};
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun 	led = devm_kzalloc(&client->dev, sizeof(*led), GFP_KERNEL);
388*4882a593Smuzhiyun 	if (!led)
389*4882a593Smuzhiyun 		return -ENOMEM;
390*4882a593Smuzhiyun 
391*4882a593Smuzhiyun 	child_node = of_get_next_available_child(np, NULL);
392*4882a593Smuzhiyun 	if (!child_node)
393*4882a593Smuzhiyun 		return -EINVAL;
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun 	led->enable_gpio = devm_gpiod_get_optional(&client->dev,
396*4882a593Smuzhiyun 						   "enable", GPIOD_OUT_LOW);
397*4882a593Smuzhiyun 	if (IS_ERR(led->enable_gpio)) {
398*4882a593Smuzhiyun 		ret = PTR_ERR(led->enable_gpio);
399*4882a593Smuzhiyun 		dev_err(&client->dev, "Failed to get enable gpio: %d\n", ret);
400*4882a593Smuzhiyun 		return ret;
401*4882a593Smuzhiyun 	}
402*4882a593Smuzhiyun 
403*4882a593Smuzhiyun 	led->regulator = devm_regulator_get(&client->dev, "vled");
404*4882a593Smuzhiyun 	if (IS_ERR(led->regulator))
405*4882a593Smuzhiyun 		led->regulator = NULL;
406*4882a593Smuzhiyun 
407*4882a593Smuzhiyun 	led->client = client;
408*4882a593Smuzhiyun 	led->led_dev.brightness_set_blocking = lp8860_brightness_set;
409*4882a593Smuzhiyun 
410*4882a593Smuzhiyun 	mutex_init(&led->lock);
411*4882a593Smuzhiyun 
412*4882a593Smuzhiyun 	i2c_set_clientdata(client, led);
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun 	led->regmap = devm_regmap_init_i2c(client, &lp8860_regmap_config);
415*4882a593Smuzhiyun 	if (IS_ERR(led->regmap)) {
416*4882a593Smuzhiyun 		ret = PTR_ERR(led->regmap);
417*4882a593Smuzhiyun 		dev_err(&client->dev, "Failed to allocate register map: %d\n",
418*4882a593Smuzhiyun 			ret);
419*4882a593Smuzhiyun 		return ret;
420*4882a593Smuzhiyun 	}
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun 	led->eeprom_regmap = devm_regmap_init_i2c(client, &lp8860_eeprom_regmap_config);
423*4882a593Smuzhiyun 	if (IS_ERR(led->eeprom_regmap)) {
424*4882a593Smuzhiyun 		ret = PTR_ERR(led->eeprom_regmap);
425*4882a593Smuzhiyun 		dev_err(&client->dev, "Failed to allocate register map: %d\n",
426*4882a593Smuzhiyun 			ret);
427*4882a593Smuzhiyun 		return ret;
428*4882a593Smuzhiyun 	}
429*4882a593Smuzhiyun 
430*4882a593Smuzhiyun 	ret = lp8860_init(led);
431*4882a593Smuzhiyun 	if (ret)
432*4882a593Smuzhiyun 		return ret;
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun 	init_data.fwnode = of_fwnode_handle(child_node);
435*4882a593Smuzhiyun 	init_data.devicename = LP8860_NAME;
436*4882a593Smuzhiyun 	init_data.default_label = ":display_cluster";
437*4882a593Smuzhiyun 
438*4882a593Smuzhiyun 	ret = devm_led_classdev_register_ext(&client->dev, &led->led_dev,
439*4882a593Smuzhiyun 					     &init_data);
440*4882a593Smuzhiyun 	if (ret) {
441*4882a593Smuzhiyun 		dev_err(&client->dev, "led register err: %d\n", ret);
442*4882a593Smuzhiyun 		return ret;
443*4882a593Smuzhiyun 	}
444*4882a593Smuzhiyun 
445*4882a593Smuzhiyun 	return 0;
446*4882a593Smuzhiyun }
447*4882a593Smuzhiyun 
lp8860_remove(struct i2c_client * client)448*4882a593Smuzhiyun static int lp8860_remove(struct i2c_client *client)
449*4882a593Smuzhiyun {
450*4882a593Smuzhiyun 	struct lp8860_led *led = i2c_get_clientdata(client);
451*4882a593Smuzhiyun 	int ret;
452*4882a593Smuzhiyun 
453*4882a593Smuzhiyun 	if (led->enable_gpio)
454*4882a593Smuzhiyun 		gpiod_direction_output(led->enable_gpio, 0);
455*4882a593Smuzhiyun 
456*4882a593Smuzhiyun 	if (led->regulator) {
457*4882a593Smuzhiyun 		ret = regulator_disable(led->regulator);
458*4882a593Smuzhiyun 		if (ret)
459*4882a593Smuzhiyun 			dev_err(&led->client->dev,
460*4882a593Smuzhiyun 				"Failed to disable regulator\n");
461*4882a593Smuzhiyun 	}
462*4882a593Smuzhiyun 
463*4882a593Smuzhiyun 	mutex_destroy(&led->lock);
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun 	return 0;
466*4882a593Smuzhiyun }
467*4882a593Smuzhiyun 
468*4882a593Smuzhiyun static const struct i2c_device_id lp8860_id[] = {
469*4882a593Smuzhiyun 	{ "lp8860", 0 },
470*4882a593Smuzhiyun 	{ }
471*4882a593Smuzhiyun };
472*4882a593Smuzhiyun MODULE_DEVICE_TABLE(i2c, lp8860_id);
473*4882a593Smuzhiyun 
474*4882a593Smuzhiyun static const struct of_device_id of_lp8860_leds_match[] = {
475*4882a593Smuzhiyun 	{ .compatible = "ti,lp8860", },
476*4882a593Smuzhiyun 	{},
477*4882a593Smuzhiyun };
478*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, of_lp8860_leds_match);
479*4882a593Smuzhiyun 
480*4882a593Smuzhiyun static struct i2c_driver lp8860_driver = {
481*4882a593Smuzhiyun 	.driver = {
482*4882a593Smuzhiyun 		.name	= "lp8860",
483*4882a593Smuzhiyun 		.of_match_table = of_lp8860_leds_match,
484*4882a593Smuzhiyun 	},
485*4882a593Smuzhiyun 	.probe		= lp8860_probe,
486*4882a593Smuzhiyun 	.remove		= lp8860_remove,
487*4882a593Smuzhiyun 	.id_table	= lp8860_id,
488*4882a593Smuzhiyun };
489*4882a593Smuzhiyun module_i2c_driver(lp8860_driver);
490*4882a593Smuzhiyun 
491*4882a593Smuzhiyun MODULE_DESCRIPTION("Texas Instruments LP8860 LED driver");
492*4882a593Smuzhiyun MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
493*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
494