diff options
author | Steffen Trumtrar <s.trumtrar@pengutronix.de> | 2013-05-30 03:50:12 -0400 |
---|---|---|
committer | Thierry Reding <thierry.reding@gmail.com> | 2013-06-12 07:13:18 -0400 |
commit | 88b613e6234def882b0b601bf831bf89af2e27f0 (patch) | |
tree | f864f8df0292c43ef902ac893fcb0fb66b7d8256 /drivers/pwm | |
parent | 8796f9c5656dedd186eda88c07db6a58d1985938 (diff) |
pwm: add pca9685 driver
Add pwm driver for the NXP pca9685 16 channel pwm-led controller.
The driver is really barebones at this stage. E.g. the OE' pin and
therefore the corresponding registers are not supported.
The driver was tested on a HW where this pin is tied to GND.
Signed-off-by: Steffen Trumtrar <s.trumtrar@pengutronix.de>
[thierry.reding@gmail.com: style and whitespace cleanups]
Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
Diffstat (limited to 'drivers/pwm')
-rw-r--r-- | drivers/pwm/Kconfig | 9 | ||||
-rw-r--r-- | drivers/pwm/Makefile | 1 | ||||
-rw-r--r-- | drivers/pwm/pwm-pca9685.c | 298 |
3 files changed, 308 insertions, 0 deletions
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 115b64453493..d3fe3205d296 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig | |||
@@ -97,6 +97,15 @@ config PWM_MXS | |||
97 | To compile this driver as a module, choose M here: the module | 97 | To compile this driver as a module, choose M here: the module |
98 | will be called pwm-mxs. | 98 | will be called pwm-mxs. |
99 | 99 | ||
100 | config PWM_PCA9685 | ||
101 | tristate "NXP PCA9685 PWM driver" | ||
102 | depends on OF && REGMAP_I2C | ||
103 | help | ||
104 | Generic PWM framework driver for NXP PCA9685 LED controller. | ||
105 | |||
106 | To compile this driver as a module, choose M here: the module | ||
107 | will be called pwm-pca9685. | ||
108 | |||
100 | config PWM_PUV3 | 109 | config PWM_PUV3 |
101 | tristate "PKUnity NetBook-0916 PWM support" | 110 | tristate "PKUnity NetBook-0916 PWM support" |
102 | depends on ARCH_PUV3 | 111 | depends on ARCH_PUV3 |
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index 94ba21e24bd6..b3afc0a1800b 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile | |||
@@ -6,6 +6,7 @@ obj-$(CONFIG_PWM_IMX) += pwm-imx.o | |||
6 | obj-$(CONFIG_PWM_JZ4740) += pwm-jz4740.o | 6 | obj-$(CONFIG_PWM_JZ4740) += pwm-jz4740.o |
7 | obj-$(CONFIG_PWM_LPC32XX) += pwm-lpc32xx.o | 7 | obj-$(CONFIG_PWM_LPC32XX) += pwm-lpc32xx.o |
8 | obj-$(CONFIG_PWM_MXS) += pwm-mxs.o | 8 | obj-$(CONFIG_PWM_MXS) += pwm-mxs.o |
9 | obj-$(CONFIG_PWM_PCA9685) += pwm-pca9685.o | ||
9 | obj-$(CONFIG_PWM_PUV3) += pwm-puv3.o | 10 | obj-$(CONFIG_PWM_PUV3) += pwm-puv3.o |
10 | obj-$(CONFIG_PWM_PXA) += pwm-pxa.o | 11 | obj-$(CONFIG_PWM_PXA) += pwm-pxa.o |
11 | obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o | 12 | obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o |
diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c new file mode 100644 index 000000000000..2afc9043550a --- /dev/null +++ b/drivers/pwm/pwm-pca9685.c | |||
@@ -0,0 +1,298 @@ | |||
1 | /* | ||
2 | * Driver for PCA9685 16-channel 12-bit PWM LED controller | ||
3 | * | ||
4 | * Copyright (C) 2013 Steffen Trumtrar <s.trumtrar@pengutronix.de> | ||
5 | * | ||
6 | * based on the pwm-twl-led.c driver | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License version 2 as published by | ||
10 | * the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
15 | * more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License along with | ||
18 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
19 | */ | ||
20 | |||
21 | #include <linux/i2c.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | #include <linux/pwm.h> | ||
25 | #include <linux/regmap.h> | ||
26 | #include <linux/slab.h> | ||
27 | |||
28 | #define PCA9685_MODE1 0x00 | ||
29 | #define PCA9685_MODE2 0x01 | ||
30 | #define PCA9685_SUBADDR1 0x02 | ||
31 | #define PCA9685_SUBADDR2 0x03 | ||
32 | #define PCA9685_SUBADDR3 0x04 | ||
33 | #define PCA9685_ALLCALLADDR 0x05 | ||
34 | #define PCA9685_LEDX_ON_L 0x06 | ||
35 | #define PCA9685_LEDX_ON_H 0x07 | ||
36 | #define PCA9685_LEDX_OFF_L 0x08 | ||
37 | #define PCA9685_LEDX_OFF_H 0x09 | ||
38 | |||
39 | #define PCA9685_ALL_LED_ON_L 0xFA | ||
40 | #define PCA9685_ALL_LED_ON_H 0xFB | ||
41 | #define PCA9685_ALL_LED_OFF_L 0xFC | ||
42 | #define PCA9685_ALL_LED_OFF_H 0xFD | ||
43 | #define PCA9685_PRESCALE 0xFE | ||
44 | |||
45 | #define PCA9685_NUMREGS 0xFF | ||
46 | #define PCA9685_MAXCHAN 0x10 | ||
47 | |||
48 | #define LED_FULL (1 << 4) | ||
49 | #define MODE1_SLEEP (1 << 4) | ||
50 | #define MODE2_INVRT (1 << 4) | ||
51 | #define MODE2_OUTDRV (1 << 2) | ||
52 | |||
53 | #define LED_N_ON_H(N) (PCA9685_LEDX_ON_H + (4 * (N))) | ||
54 | #define LED_N_ON_L(N) (PCA9685_LEDX_ON_L + (4 * (N))) | ||
55 | #define LED_N_OFF_H(N) (PCA9685_LEDX_OFF_H + (4 * (N))) | ||
56 | #define LED_N_OFF_L(N) (PCA9685_LEDX_OFF_L + (4 * (N))) | ||
57 | |||
58 | struct pca9685 { | ||
59 | struct pwm_chip chip; | ||
60 | struct regmap *regmap; | ||
61 | int active_cnt; | ||
62 | }; | ||
63 | |||
64 | static inline struct pca9685 *to_pca(struct pwm_chip *chip) | ||
65 | { | ||
66 | return container_of(chip, struct pca9685, chip); | ||
67 | } | ||
68 | |||
69 | static int pca9685_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | ||
70 | int duty_ns, int period_ns) | ||
71 | { | ||
72 | struct pca9685 *pca = to_pca(chip); | ||
73 | unsigned long long duty; | ||
74 | unsigned int reg; | ||
75 | |||
76 | if (duty_ns < 1) { | ||
77 | if (pwm->hwpwm >= PCA9685_MAXCHAN) | ||
78 | reg = PCA9685_ALL_LED_OFF_H; | ||
79 | else | ||
80 | reg = LED_N_OFF_H(pwm->hwpwm); | ||
81 | |||
82 | regmap_write(pca->regmap, reg, LED_FULL); | ||
83 | |||
84 | return 0; | ||
85 | } | ||
86 | |||
87 | if (duty_ns == period_ns) { | ||
88 | if (pwm->hwpwm >= PCA9685_MAXCHAN) | ||
89 | reg = PCA9685_ALL_LED_ON_H; | ||
90 | else | ||
91 | reg = LED_N_ON_H(pwm->hwpwm); | ||
92 | |||
93 | regmap_write(pca->regmap, reg, LED_FULL); | ||
94 | |||
95 | return 0; | ||
96 | } | ||
97 | |||
98 | duty = 4096 * (unsigned long long)duty_ns; | ||
99 | duty = DIV_ROUND_UP_ULL(duty, period_ns); | ||
100 | |||
101 | if (pwm->hwpwm >= PCA9685_MAXCHAN) | ||
102 | reg = PCA9685_ALL_LED_OFF_L; | ||
103 | else | ||
104 | reg = LED_N_OFF_L(pwm->hwpwm); | ||
105 | |||
106 | regmap_write(pca->regmap, reg, (int)duty & 0xff); | ||
107 | |||
108 | if (pwm->hwpwm >= PCA9685_MAXCHAN) | ||
109 | reg = PCA9685_ALL_LED_OFF_H; | ||
110 | else | ||
111 | reg = LED_N_OFF_H(pwm->hwpwm); | ||
112 | |||
113 | regmap_write(pca->regmap, reg, ((int)duty >> 8) & 0xf); | ||
114 | |||
115 | return 0; | ||
116 | } | ||
117 | |||
118 | static int pca9685_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) | ||
119 | { | ||
120 | struct pca9685 *pca = to_pca(chip); | ||
121 | unsigned int reg; | ||
122 | |||
123 | /* | ||
124 | * The PWM subsystem does not support a pre-delay. | ||
125 | * So, set the ON-timeout to 0 | ||
126 | */ | ||
127 | if (pwm->hwpwm >= PCA9685_MAXCHAN) | ||
128 | reg = PCA9685_ALL_LED_ON_L; | ||
129 | else | ||
130 | reg = LED_N_ON_L(pwm->hwpwm); | ||
131 | |||
132 | regmap_write(pca->regmap, reg, 0); | ||
133 | |||
134 | if (pwm->hwpwm >= PCA9685_MAXCHAN) | ||
135 | reg = PCA9685_ALL_LED_ON_H; | ||
136 | else | ||
137 | reg = LED_N_ON_H(pwm->hwpwm); | ||
138 | |||
139 | regmap_write(pca->regmap, reg, 0); | ||
140 | |||
141 | /* | ||
142 | * Clear the full-off bit. | ||
143 | * It has precedence over the others and must be off. | ||
144 | */ | ||
145 | if (pwm->hwpwm >= PCA9685_MAXCHAN) | ||
146 | reg = PCA9685_ALL_LED_OFF_H; | ||
147 | else | ||
148 | reg = LED_N_OFF_H(pwm->hwpwm); | ||
149 | |||
150 | regmap_update_bits(pca->regmap, reg, LED_FULL, 0x0); | ||
151 | |||
152 | return 0; | ||
153 | } | ||
154 | |||
155 | static void pca9685_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) | ||
156 | { | ||
157 | struct pca9685 *pca = to_pca(chip); | ||
158 | unsigned int reg; | ||
159 | |||
160 | if (pwm->hwpwm >= PCA9685_MAXCHAN) | ||
161 | reg = PCA9685_ALL_LED_OFF_H; | ||
162 | else | ||
163 | reg = LED_N_OFF_H(pwm->hwpwm); | ||
164 | |||
165 | regmap_write(pca->regmap, reg, LED_FULL); | ||
166 | |||
167 | /* Clear the LED_OFF counter. */ | ||
168 | if (pwm->hwpwm >= PCA9685_MAXCHAN) | ||
169 | reg = PCA9685_ALL_LED_OFF_L; | ||
170 | else | ||
171 | reg = LED_N_OFF_L(pwm->hwpwm); | ||
172 | |||
173 | regmap_write(pca->regmap, reg, 0x0); | ||
174 | } | ||
175 | |||
176 | static int pca9685_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) | ||
177 | { | ||
178 | struct pca9685 *pca = to_pca(chip); | ||
179 | |||
180 | if (pca->active_cnt++ == 0) | ||
181 | return regmap_update_bits(pca->regmap, PCA9685_MODE1, | ||
182 | MODE1_SLEEP, 0x0); | ||
183 | |||
184 | return 0; | ||
185 | } | ||
186 | |||
187 | static void pca9685_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) | ||
188 | { | ||
189 | struct pca9685 *pca = to_pca(chip); | ||
190 | |||
191 | if (--pca->active_cnt == 0) | ||
192 | regmap_update_bits(pca->regmap, PCA9685_MODE1, MODE1_SLEEP, | ||
193 | 0x1); | ||
194 | } | ||
195 | |||
196 | static const struct pwm_ops pca9685_pwm_ops = { | ||
197 | .enable = pca9685_pwm_enable, | ||
198 | .disable = pca9685_pwm_disable, | ||
199 | .config = pca9685_pwm_config, | ||
200 | .request = pca9685_pwm_request, | ||
201 | .free = pca9685_pwm_free, | ||
202 | }; | ||
203 | |||
204 | static struct regmap_config pca9685_regmap_i2c_config = { | ||
205 | .reg_bits = 8, | ||
206 | .val_bits = 8, | ||
207 | .max_register = PCA9685_NUMREGS, | ||
208 | .cache_type = REGCACHE_NONE, | ||
209 | }; | ||
210 | |||
211 | static int pca9685_pwm_probe(struct i2c_client *client, | ||
212 | const struct i2c_device_id *id) | ||
213 | { | ||
214 | struct device_node *np = client->dev.of_node; | ||
215 | struct pca9685 *pca; | ||
216 | int ret; | ||
217 | int mode2; | ||
218 | |||
219 | pca = devm_kzalloc(&client->dev, sizeof(*pca), GFP_KERNEL); | ||
220 | if (!pca) | ||
221 | return -ENOMEM; | ||
222 | |||
223 | pca->regmap = devm_regmap_init_i2c(client, &pca9685_regmap_i2c_config); | ||
224 | if (IS_ERR(pca->regmap)) { | ||
225 | ret = PTR_ERR(pca->regmap); | ||
226 | dev_err(&client->dev, "Failed to initialize register map: %d\n", | ||
227 | ret); | ||
228 | return ret; | ||
229 | } | ||
230 | |||
231 | i2c_set_clientdata(client, pca); | ||
232 | |||
233 | regmap_read(pca->regmap, PCA9685_MODE2, &mode2); | ||
234 | |||
235 | if (of_property_read_bool(np, "invert")) | ||
236 | mode2 |= MODE2_INVRT; | ||
237 | else | ||
238 | mode2 &= ~MODE2_INVRT; | ||
239 | |||
240 | if (of_property_read_bool(np, "open-drain")) | ||
241 | mode2 &= ~MODE2_OUTDRV; | ||
242 | else | ||
243 | mode2 |= MODE2_OUTDRV; | ||
244 | |||
245 | regmap_write(pca->regmap, PCA9685_MODE2, mode2); | ||
246 | |||
247 | /* clear all "full off" bits */ | ||
248 | regmap_write(pca->regmap, PCA9685_ALL_LED_OFF_L, 0); | ||
249 | regmap_write(pca->regmap, PCA9685_ALL_LED_OFF_H, 0); | ||
250 | |||
251 | pca->chip.ops = &pca9685_pwm_ops; | ||
252 | /* add an extra channel for ALL_LED */ | ||
253 | pca->chip.npwm = PCA9685_MAXCHAN + 1; | ||
254 | |||
255 | pca->chip.dev = &client->dev; | ||
256 | pca->chip.base = -1; | ||
257 | pca->chip.can_sleep = true; | ||
258 | |||
259 | return pwmchip_add(&pca->chip); | ||
260 | } | ||
261 | |||
262 | static int pca9685_pwm_remove(struct i2c_client *client) | ||
263 | { | ||
264 | struct pca9685 *pca = i2c_get_clientdata(client); | ||
265 | |||
266 | regmap_update_bits(pca->regmap, PCA9685_MODE1, MODE1_SLEEP, 0x1); | ||
267 | |||
268 | return pwmchip_remove(&pca->chip); | ||
269 | } | ||
270 | |||
271 | static const struct i2c_device_id pca9685_id[] = { | ||
272 | { "pca9685", 0 }, | ||
273 | { /* sentinel */ }, | ||
274 | }; | ||
275 | MODULE_DEVICE_TABLE(i2c, pca9685_id); | ||
276 | |||
277 | static const struct of_device_id pca9685_dt_ids[] = { | ||
278 | { .compatible = "nxp,pca9685-pwm", }, | ||
279 | { /* sentinel */ } | ||
280 | }; | ||
281 | MODULE_DEVICE_TABLE(of, pca9685_dt_ids); | ||
282 | |||
283 | static struct i2c_driver pca9685_i2c_driver = { | ||
284 | .driver = { | ||
285 | .name = "pca9685-pwm", | ||
286 | .owner = THIS_MODULE, | ||
287 | .of_match_table = pca9685_dt_ids, | ||
288 | }, | ||
289 | .probe = pca9685_pwm_probe, | ||
290 | .remove = pca9685_pwm_remove, | ||
291 | .id_table = pca9685_id, | ||
292 | }; | ||
293 | |||
294 | module_i2c_driver(pca9685_i2c_driver); | ||
295 | |||
296 | MODULE_AUTHOR("Steffen Trumtrar <s.trumtrar@pengutronix.de>"); | ||
297 | MODULE_DESCRIPTION("PWM driver for PCA9685"); | ||
298 | MODULE_LICENSE("GPL"); | ||