Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Driver for TWL4030/6030 Pulse Width Modulator used as LED driver
0004  *
0005  * Copyright (C) 2012 Texas Instruments
0006  * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
0007  *
0008  * This driver is a complete rewrite of the former pwm-twl6030.c authorded by:
0009  * Hemanth V <hemanthv@ti.com>
0010  *
0011  * Reference manual for the twl6030 is available at:
0012  * https://www.ti.com/lit/ds/symlink/twl6030.pdf
0013  *
0014  * Limitations:
0015  * - The twl6030 hardware only supports two period lengths (128 clock ticks and
0016  *   64 clock ticks), the driver only uses 128 ticks
0017  * - The hardware doesn't support ON = 0, so the active part of a period doesn't
0018  *   start at its beginning.
0019  * - The hardware could support inverted polarity (with a similar limitation as
0020  *   for normal: the last clock tick is always inactive).
0021  * - The hardware emits a constant low output when disabled.
0022  * - A request for .duty_cycle = 0 results in an output wave with one active
0023  *   clock tick per period. This should better use the disabled state.
0024  * - The driver only implements setting the relative duty cycle.
0025  * - The driver doesn't implement .get_state().
0026  */
0027 
0028 #include <linux/module.h>
0029 #include <linux/of.h>
0030 #include <linux/platform_device.h>
0031 #include <linux/pwm.h>
0032 #include <linux/mfd/twl.h>
0033 #include <linux/slab.h>
0034 
0035 /*
0036  * This driver handles the PWM driven LED terminals of TWL4030 and TWL6030.
0037  * To generate the signal on TWL4030:
0038  *  - LEDA uses PWMA
0039  *  - LEDB uses PWMB
0040  * TWL6030 has one LED pin with dedicated LEDPWM
0041  */
0042 
0043 #define TWL4030_LED_MAX     0x7f
0044 #define TWL6030_LED_MAX     0xff
0045 
0046 /* Registers, bits and macro for TWL4030 */
0047 #define TWL4030_LEDEN_REG   0x00
0048 #define TWL4030_PWMA_REG    0x01
0049 
0050 #define TWL4030_LEDXON      (1 << 0)
0051 #define TWL4030_LEDXPWM     (1 << 4)
0052 #define TWL4030_LED_PINS    (TWL4030_LEDXON | TWL4030_LEDXPWM)
0053 #define TWL4030_LED_TOGGLE(led, x)  ((x) << (led))
0054 
0055 /* Register, bits and macro for TWL6030 */
0056 #define TWL6030_LED_PWM_CTRL1   0xf4
0057 #define TWL6030_LED_PWM_CTRL2   0xf5
0058 
0059 #define TWL6040_LED_MODE_HW 0x00
0060 #define TWL6040_LED_MODE_ON 0x01
0061 #define TWL6040_LED_MODE_OFF    0x02
0062 #define TWL6040_LED_MODE_MASK   0x03
0063 
0064 struct twl_pwmled_chip {
0065     struct pwm_chip chip;
0066     struct mutex mutex;
0067 };
0068 
0069 static inline struct twl_pwmled_chip *to_twl(struct pwm_chip *chip)
0070 {
0071     return container_of(chip, struct twl_pwmled_chip, chip);
0072 }
0073 
0074 static int twl4030_pwmled_config(struct pwm_chip *chip, struct pwm_device *pwm,
0075                   int duty_ns, int period_ns)
0076 {
0077     int duty_cycle = DIV_ROUND_UP(duty_ns * TWL4030_LED_MAX, period_ns) + 1;
0078     u8 pwm_config[2] = { 1, 0 };
0079     int base, ret;
0080 
0081     /*
0082      * To configure the duty period:
0083      * On-cycle is set to 1 (the minimum allowed value)
0084      * The off time of 0 is not configurable, so the mapping is:
0085      * 0 -> off cycle = 2,
0086      * 1 -> off cycle = 2,
0087      * 2 -> off cycle = 3,
0088      * 126 - > off cycle 127,
0089      * 127 - > off cycle 1
0090      * When on cycle == off cycle the PWM will be always on
0091      */
0092     if (duty_cycle == 1)
0093         duty_cycle = 2;
0094     else if (duty_cycle > TWL4030_LED_MAX)
0095         duty_cycle = 1;
0096 
0097     base = pwm->hwpwm * 2 + TWL4030_PWMA_REG;
0098 
0099     pwm_config[1] = duty_cycle;
0100 
0101     ret = twl_i2c_write(TWL4030_MODULE_LED, pwm_config, base, 2);
0102     if (ret < 0)
0103         dev_err(chip->dev, "%s: Failed to configure PWM\n", pwm->label);
0104 
0105     return ret;
0106 }
0107 
0108 static int twl4030_pwmled_enable(struct pwm_chip *chip, struct pwm_device *pwm)
0109 {
0110     struct twl_pwmled_chip *twl = to_twl(chip);
0111     int ret;
0112     u8 val;
0113 
0114     mutex_lock(&twl->mutex);
0115     ret = twl_i2c_read_u8(TWL4030_MODULE_LED, &val, TWL4030_LEDEN_REG);
0116     if (ret < 0) {
0117         dev_err(chip->dev, "%s: Failed to read LEDEN\n", pwm->label);
0118         goto out;
0119     }
0120 
0121     val |= TWL4030_LED_TOGGLE(pwm->hwpwm, TWL4030_LED_PINS);
0122 
0123     ret = twl_i2c_write_u8(TWL4030_MODULE_LED, val, TWL4030_LEDEN_REG);
0124     if (ret < 0)
0125         dev_err(chip->dev, "%s: Failed to enable PWM\n", pwm->label);
0126 
0127 out:
0128     mutex_unlock(&twl->mutex);
0129     return ret;
0130 }
0131 
0132 static void twl4030_pwmled_disable(struct pwm_chip *chip,
0133                    struct pwm_device *pwm)
0134 {
0135     struct twl_pwmled_chip *twl = to_twl(chip);
0136     int ret;
0137     u8 val;
0138 
0139     mutex_lock(&twl->mutex);
0140     ret = twl_i2c_read_u8(TWL4030_MODULE_LED, &val, TWL4030_LEDEN_REG);
0141     if (ret < 0) {
0142         dev_err(chip->dev, "%s: Failed to read LEDEN\n", pwm->label);
0143         goto out;
0144     }
0145 
0146     val &= ~TWL4030_LED_TOGGLE(pwm->hwpwm, TWL4030_LED_PINS);
0147 
0148     ret = twl_i2c_write_u8(TWL4030_MODULE_LED, val, TWL4030_LEDEN_REG);
0149     if (ret < 0)
0150         dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label);
0151 
0152 out:
0153     mutex_unlock(&twl->mutex);
0154 }
0155 
0156 static int twl4030_pwmled_apply(struct pwm_chip *chip, struct pwm_device *pwm,
0157                 const struct pwm_state *state)
0158 {
0159     int ret;
0160 
0161     if (state->polarity != PWM_POLARITY_NORMAL)
0162         return -EINVAL;
0163 
0164     if (!state->enabled) {
0165         if (pwm->state.enabled)
0166             twl4030_pwmled_disable(chip, pwm);
0167 
0168         return 0;
0169     }
0170 
0171     /*
0172      * We cannot skip calling ->config even if state->period ==
0173      * pwm->state.period && state->duty_cycle == pwm->state.duty_cycle
0174      * because we might have exited early in the last call to
0175      * pwm_apply_state because of !state->enabled and so the two values in
0176      * pwm->state might not be configured in hardware.
0177      */
0178     ret = twl4030_pwmled_config(pwm->chip, pwm,
0179                     state->duty_cycle, state->period);
0180     if (ret)
0181         return ret;
0182 
0183     if (!pwm->state.enabled)
0184         ret = twl4030_pwmled_enable(chip, pwm);
0185 
0186     return ret;
0187 }
0188 
0189 
0190 static const struct pwm_ops twl4030_pwmled_ops = {
0191     .apply = twl4030_pwmled_apply,
0192     .owner = THIS_MODULE,
0193 };
0194 
0195 static int twl6030_pwmled_config(struct pwm_chip *chip, struct pwm_device *pwm,
0196                   int duty_ns, int period_ns)
0197 {
0198     int duty_cycle = (duty_ns * TWL6030_LED_MAX) / period_ns;
0199     u8 on_time;
0200     int ret;
0201 
0202     on_time = duty_cycle & 0xff;
0203 
0204     ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, on_time,
0205                    TWL6030_LED_PWM_CTRL1);
0206     if (ret < 0)
0207         dev_err(chip->dev, "%s: Failed to configure PWM\n", pwm->label);
0208 
0209     return ret;
0210 }
0211 
0212 static int twl6030_pwmled_enable(struct pwm_chip *chip, struct pwm_device *pwm)
0213 {
0214     struct twl_pwmled_chip *twl = to_twl(chip);
0215     int ret;
0216     u8 val;
0217 
0218     mutex_lock(&twl->mutex);
0219     ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, TWL6030_LED_PWM_CTRL2);
0220     if (ret < 0) {
0221         dev_err(chip->dev, "%s: Failed to read PWM_CTRL2\n",
0222             pwm->label);
0223         goto out;
0224     }
0225 
0226     val &= ~TWL6040_LED_MODE_MASK;
0227     val |= TWL6040_LED_MODE_ON;
0228 
0229     ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_LED_PWM_CTRL2);
0230     if (ret < 0)
0231         dev_err(chip->dev, "%s: Failed to enable PWM\n", pwm->label);
0232 
0233 out:
0234     mutex_unlock(&twl->mutex);
0235     return ret;
0236 }
0237 
0238 static void twl6030_pwmled_disable(struct pwm_chip *chip,
0239                    struct pwm_device *pwm)
0240 {
0241     struct twl_pwmled_chip *twl = to_twl(chip);
0242     int ret;
0243     u8 val;
0244 
0245     mutex_lock(&twl->mutex);
0246     ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, TWL6030_LED_PWM_CTRL2);
0247     if (ret < 0) {
0248         dev_err(chip->dev, "%s: Failed to read PWM_CTRL2\n",
0249             pwm->label);
0250         goto out;
0251     }
0252 
0253     val &= ~TWL6040_LED_MODE_MASK;
0254     val |= TWL6040_LED_MODE_OFF;
0255 
0256     ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_LED_PWM_CTRL2);
0257     if (ret < 0)
0258         dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label);
0259 
0260 out:
0261     mutex_unlock(&twl->mutex);
0262 }
0263 
0264 static int twl6030_pwmled_apply(struct pwm_chip *chip, struct pwm_device *pwm,
0265                 const struct pwm_state *state)
0266 {
0267     int err;
0268 
0269     if (state->polarity != pwm->state.polarity)
0270         return -EINVAL;
0271 
0272     if (!state->enabled) {
0273         if (pwm->state.enabled)
0274             twl6030_pwmled_disable(chip, pwm);
0275 
0276         return 0;
0277     }
0278 
0279     err = twl6030_pwmled_config(pwm->chip, pwm,
0280                     state->duty_cycle, state->period);
0281     if (err)
0282         return err;
0283 
0284     if (!pwm->state.enabled)
0285         err = twl6030_pwmled_enable(chip, pwm);
0286 
0287     return err;
0288 }
0289 
0290 static int twl6030_pwmled_request(struct pwm_chip *chip, struct pwm_device *pwm)
0291 {
0292     struct twl_pwmled_chip *twl = to_twl(chip);
0293     int ret;
0294     u8 val;
0295 
0296     mutex_lock(&twl->mutex);
0297     ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, TWL6030_LED_PWM_CTRL2);
0298     if (ret < 0) {
0299         dev_err(chip->dev, "%s: Failed to read PWM_CTRL2\n",
0300             pwm->label);
0301         goto out;
0302     }
0303 
0304     val &= ~TWL6040_LED_MODE_MASK;
0305     val |= TWL6040_LED_MODE_OFF;
0306 
0307     ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_LED_PWM_CTRL2);
0308     if (ret < 0)
0309         dev_err(chip->dev, "%s: Failed to request PWM\n", pwm->label);
0310 
0311 out:
0312     mutex_unlock(&twl->mutex);
0313     return ret;
0314 }
0315 
0316 static void twl6030_pwmled_free(struct pwm_chip *chip, struct pwm_device *pwm)
0317 {
0318     struct twl_pwmled_chip *twl = to_twl(chip);
0319     int ret;
0320     u8 val;
0321 
0322     mutex_lock(&twl->mutex);
0323     ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, TWL6030_LED_PWM_CTRL2);
0324     if (ret < 0) {
0325         dev_err(chip->dev, "%s: Failed to read PWM_CTRL2\n",
0326             pwm->label);
0327         goto out;
0328     }
0329 
0330     val &= ~TWL6040_LED_MODE_MASK;
0331     val |= TWL6040_LED_MODE_HW;
0332 
0333     ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_LED_PWM_CTRL2);
0334     if (ret < 0)
0335         dev_err(chip->dev, "%s: Failed to free PWM\n", pwm->label);
0336 
0337 out:
0338     mutex_unlock(&twl->mutex);
0339 }
0340 
0341 static const struct pwm_ops twl6030_pwmled_ops = {
0342     .apply = twl6030_pwmled_apply,
0343     .request = twl6030_pwmled_request,
0344     .free = twl6030_pwmled_free,
0345     .owner = THIS_MODULE,
0346 };
0347 
0348 static int twl_pwmled_probe(struct platform_device *pdev)
0349 {
0350     struct twl_pwmled_chip *twl;
0351 
0352     twl = devm_kzalloc(&pdev->dev, sizeof(*twl), GFP_KERNEL);
0353     if (!twl)
0354         return -ENOMEM;
0355 
0356     if (twl_class_is_4030()) {
0357         twl->chip.ops = &twl4030_pwmled_ops;
0358         twl->chip.npwm = 2;
0359     } else {
0360         twl->chip.ops = &twl6030_pwmled_ops;
0361         twl->chip.npwm = 1;
0362     }
0363 
0364     twl->chip.dev = &pdev->dev;
0365 
0366     mutex_init(&twl->mutex);
0367 
0368     return devm_pwmchip_add(&pdev->dev, &twl->chip);
0369 }
0370 
0371 #ifdef CONFIG_OF
0372 static const struct of_device_id twl_pwmled_of_match[] = {
0373     { .compatible = "ti,twl4030-pwmled" },
0374     { .compatible = "ti,twl6030-pwmled" },
0375     { },
0376 };
0377 MODULE_DEVICE_TABLE(of, twl_pwmled_of_match);
0378 #endif
0379 
0380 static struct platform_driver twl_pwmled_driver = {
0381     .driver = {
0382         .name = "twl-pwmled",
0383         .of_match_table = of_match_ptr(twl_pwmled_of_match),
0384     },
0385     .probe = twl_pwmled_probe,
0386 };
0387 module_platform_driver(twl_pwmled_driver);
0388 
0389 MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
0390 MODULE_DESCRIPTION("PWM driver for TWL4030 and TWL6030 LED outputs");
0391 MODULE_ALIAS("platform:twl-pwmled");
0392 MODULE_LICENSE("GPL");