xref: /openbmc/linux/drivers/video/backlight/lm3630a_bl.c (revision 28e64a68a2ef1c48f30e8b6803725199929069fc)
1*28e64a68SDaniel Jeong /*
2*28e64a68SDaniel Jeong * Simple driver for Texas Instruments LM3630A Backlight driver chip
3*28e64a68SDaniel Jeong * Copyright (C) 2012 Texas Instruments
4*28e64a68SDaniel Jeong *
5*28e64a68SDaniel Jeong * This program is free software; you can redistribute it and/or modify
6*28e64a68SDaniel Jeong * it under the terms of the GNU General Public License version 2 as
7*28e64a68SDaniel Jeong * published by the Free Software Foundation.
8*28e64a68SDaniel Jeong *
9*28e64a68SDaniel Jeong */
10*28e64a68SDaniel Jeong #include <linux/module.h>
11*28e64a68SDaniel Jeong #include <linux/slab.h>
12*28e64a68SDaniel Jeong #include <linux/i2c.h>
13*28e64a68SDaniel Jeong #include <linux/backlight.h>
14*28e64a68SDaniel Jeong #include <linux/err.h>
15*28e64a68SDaniel Jeong #include <linux/delay.h>
16*28e64a68SDaniel Jeong #include <linux/uaccess.h>
17*28e64a68SDaniel Jeong #include <linux/interrupt.h>
18*28e64a68SDaniel Jeong #include <linux/regmap.h>
19*28e64a68SDaniel Jeong #include <linux/pwm.h>
20*28e64a68SDaniel Jeong #include <linux/platform_data/lm3630a_bl.h>
21*28e64a68SDaniel Jeong 
22*28e64a68SDaniel Jeong #define REG_CTRL	0x00
23*28e64a68SDaniel Jeong #define REG_BOOST	0x02
24*28e64a68SDaniel Jeong #define REG_CONFIG	0x01
25*28e64a68SDaniel Jeong #define REG_BRT_A	0x03
26*28e64a68SDaniel Jeong #define REG_BRT_B	0x04
27*28e64a68SDaniel Jeong #define REG_I_A		0x05
28*28e64a68SDaniel Jeong #define REG_I_B		0x06
29*28e64a68SDaniel Jeong #define REG_INT_STATUS	0x09
30*28e64a68SDaniel Jeong #define REG_INT_EN	0x0A
31*28e64a68SDaniel Jeong #define REG_FAULT	0x0B
32*28e64a68SDaniel Jeong #define REG_PWM_OUTLOW	0x12
33*28e64a68SDaniel Jeong #define REG_PWM_OUTHIGH	0x13
34*28e64a68SDaniel Jeong #define REG_MAX		0x1F
35*28e64a68SDaniel Jeong 
36*28e64a68SDaniel Jeong #define INT_DEBOUNCE_MSEC	10
37*28e64a68SDaniel Jeong struct lm3630a_chip {
38*28e64a68SDaniel Jeong 	struct device *dev;
39*28e64a68SDaniel Jeong 	struct delayed_work work;
40*28e64a68SDaniel Jeong 
41*28e64a68SDaniel Jeong 	int irq;
42*28e64a68SDaniel Jeong 	struct workqueue_struct *irqthread;
43*28e64a68SDaniel Jeong 	struct lm3630a_platform_data *pdata;
44*28e64a68SDaniel Jeong 	struct backlight_device *bleda;
45*28e64a68SDaniel Jeong 	struct backlight_device *bledb;
46*28e64a68SDaniel Jeong 	struct regmap *regmap;
47*28e64a68SDaniel Jeong 	struct pwm_device *pwmd;
48*28e64a68SDaniel Jeong };
49*28e64a68SDaniel Jeong 
50*28e64a68SDaniel Jeong /* i2c access */
51*28e64a68SDaniel Jeong static int lm3630a_read(struct lm3630a_chip *pchip, unsigned int reg)
52*28e64a68SDaniel Jeong {
53*28e64a68SDaniel Jeong 	int rval;
54*28e64a68SDaniel Jeong 	unsigned int reg_val;
55*28e64a68SDaniel Jeong 
56*28e64a68SDaniel Jeong 	rval = regmap_read(pchip->regmap, reg, &reg_val);
57*28e64a68SDaniel Jeong 	if (rval < 0)
58*28e64a68SDaniel Jeong 		return rval;
59*28e64a68SDaniel Jeong 	return reg_val & 0xFF;
60*28e64a68SDaniel Jeong }
61*28e64a68SDaniel Jeong 
62*28e64a68SDaniel Jeong static int lm3630a_write(struct lm3630a_chip *pchip,
63*28e64a68SDaniel Jeong 			 unsigned int reg, unsigned int data)
64*28e64a68SDaniel Jeong {
65*28e64a68SDaniel Jeong 	return regmap_write(pchip->regmap, reg, data);
66*28e64a68SDaniel Jeong }
67*28e64a68SDaniel Jeong 
68*28e64a68SDaniel Jeong static int lm3630a_update(struct lm3630a_chip *pchip,
69*28e64a68SDaniel Jeong 			  unsigned int reg, unsigned int mask,
70*28e64a68SDaniel Jeong 			  unsigned int data)
71*28e64a68SDaniel Jeong {
72*28e64a68SDaniel Jeong 	return regmap_update_bits(pchip->regmap, reg, mask, data);
73*28e64a68SDaniel Jeong }
74*28e64a68SDaniel Jeong 
75*28e64a68SDaniel Jeong /* initialize chip */
76*28e64a68SDaniel Jeong static int lm3630a_chip_init(struct lm3630a_chip *pchip)
77*28e64a68SDaniel Jeong {
78*28e64a68SDaniel Jeong 	int rval;
79*28e64a68SDaniel Jeong 	struct lm3630a_platform_data *pdata = pchip->pdata;
80*28e64a68SDaniel Jeong 
81*28e64a68SDaniel Jeong 	usleep_range(1000, 2000);
82*28e64a68SDaniel Jeong 	/* set Filter Strength Register */
83*28e64a68SDaniel Jeong 	rval = lm3630a_write(pchip, 0x50, 0x03);
84*28e64a68SDaniel Jeong 	/* set Cofig. register */
85*28e64a68SDaniel Jeong 	rval |= lm3630a_update(pchip, REG_CONFIG, 0x07, pdata->pwm_ctrl);
86*28e64a68SDaniel Jeong 	/* set boost control */
87*28e64a68SDaniel Jeong 	rval |= lm3630a_write(pchip, REG_BOOST, 0x38);
88*28e64a68SDaniel Jeong 	/* set current A */
89*28e64a68SDaniel Jeong 	rval |= lm3630a_update(pchip, REG_I_A, 0x1F, 0x1F);
90*28e64a68SDaniel Jeong 	/* set current B */
91*28e64a68SDaniel Jeong 	rval |= lm3630a_write(pchip, REG_I_B, 0x1F);
92*28e64a68SDaniel Jeong 	/* set control */
93*28e64a68SDaniel Jeong 	rval |=
94*28e64a68SDaniel Jeong 	    lm3630a_write(pchip, REG_CTRL, pdata->leda_ctrl | pdata->ledb_ctrl);
95*28e64a68SDaniel Jeong 	usleep_range(1000, 2000);
96*28e64a68SDaniel Jeong 	/* set brightness A and B */
97*28e64a68SDaniel Jeong 	rval |= lm3630a_write(pchip, REG_BRT_A, pdata->leda_init_brt);
98*28e64a68SDaniel Jeong 	rval |= lm3630a_write(pchip, REG_BRT_B, pdata->ledb_init_brt);
99*28e64a68SDaniel Jeong 
100*28e64a68SDaniel Jeong 	if (rval < 0)
101*28e64a68SDaniel Jeong 		dev_err(pchip->dev, "i2c failed to access register\n");
102*28e64a68SDaniel Jeong 	return rval;
103*28e64a68SDaniel Jeong }
104*28e64a68SDaniel Jeong 
105*28e64a68SDaniel Jeong /* interrupt handling */
106*28e64a68SDaniel Jeong static void lm3630a_delayed_func(struct work_struct *work)
107*28e64a68SDaniel Jeong {
108*28e64a68SDaniel Jeong 	unsigned int rval;
109*28e64a68SDaniel Jeong 	struct lm3630a_chip *pchip;
110*28e64a68SDaniel Jeong 
111*28e64a68SDaniel Jeong 	pchip = container_of(work, struct lm3630a_chip, work.work);
112*28e64a68SDaniel Jeong 
113*28e64a68SDaniel Jeong 	rval = lm3630a_read(pchip, REG_INT_STATUS);
114*28e64a68SDaniel Jeong 	if (rval < 0) {
115*28e64a68SDaniel Jeong 		dev_err(pchip->dev,
116*28e64a68SDaniel Jeong 			"i2c failed to access REG_INT_STATUS Register\n");
117*28e64a68SDaniel Jeong 		return;
118*28e64a68SDaniel Jeong 	}
119*28e64a68SDaniel Jeong 
120*28e64a68SDaniel Jeong 	dev_info(pchip->dev, "REG_INT_STATUS Register is 0x%x\n", rval);
121*28e64a68SDaniel Jeong }
122*28e64a68SDaniel Jeong 
123*28e64a68SDaniel Jeong static irqreturn_t lm3630a_isr_func(int irq, void *chip)
124*28e64a68SDaniel Jeong {
125*28e64a68SDaniel Jeong 	int rval;
126*28e64a68SDaniel Jeong 	struct lm3630a_chip *pchip = chip;
127*28e64a68SDaniel Jeong 	unsigned long delay = msecs_to_jiffies(INT_DEBOUNCE_MSEC);
128*28e64a68SDaniel Jeong 
129*28e64a68SDaniel Jeong 	queue_delayed_work(pchip->irqthread, &pchip->work, delay);
130*28e64a68SDaniel Jeong 
131*28e64a68SDaniel Jeong 	rval = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00);
132*28e64a68SDaniel Jeong 	if (rval < 0) {
133*28e64a68SDaniel Jeong 		dev_err(pchip->dev, "i2c failed to access register\n");
134*28e64a68SDaniel Jeong 		return IRQ_NONE;
135*28e64a68SDaniel Jeong 	}
136*28e64a68SDaniel Jeong 	return IRQ_HANDLED;
137*28e64a68SDaniel Jeong }
138*28e64a68SDaniel Jeong 
139*28e64a68SDaniel Jeong static int lm3630a_intr_config(struct lm3630a_chip *pchip)
140*28e64a68SDaniel Jeong {
141*28e64a68SDaniel Jeong 	int rval;
142*28e64a68SDaniel Jeong 
143*28e64a68SDaniel Jeong 	rval = lm3630a_write(pchip, REG_INT_EN, 0x87);
144*28e64a68SDaniel Jeong 	if (rval < 0)
145*28e64a68SDaniel Jeong 		return rval;
146*28e64a68SDaniel Jeong 
147*28e64a68SDaniel Jeong 	INIT_DELAYED_WORK(&pchip->work, lm3630a_delayed_func);
148*28e64a68SDaniel Jeong 	pchip->irqthread = create_singlethread_workqueue("lm3630a-irqthd");
149*28e64a68SDaniel Jeong 	if (!pchip->irqthread) {
150*28e64a68SDaniel Jeong 		dev_err(pchip->dev, "create irq thread fail\n");
151*28e64a68SDaniel Jeong 		return -ENOMEM;
152*28e64a68SDaniel Jeong 	}
153*28e64a68SDaniel Jeong 	if (request_threaded_irq
154*28e64a68SDaniel Jeong 	    (pchip->irq, NULL, lm3630a_isr_func,
155*28e64a68SDaniel Jeong 	     IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "lm3630a_irq", pchip)) {
156*28e64a68SDaniel Jeong 		dev_err(pchip->dev, "request threaded irq fail\n");
157*28e64a68SDaniel Jeong 		return -ENOMEM;
158*28e64a68SDaniel Jeong 	}
159*28e64a68SDaniel Jeong 	return rval;
160*28e64a68SDaniel Jeong }
161*28e64a68SDaniel Jeong 
162*28e64a68SDaniel Jeong static void lm3630a_pwm_ctrl(struct lm3630a_chip *pchip, int br, int br_max)
163*28e64a68SDaniel Jeong {
164*28e64a68SDaniel Jeong 	unsigned int period = pwm_get_period(pchip->pwmd);
165*28e64a68SDaniel Jeong 	unsigned int duty = br * period / br_max;
166*28e64a68SDaniel Jeong 
167*28e64a68SDaniel Jeong 	pwm_config(pchip->pwmd, duty, period);
168*28e64a68SDaniel Jeong 	if (duty)
169*28e64a68SDaniel Jeong 		pwm_enable(pchip->pwmd);
170*28e64a68SDaniel Jeong 	else
171*28e64a68SDaniel Jeong 		pwm_disable(pchip->pwmd);
172*28e64a68SDaniel Jeong }
173*28e64a68SDaniel Jeong 
174*28e64a68SDaniel Jeong /* update and get brightness */
175*28e64a68SDaniel Jeong static int lm3630a_bank_a_update_status(struct backlight_device *bl)
176*28e64a68SDaniel Jeong {
177*28e64a68SDaniel Jeong 	int ret;
178*28e64a68SDaniel Jeong 	struct lm3630a_chip *pchip = bl_get_data(bl);
179*28e64a68SDaniel Jeong 	enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl;
180*28e64a68SDaniel Jeong 
181*28e64a68SDaniel Jeong 	/* pwm control */
182*28e64a68SDaniel Jeong 	if ((pwm_ctrl & LM3630A_PWM_BANK_A) != 0) {
183*28e64a68SDaniel Jeong 		lm3630a_pwm_ctrl(pchip, bl->props.brightness,
184*28e64a68SDaniel Jeong 				 bl->props.max_brightness);
185*28e64a68SDaniel Jeong 		return bl->props.brightness;
186*28e64a68SDaniel Jeong 	}
187*28e64a68SDaniel Jeong 
188*28e64a68SDaniel Jeong 	/* disable sleep */
189*28e64a68SDaniel Jeong 	ret = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00);
190*28e64a68SDaniel Jeong 	if (ret < 0)
191*28e64a68SDaniel Jeong 		goto out_i2c_err;
192*28e64a68SDaniel Jeong 	usleep_range(1000, 2000);
193*28e64a68SDaniel Jeong 	/* minimum brightness is 0x04 */
194*28e64a68SDaniel Jeong 	ret = lm3630a_write(pchip, REG_BRT_A, bl->props.brightness);
195*28e64a68SDaniel Jeong 	if (bl->props.brightness < 0x4)
196*28e64a68SDaniel Jeong 		ret |= lm3630a_update(pchip, REG_CTRL, LM3630A_LEDA_ENABLE, 0);
197*28e64a68SDaniel Jeong 	else
198*28e64a68SDaniel Jeong 		ret |= lm3630a_update(pchip, REG_CTRL,
199*28e64a68SDaniel Jeong 				      LM3630A_LEDA_ENABLE, LM3630A_LEDA_ENABLE);
200*28e64a68SDaniel Jeong 	if (ret < 0)
201*28e64a68SDaniel Jeong 		goto out_i2c_err;
202*28e64a68SDaniel Jeong 	return bl->props.brightness;
203*28e64a68SDaniel Jeong 
204*28e64a68SDaniel Jeong out_i2c_err:
205*28e64a68SDaniel Jeong 	dev_err(pchip->dev, "i2c failed to access\n");
206*28e64a68SDaniel Jeong 	return bl->props.brightness;
207*28e64a68SDaniel Jeong }
208*28e64a68SDaniel Jeong 
209*28e64a68SDaniel Jeong static int lm3630a_bank_a_get_brightness(struct backlight_device *bl)
210*28e64a68SDaniel Jeong {
211*28e64a68SDaniel Jeong 	int brightness, rval;
212*28e64a68SDaniel Jeong 	struct lm3630a_chip *pchip = bl_get_data(bl);
213*28e64a68SDaniel Jeong 	enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl;
214*28e64a68SDaniel Jeong 
215*28e64a68SDaniel Jeong 	if ((pwm_ctrl & LM3630A_PWM_BANK_A) != 0) {
216*28e64a68SDaniel Jeong 		rval = lm3630a_read(pchip, REG_PWM_OUTHIGH);
217*28e64a68SDaniel Jeong 		if (rval < 0)
218*28e64a68SDaniel Jeong 			goto out_i2c_err;
219*28e64a68SDaniel Jeong 		brightness = (rval & 0x01) << 8;
220*28e64a68SDaniel Jeong 		rval = lm3630a_read(pchip, REG_PWM_OUTLOW);
221*28e64a68SDaniel Jeong 		if (rval < 0)
222*28e64a68SDaniel Jeong 			goto out_i2c_err;
223*28e64a68SDaniel Jeong 		brightness |= rval;
224*28e64a68SDaniel Jeong 		goto out;
225*28e64a68SDaniel Jeong 	}
226*28e64a68SDaniel Jeong 
227*28e64a68SDaniel Jeong 	/* disable sleep */
228*28e64a68SDaniel Jeong 	rval = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00);
229*28e64a68SDaniel Jeong 	if (rval < 0)
230*28e64a68SDaniel Jeong 		goto out_i2c_err;
231*28e64a68SDaniel Jeong 	usleep_range(1000, 2000);
232*28e64a68SDaniel Jeong 	rval = lm3630a_read(pchip, REG_BRT_A);
233*28e64a68SDaniel Jeong 	if (rval < 0)
234*28e64a68SDaniel Jeong 		goto out_i2c_err;
235*28e64a68SDaniel Jeong 	brightness = rval;
236*28e64a68SDaniel Jeong 
237*28e64a68SDaniel Jeong out:
238*28e64a68SDaniel Jeong 	bl->props.brightness = brightness;
239*28e64a68SDaniel Jeong 	return bl->props.brightness;
240*28e64a68SDaniel Jeong out_i2c_err:
241*28e64a68SDaniel Jeong 	dev_err(pchip->dev, "i2c failed to access register\n");
242*28e64a68SDaniel Jeong 	return 0;
243*28e64a68SDaniel Jeong }
244*28e64a68SDaniel Jeong 
245*28e64a68SDaniel Jeong static const struct backlight_ops lm3630a_bank_a_ops = {
246*28e64a68SDaniel Jeong 	.options = BL_CORE_SUSPENDRESUME,
247*28e64a68SDaniel Jeong 	.update_status = lm3630a_bank_a_update_status,
248*28e64a68SDaniel Jeong 	.get_brightness = lm3630a_bank_a_get_brightness,
249*28e64a68SDaniel Jeong };
250*28e64a68SDaniel Jeong 
251*28e64a68SDaniel Jeong /* update and get brightness */
252*28e64a68SDaniel Jeong static int lm3630a_bank_b_update_status(struct backlight_device *bl)
253*28e64a68SDaniel Jeong {
254*28e64a68SDaniel Jeong 	int ret;
255*28e64a68SDaniel Jeong 	struct lm3630a_chip *pchip = bl_get_data(bl);
256*28e64a68SDaniel Jeong 	enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl;
257*28e64a68SDaniel Jeong 
258*28e64a68SDaniel Jeong 	/* pwm control */
259*28e64a68SDaniel Jeong 	if ((pwm_ctrl & LM3630A_PWM_BANK_B) != 0) {
260*28e64a68SDaniel Jeong 		lm3630a_pwm_ctrl(pchip, bl->props.brightness,
261*28e64a68SDaniel Jeong 				 bl->props.max_brightness);
262*28e64a68SDaniel Jeong 		return bl->props.brightness;
263*28e64a68SDaniel Jeong 	}
264*28e64a68SDaniel Jeong 
265*28e64a68SDaniel Jeong 	/* disable sleep */
266*28e64a68SDaniel Jeong 	ret = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00);
267*28e64a68SDaniel Jeong 	if (ret < 0)
268*28e64a68SDaniel Jeong 		goto out_i2c_err;
269*28e64a68SDaniel Jeong 	usleep_range(1000, 2000);
270*28e64a68SDaniel Jeong 	/* minimum brightness is 0x04 */
271*28e64a68SDaniel Jeong 	ret = lm3630a_write(pchip, REG_BRT_B, bl->props.brightness);
272*28e64a68SDaniel Jeong 	if (bl->props.brightness < 0x4)
273*28e64a68SDaniel Jeong 		ret |= lm3630a_update(pchip, REG_CTRL, LM3630A_LEDB_ENABLE, 0);
274*28e64a68SDaniel Jeong 	else
275*28e64a68SDaniel Jeong 		ret |= lm3630a_update(pchip, REG_CTRL,
276*28e64a68SDaniel Jeong 				      LM3630A_LEDB_ENABLE, LM3630A_LEDB_ENABLE);
277*28e64a68SDaniel Jeong 	if (ret < 0)
278*28e64a68SDaniel Jeong 		goto out_i2c_err;
279*28e64a68SDaniel Jeong 	return bl->props.brightness;
280*28e64a68SDaniel Jeong 
281*28e64a68SDaniel Jeong out_i2c_err:
282*28e64a68SDaniel Jeong 	dev_err(pchip->dev, "i2c failed to access REG_CTRL\n");
283*28e64a68SDaniel Jeong 	return bl->props.brightness;
284*28e64a68SDaniel Jeong }
285*28e64a68SDaniel Jeong 
286*28e64a68SDaniel Jeong static int lm3630a_bank_b_get_brightness(struct backlight_device *bl)
287*28e64a68SDaniel Jeong {
288*28e64a68SDaniel Jeong 	int brightness, rval;
289*28e64a68SDaniel Jeong 	struct lm3630a_chip *pchip = bl_get_data(bl);
290*28e64a68SDaniel Jeong 	enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl;
291*28e64a68SDaniel Jeong 
292*28e64a68SDaniel Jeong 	if ((pwm_ctrl & LM3630A_PWM_BANK_B) != 0) {
293*28e64a68SDaniel Jeong 		rval = lm3630a_read(pchip, REG_PWM_OUTHIGH);
294*28e64a68SDaniel Jeong 		if (rval < 0)
295*28e64a68SDaniel Jeong 			goto out_i2c_err;
296*28e64a68SDaniel Jeong 		brightness = (rval & 0x01) << 8;
297*28e64a68SDaniel Jeong 		rval = lm3630a_read(pchip, REG_PWM_OUTLOW);
298*28e64a68SDaniel Jeong 		if (rval < 0)
299*28e64a68SDaniel Jeong 			goto out_i2c_err;
300*28e64a68SDaniel Jeong 		brightness |= rval;
301*28e64a68SDaniel Jeong 		goto out;
302*28e64a68SDaniel Jeong 	}
303*28e64a68SDaniel Jeong 
304*28e64a68SDaniel Jeong 	/* disable sleep */
305*28e64a68SDaniel Jeong 	rval = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00);
306*28e64a68SDaniel Jeong 	if (rval < 0)
307*28e64a68SDaniel Jeong 		goto out_i2c_err;
308*28e64a68SDaniel Jeong 	usleep_range(1000, 2000);
309*28e64a68SDaniel Jeong 	rval = lm3630a_read(pchip, REG_BRT_B);
310*28e64a68SDaniel Jeong 	if (rval < 0)
311*28e64a68SDaniel Jeong 		goto out_i2c_err;
312*28e64a68SDaniel Jeong 	brightness = rval;
313*28e64a68SDaniel Jeong 
314*28e64a68SDaniel Jeong out:
315*28e64a68SDaniel Jeong 	bl->props.brightness = brightness;
316*28e64a68SDaniel Jeong 	return bl->props.brightness;
317*28e64a68SDaniel Jeong out_i2c_err:
318*28e64a68SDaniel Jeong 	dev_err(pchip->dev, "i2c failed to access register\n");
319*28e64a68SDaniel Jeong 	return 0;
320*28e64a68SDaniel Jeong }
321*28e64a68SDaniel Jeong 
322*28e64a68SDaniel Jeong static const struct backlight_ops lm3630a_bank_b_ops = {
323*28e64a68SDaniel Jeong 	.options = BL_CORE_SUSPENDRESUME,
324*28e64a68SDaniel Jeong 	.update_status = lm3630a_bank_b_update_status,
325*28e64a68SDaniel Jeong 	.get_brightness = lm3630a_bank_b_get_brightness,
326*28e64a68SDaniel Jeong };
327*28e64a68SDaniel Jeong 
328*28e64a68SDaniel Jeong static int lm3630a_backlight_register(struct lm3630a_chip *pchip)
329*28e64a68SDaniel Jeong {
330*28e64a68SDaniel Jeong 	struct backlight_properties props;
331*28e64a68SDaniel Jeong 	struct lm3630a_platform_data *pdata = pchip->pdata;
332*28e64a68SDaniel Jeong 
333*28e64a68SDaniel Jeong 	props.type = BACKLIGHT_RAW;
334*28e64a68SDaniel Jeong 	if (pdata->leda_ctrl != LM3630A_LEDA_DISABLE) {
335*28e64a68SDaniel Jeong 		props.brightness = pdata->leda_init_brt;
336*28e64a68SDaniel Jeong 		props.max_brightness = pdata->leda_max_brt;
337*28e64a68SDaniel Jeong 		pchip->bleda =
338*28e64a68SDaniel Jeong 		    devm_backlight_device_register(pchip->dev, "lm3630a_leda",
339*28e64a68SDaniel Jeong 						   pchip->dev, pchip,
340*28e64a68SDaniel Jeong 						   &lm3630a_bank_a_ops, &props);
341*28e64a68SDaniel Jeong 		if (IS_ERR(pchip->bleda))
342*28e64a68SDaniel Jeong 			return PTR_ERR(pchip->bleda);
343*28e64a68SDaniel Jeong 	}
344*28e64a68SDaniel Jeong 
345*28e64a68SDaniel Jeong 	if ((pdata->ledb_ctrl != LM3630A_LEDB_DISABLE) &&
346*28e64a68SDaniel Jeong 	    (pdata->ledb_ctrl != LM3630A_LEDB_ON_A)) {
347*28e64a68SDaniel Jeong 		props.brightness = pdata->ledb_init_brt;
348*28e64a68SDaniel Jeong 		props.max_brightness = pdata->ledb_max_brt;
349*28e64a68SDaniel Jeong 		pchip->bledb =
350*28e64a68SDaniel Jeong 		    devm_backlight_device_register(pchip->dev, "lm3630a_ledb",
351*28e64a68SDaniel Jeong 						   pchip->dev, pchip,
352*28e64a68SDaniel Jeong 						   &lm3630a_bank_b_ops, &props);
353*28e64a68SDaniel Jeong 		if (IS_ERR(pchip->bledb))
354*28e64a68SDaniel Jeong 			return PTR_ERR(pchip->bledb);
355*28e64a68SDaniel Jeong 	}
356*28e64a68SDaniel Jeong 	return 0;
357*28e64a68SDaniel Jeong }
358*28e64a68SDaniel Jeong 
359*28e64a68SDaniel Jeong static const struct regmap_config lm3630a_regmap = {
360*28e64a68SDaniel Jeong 	.reg_bits = 8,
361*28e64a68SDaniel Jeong 	.val_bits = 8,
362*28e64a68SDaniel Jeong 	.max_register = REG_MAX,
363*28e64a68SDaniel Jeong };
364*28e64a68SDaniel Jeong 
365*28e64a68SDaniel Jeong static int lm3630a_probe(struct i2c_client *client,
366*28e64a68SDaniel Jeong 			 const struct i2c_device_id *id)
367*28e64a68SDaniel Jeong {
368*28e64a68SDaniel Jeong 	struct lm3630a_platform_data *pdata = client->dev.platform_data;
369*28e64a68SDaniel Jeong 	struct lm3630a_chip *pchip;
370*28e64a68SDaniel Jeong 	int rval;
371*28e64a68SDaniel Jeong 
372*28e64a68SDaniel Jeong 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
373*28e64a68SDaniel Jeong 		dev_err(&client->dev, "fail : i2c functionality check\n");
374*28e64a68SDaniel Jeong 		return -EOPNOTSUPP;
375*28e64a68SDaniel Jeong 	}
376*28e64a68SDaniel Jeong 
377*28e64a68SDaniel Jeong 	pchip = devm_kzalloc(&client->dev, sizeof(struct lm3630a_chip),
378*28e64a68SDaniel Jeong 			     GFP_KERNEL);
379*28e64a68SDaniel Jeong 	if (!pchip)
380*28e64a68SDaniel Jeong 		return -ENOMEM;
381*28e64a68SDaniel Jeong 	pchip->dev = &client->dev;
382*28e64a68SDaniel Jeong 
383*28e64a68SDaniel Jeong 	pchip->regmap = devm_regmap_init_i2c(client, &lm3630a_regmap);
384*28e64a68SDaniel Jeong 	if (IS_ERR(pchip->regmap)) {
385*28e64a68SDaniel Jeong 		rval = PTR_ERR(pchip->regmap);
386*28e64a68SDaniel Jeong 		dev_err(&client->dev, "fail : allocate reg. map: %d\n", rval);
387*28e64a68SDaniel Jeong 		return rval;
388*28e64a68SDaniel Jeong 	}
389*28e64a68SDaniel Jeong 
390*28e64a68SDaniel Jeong 	i2c_set_clientdata(client, pchip);
391*28e64a68SDaniel Jeong 	if (pdata == NULL) {
392*28e64a68SDaniel Jeong 		pchip->pdata = devm_kzalloc(pchip->dev,
393*28e64a68SDaniel Jeong 					    sizeof(struct
394*28e64a68SDaniel Jeong 						   lm3630a_platform_data),
395*28e64a68SDaniel Jeong 					    GFP_KERNEL);
396*28e64a68SDaniel Jeong 		if (pchip->pdata == NULL)
397*28e64a68SDaniel Jeong 			return -ENOMEM;
398*28e64a68SDaniel Jeong 		/* default values */
399*28e64a68SDaniel Jeong 		pchip->pdata->leda_ctrl = LM3630A_LEDA_ENABLE;
400*28e64a68SDaniel Jeong 		pchip->pdata->ledb_ctrl = LM3630A_LEDB_ENABLE;
401*28e64a68SDaniel Jeong 		pchip->pdata->leda_max_brt = LM3630A_MAX_BRIGHTNESS;
402*28e64a68SDaniel Jeong 		pchip->pdata->ledb_max_brt = LM3630A_MAX_BRIGHTNESS;
403*28e64a68SDaniel Jeong 		pchip->pdata->leda_init_brt = LM3630A_MAX_BRIGHTNESS;
404*28e64a68SDaniel Jeong 		pchip->pdata->ledb_init_brt = LM3630A_MAX_BRIGHTNESS;
405*28e64a68SDaniel Jeong 	} else {
406*28e64a68SDaniel Jeong 		pchip->pdata = pdata;
407*28e64a68SDaniel Jeong 	}
408*28e64a68SDaniel Jeong 	/* chip initialize */
409*28e64a68SDaniel Jeong 	rval = lm3630a_chip_init(pchip);
410*28e64a68SDaniel Jeong 	if (rval < 0) {
411*28e64a68SDaniel Jeong 		dev_err(&client->dev, "fail : init chip\n");
412*28e64a68SDaniel Jeong 		return rval;
413*28e64a68SDaniel Jeong 	}
414*28e64a68SDaniel Jeong 	/* backlight register */
415*28e64a68SDaniel Jeong 	rval = lm3630a_backlight_register(pchip);
416*28e64a68SDaniel Jeong 	if (rval < 0) {
417*28e64a68SDaniel Jeong 		dev_err(&client->dev, "fail : backlight register.\n");
418*28e64a68SDaniel Jeong 		return rval;
419*28e64a68SDaniel Jeong 	}
420*28e64a68SDaniel Jeong 	/* pwm */
421*28e64a68SDaniel Jeong 	if (pdata->pwm_ctrl != LM3630A_PWM_DISABLE) {
422*28e64a68SDaniel Jeong 		pchip->pwmd = devm_pwm_get(pchip->dev, "lm3630a-pwm");
423*28e64a68SDaniel Jeong 		if (IS_ERR(pchip->pwmd)) {
424*28e64a68SDaniel Jeong 			dev_err(&client->dev, "fail : get pwm device\n");
425*28e64a68SDaniel Jeong 			return PTR_ERR(pchip->pwmd);
426*28e64a68SDaniel Jeong 		}
427*28e64a68SDaniel Jeong 	}
428*28e64a68SDaniel Jeong 	pchip->pwmd->period = pdata->pwm_period;
429*28e64a68SDaniel Jeong 
430*28e64a68SDaniel Jeong 	/* interrupt enable  : irq 0 is not allowed */
431*28e64a68SDaniel Jeong 	pchip->irq = client->irq;
432*28e64a68SDaniel Jeong 	if (pchip->irq) {
433*28e64a68SDaniel Jeong 		rval = lm3630a_intr_config(pchip);
434*28e64a68SDaniel Jeong 		if (rval < 0)
435*28e64a68SDaniel Jeong 			return rval;
436*28e64a68SDaniel Jeong 	}
437*28e64a68SDaniel Jeong 	dev_info(&client->dev, "LM3630A backlight register OK.\n");
438*28e64a68SDaniel Jeong 	return 0;
439*28e64a68SDaniel Jeong }
440*28e64a68SDaniel Jeong 
441*28e64a68SDaniel Jeong static int lm3630a_remove(struct i2c_client *client)
442*28e64a68SDaniel Jeong {
443*28e64a68SDaniel Jeong 	int rval;
444*28e64a68SDaniel Jeong 	struct lm3630a_chip *pchip = i2c_get_clientdata(client);
445*28e64a68SDaniel Jeong 
446*28e64a68SDaniel Jeong 	rval = lm3630a_write(pchip, REG_BRT_A, 0);
447*28e64a68SDaniel Jeong 	if (rval < 0)
448*28e64a68SDaniel Jeong 		dev_err(pchip->dev, "i2c failed to access register\n");
449*28e64a68SDaniel Jeong 
450*28e64a68SDaniel Jeong 	rval = lm3630a_write(pchip, REG_BRT_B, 0);
451*28e64a68SDaniel Jeong 	if (rval < 0)
452*28e64a68SDaniel Jeong 		dev_err(pchip->dev, "i2c failed to access register\n");
453*28e64a68SDaniel Jeong 
454*28e64a68SDaniel Jeong 	if (pchip->irq) {
455*28e64a68SDaniel Jeong 		free_irq(pchip->irq, pchip);
456*28e64a68SDaniel Jeong 		flush_workqueue(pchip->irqthread);
457*28e64a68SDaniel Jeong 		destroy_workqueue(pchip->irqthread);
458*28e64a68SDaniel Jeong 	}
459*28e64a68SDaniel Jeong 	return 0;
460*28e64a68SDaniel Jeong }
461*28e64a68SDaniel Jeong 
462*28e64a68SDaniel Jeong static const struct i2c_device_id lm3630a_id[] = {
463*28e64a68SDaniel Jeong 	{LM3630A_NAME, 0},
464*28e64a68SDaniel Jeong 	{}
465*28e64a68SDaniel Jeong };
466*28e64a68SDaniel Jeong 
467*28e64a68SDaniel Jeong MODULE_DEVICE_TABLE(i2c, lm3630a_id);
468*28e64a68SDaniel Jeong 
469*28e64a68SDaniel Jeong static struct i2c_driver lm3630a_i2c_driver = {
470*28e64a68SDaniel Jeong 	.driver = {
471*28e64a68SDaniel Jeong 		   .name = LM3630A_NAME,
472*28e64a68SDaniel Jeong 		   },
473*28e64a68SDaniel Jeong 	.probe = lm3630a_probe,
474*28e64a68SDaniel Jeong 	.remove = lm3630a_remove,
475*28e64a68SDaniel Jeong 	.id_table = lm3630a_id,
476*28e64a68SDaniel Jeong };
477*28e64a68SDaniel Jeong 
478*28e64a68SDaniel Jeong module_i2c_driver(lm3630a_i2c_driver);
479*28e64a68SDaniel Jeong 
480*28e64a68SDaniel Jeong MODULE_DESCRIPTION("Texas Instruments Backlight driver for LM3630A");
481*28e64a68SDaniel Jeong MODULE_AUTHOR("Daniel Jeong <gshark.jeong@gmail.com>");
482*28e64a68SDaniel Jeong MODULE_AUTHOR("LDD MLP <ldd-mlp@list.ti.com>");
483*28e64a68SDaniel Jeong MODULE_LICENSE("GPL v2");
484