2 * Driver for TWL4030/6030 Pulse Width Modulator used as LED driver
4 * Copyright (C) 2012 Texas Instruments
5 * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
7 * This driver is a complete rewrite of the former pwm-twl6030.c authorded by:
8 * Hemanth V <hemanthv@ti.com>
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published by
12 * the Free Software Foundation.
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19 * You should have received a copy of the GNU General Public License along with
20 * this program. If not, see <http://www.gnu.org/licenses/>.
23 #include <linux/module.h>
25 #include <linux/platform_device.h>
26 #include <linux/pwm.h>
27 #include <linux/mfd/twl.h>
28 #include <linux/slab.h>
31 * This driver handles the PWM driven LED terminals of TWL4030 and TWL6030.
32 * To generate the signal on TWL4030:
35 * TWL6030 has one LED pin with dedicated LEDPWM
38 #define TWL4030_LED_MAX 0x7f
39 #define TWL6030_LED_MAX 0xff
41 /* Registers, bits and macro for TWL4030 */
42 #define TWL4030_LEDEN_REG 0x00
43 #define TWL4030_PWMA_REG 0x01
45 #define TWL4030_LEDXON (1 << 0)
46 #define TWL4030_LEDXPWM (1 << 4)
47 #define TWL4030_LED_PINS (TWL4030_LEDXON | TWL4030_LEDXPWM)
48 #define TWL4030_LED_TOGGLE(led, x) ((x) << (led))
50 /* Register, bits and macro for TWL6030 */
51 #define TWL6030_LED_PWM_CTRL1 0xf4
52 #define TWL6030_LED_PWM_CTRL2 0xf5
54 #define TWL6040_LED_MODE_HW 0x00
55 #define TWL6040_LED_MODE_ON 0x01
56 #define TWL6040_LED_MODE_OFF 0x02
57 #define TWL6040_LED_MODE_MASK 0x03
59 struct twl_pwmled_chip
{
64 static inline struct twl_pwmled_chip
*to_twl(struct pwm_chip
*chip
)
66 return container_of(chip
, struct twl_pwmled_chip
, chip
);
69 static int twl4030_pwmled_config(struct pwm_chip
*chip
, struct pwm_device
*pwm
,
70 int duty_ns
, int period_ns
)
72 int duty_cycle
= DIV_ROUND_UP(duty_ns
* TWL4030_LED_MAX
, period_ns
) + 1;
73 u8 pwm_config
[2] = { 1, 0 };
77 * To configure the duty period:
78 * On-cycle is set to 1 (the minimum allowed value)
79 * The off time of 0 is not configurable, so the mapping is:
83 * 126 - > off cycle 127,
85 * When on cycle == off cycle the PWM will be always on
89 else if (duty_cycle
> TWL4030_LED_MAX
)
92 base
= pwm
->hwpwm
* 2 + TWL4030_PWMA_REG
;
94 pwm_config
[1] = duty_cycle
;
96 ret
= twl_i2c_write(TWL4030_MODULE_LED
, pwm_config
, base
, 2);
98 dev_err(chip
->dev
, "%s: Failed to configure PWM\n", pwm
->label
);
103 static int twl4030_pwmled_enable(struct pwm_chip
*chip
, struct pwm_device
*pwm
)
105 struct twl_pwmled_chip
*twl
= to_twl(chip
);
109 mutex_lock(&twl
->mutex
);
110 ret
= twl_i2c_read_u8(TWL4030_MODULE_LED
, &val
, TWL4030_LEDEN_REG
);
112 dev_err(chip
->dev
, "%s: Failed to read LEDEN\n", pwm
->label
);
116 val
|= TWL4030_LED_TOGGLE(pwm
->hwpwm
, TWL4030_LED_PINS
);
118 ret
= twl_i2c_write_u8(TWL4030_MODULE_LED
, val
, TWL4030_LEDEN_REG
);
120 dev_err(chip
->dev
, "%s: Failed to enable PWM\n", pwm
->label
);
123 mutex_unlock(&twl
->mutex
);
127 static void twl4030_pwmled_disable(struct pwm_chip
*chip
,
128 struct pwm_device
*pwm
)
130 struct twl_pwmled_chip
*twl
= to_twl(chip
);
134 mutex_lock(&twl
->mutex
);
135 ret
= twl_i2c_read_u8(TWL4030_MODULE_LED
, &val
, TWL4030_LEDEN_REG
);
137 dev_err(chip
->dev
, "%s: Failed to read LEDEN\n", pwm
->label
);
141 val
&= ~TWL4030_LED_TOGGLE(pwm
->hwpwm
, TWL4030_LED_PINS
);
143 ret
= twl_i2c_write_u8(TWL4030_MODULE_LED
, val
, TWL4030_LEDEN_REG
);
145 dev_err(chip
->dev
, "%s: Failed to disable PWM\n", pwm
->label
);
148 mutex_unlock(&twl
->mutex
);
151 static int twl6030_pwmled_config(struct pwm_chip
*chip
, struct pwm_device
*pwm
,
152 int duty_ns
, int period_ns
)
154 int duty_cycle
= (duty_ns
* TWL6030_LED_MAX
) / period_ns
;
158 on_time
= duty_cycle
& 0xff;
160 ret
= twl_i2c_write_u8(TWL6030_MODULE_ID1
, on_time
,
161 TWL6030_LED_PWM_CTRL1
);
163 dev_err(chip
->dev
, "%s: Failed to configure PWM\n", pwm
->label
);
168 static int twl6030_pwmled_enable(struct pwm_chip
*chip
, struct pwm_device
*pwm
)
170 struct twl_pwmled_chip
*twl
= to_twl(chip
);
174 mutex_lock(&twl
->mutex
);
175 ret
= twl_i2c_read_u8(TWL6030_MODULE_ID1
, &val
, TWL6030_LED_PWM_CTRL2
);
177 dev_err(chip
->dev
, "%s: Failed to read PWM_CTRL2\n",
182 val
&= ~TWL6040_LED_MODE_MASK
;
183 val
|= TWL6040_LED_MODE_ON
;
185 ret
= twl_i2c_write_u8(TWL6030_MODULE_ID1
, val
, TWL6030_LED_PWM_CTRL2
);
187 dev_err(chip
->dev
, "%s: Failed to enable PWM\n", pwm
->label
);
190 mutex_unlock(&twl
->mutex
);
194 static void twl6030_pwmled_disable(struct pwm_chip
*chip
,
195 struct pwm_device
*pwm
)
197 struct twl_pwmled_chip
*twl
= to_twl(chip
);
201 mutex_lock(&twl
->mutex
);
202 ret
= twl_i2c_read_u8(TWL6030_MODULE_ID1
, &val
, TWL6030_LED_PWM_CTRL2
);
204 dev_err(chip
->dev
, "%s: Failed to read PWM_CTRL2\n",
209 val
&= ~TWL6040_LED_MODE_MASK
;
210 val
|= TWL6040_LED_MODE_OFF
;
212 ret
= twl_i2c_write_u8(TWL6030_MODULE_ID1
, val
, TWL6030_LED_PWM_CTRL2
);
214 dev_err(chip
->dev
, "%s: Failed to disable PWM\n", pwm
->label
);
217 mutex_unlock(&twl
->mutex
);
220 static int twl6030_pwmled_request(struct pwm_chip
*chip
, struct pwm_device
*pwm
)
222 struct twl_pwmled_chip
*twl
= to_twl(chip
);
226 mutex_lock(&twl
->mutex
);
227 ret
= twl_i2c_read_u8(TWL6030_MODULE_ID1
, &val
, TWL6030_LED_PWM_CTRL2
);
229 dev_err(chip
->dev
, "%s: Failed to read PWM_CTRL2\n",
234 val
&= ~TWL6040_LED_MODE_MASK
;
235 val
|= TWL6040_LED_MODE_OFF
;
237 ret
= twl_i2c_write_u8(TWL6030_MODULE_ID1
, val
, TWL6030_LED_PWM_CTRL2
);
239 dev_err(chip
->dev
, "%s: Failed to request PWM\n", pwm
->label
);
242 mutex_unlock(&twl
->mutex
);
246 static void twl6030_pwmled_free(struct pwm_chip
*chip
, struct pwm_device
*pwm
)
248 struct twl_pwmled_chip
*twl
= to_twl(chip
);
252 mutex_lock(&twl
->mutex
);
253 ret
= twl_i2c_read_u8(TWL6030_MODULE_ID1
, &val
, TWL6030_LED_PWM_CTRL2
);
255 dev_err(chip
->dev
, "%s: Failed to read PWM_CTRL2\n",
260 val
&= ~TWL6040_LED_MODE_MASK
;
261 val
|= TWL6040_LED_MODE_HW
;
263 ret
= twl_i2c_write_u8(TWL6030_MODULE_ID1
, val
, TWL6030_LED_PWM_CTRL2
);
265 dev_err(chip
->dev
, "%s: Failed to free PWM\n", pwm
->label
);
268 mutex_unlock(&twl
->mutex
);
271 static const struct pwm_ops twl4030_pwmled_ops
= {
272 .enable
= twl4030_pwmled_enable
,
273 .disable
= twl4030_pwmled_disable
,
274 .config
= twl4030_pwmled_config
,
275 .owner
= THIS_MODULE
,
278 static const struct pwm_ops twl6030_pwmled_ops
= {
279 .enable
= twl6030_pwmled_enable
,
280 .disable
= twl6030_pwmled_disable
,
281 .config
= twl6030_pwmled_config
,
282 .request
= twl6030_pwmled_request
,
283 .free
= twl6030_pwmled_free
,
284 .owner
= THIS_MODULE
,
287 static int twl_pwmled_probe(struct platform_device
*pdev
)
289 struct twl_pwmled_chip
*twl
;
292 twl
= devm_kzalloc(&pdev
->dev
, sizeof(*twl
), GFP_KERNEL
);
296 if (twl_class_is_4030()) {
297 twl
->chip
.ops
= &twl4030_pwmled_ops
;
300 twl
->chip
.ops
= &twl6030_pwmled_ops
;
304 twl
->chip
.dev
= &pdev
->dev
;
307 mutex_init(&twl
->mutex
);
309 ret
= pwmchip_add(&twl
->chip
);
313 platform_set_drvdata(pdev
, twl
);
318 static int twl_pwmled_remove(struct platform_device
*pdev
)
320 struct twl_pwmled_chip
*twl
= platform_get_drvdata(pdev
);
322 return pwmchip_remove(&twl
->chip
);
326 static const struct of_device_id twl_pwmled_of_match
[] = {
327 { .compatible
= "ti,twl4030-pwmled" },
328 { .compatible
= "ti,twl6030-pwmled" },
331 MODULE_DEVICE_TABLE(of
, twl_pwmled_of_match
);
334 static struct platform_driver twl_pwmled_driver
= {
336 .name
= "twl-pwmled",
337 .of_match_table
= of_match_ptr(twl_pwmled_of_match
),
339 .probe
= twl_pwmled_probe
,
340 .remove
= twl_pwmled_remove
,
342 module_platform_driver(twl_pwmled_driver
);
344 MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
345 MODULE_DESCRIPTION("PWM driver for TWL4030 and TWL6030 LED outputs");
346 MODULE_ALIAS("platform:twl-pwmled");
347 MODULE_LICENSE("GPL");