Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Driver for TWL4030/6030 Generic Pulse Width Modulator
0004  *
0005  * Copyright (C) 2012 Texas Instruments
0006  * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
0007  */
0008 
0009 #include <linux/module.h>
0010 #include <linux/of.h>
0011 #include <linux/platform_device.h>
0012 #include <linux/pwm.h>
0013 #include <linux/mfd/twl.h>
0014 #include <linux/slab.h>
0015 
0016 /*
0017  * This driver handles the PWMs of TWL4030 and TWL6030.
0018  * The TRM names for the PWMs on TWL4030 are: PWM0, PWM1
0019  * TWL6030 also have two PWMs named in the TRM as PWM1, PWM2
0020  */
0021 
0022 #define TWL_PWM_MAX     0x7f
0023 
0024 /* Registers, bits and macro for TWL4030 */
0025 #define TWL4030_GPBR1_REG   0x0c
0026 #define TWL4030_PMBR1_REG   0x0d
0027 
0028 /* GPBR1 register bits */
0029 #define TWL4030_PWMXCLK_ENABLE  (1 << 0)
0030 #define TWL4030_PWMX_ENABLE (1 << 2)
0031 #define TWL4030_PWMX_BITS   (TWL4030_PWMX_ENABLE | TWL4030_PWMXCLK_ENABLE)
0032 #define TWL4030_PWM_TOGGLE(pwm, x)  ((x) << (pwm))
0033 
0034 /* PMBR1 register bits */
0035 #define TWL4030_GPIO6_PWM0_MUTE_MASK        (0x03 << 2)
0036 #define TWL4030_GPIO6_PWM0_MUTE_PWM0        (0x01 << 2)
0037 #define TWL4030_GPIO7_VIBRASYNC_PWM1_MASK   (0x03 << 4)
0038 #define TWL4030_GPIO7_VIBRASYNC_PWM1_PWM1   (0x03 << 4)
0039 
0040 /* Register, bits and macro for TWL6030 */
0041 #define TWL6030_TOGGLE3_REG 0x92
0042 
0043 #define TWL6030_PWMXR       (1 << 0)
0044 #define TWL6030_PWMXS       (1 << 1)
0045 #define TWL6030_PWMXEN      (1 << 2)
0046 #define TWL6030_PWM_TOGGLE(pwm, x)  ((x) << (pwm * 3))
0047 
0048 struct twl_pwm_chip {
0049     struct pwm_chip chip;
0050     struct mutex mutex;
0051     u8 twl6030_toggle3;
0052     u8 twl4030_pwm_mux;
0053 };
0054 
0055 static inline struct twl_pwm_chip *to_twl(struct pwm_chip *chip)
0056 {
0057     return container_of(chip, struct twl_pwm_chip, chip);
0058 }
0059 
0060 static int twl_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
0061               u64 duty_ns, u64 period_ns)
0062 {
0063     int duty_cycle = DIV64_U64_ROUND_UP(duty_ns * TWL_PWM_MAX, period_ns) + 1;
0064     u8 pwm_config[2] = { 1, 0 };
0065     int base, ret;
0066 
0067     /*
0068      * To configure the duty period:
0069      * On-cycle is set to 1 (the minimum allowed value)
0070      * The off time of 0 is not configurable, so the mapping is:
0071      * 0 -> off cycle = 2,
0072      * 1 -> off cycle = 2,
0073      * 2 -> off cycle = 3,
0074      * 126 - > off cycle 127,
0075      * 127 - > off cycle 1
0076      * When on cycle == off cycle the PWM will be always on
0077      */
0078     if (duty_cycle == 1)
0079         duty_cycle = 2;
0080     else if (duty_cycle > TWL_PWM_MAX)
0081         duty_cycle = 1;
0082 
0083     base = pwm->hwpwm * 3;
0084 
0085     pwm_config[1] = duty_cycle;
0086 
0087     ret = twl_i2c_write(TWL_MODULE_PWM, pwm_config, base, 2);
0088     if (ret < 0)
0089         dev_err(chip->dev, "%s: Failed to configure PWM\n", pwm->label);
0090 
0091     return ret;
0092 }
0093 
0094 static int twl4030_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
0095 {
0096     struct twl_pwm_chip *twl = to_twl(chip);
0097     int ret;
0098     u8 val;
0099 
0100     mutex_lock(&twl->mutex);
0101     ret = twl_i2c_read_u8(TWL4030_MODULE_INTBR, &val, TWL4030_GPBR1_REG);
0102     if (ret < 0) {
0103         dev_err(chip->dev, "%s: Failed to read GPBR1\n", pwm->label);
0104         goto out;
0105     }
0106 
0107     val |= TWL4030_PWM_TOGGLE(pwm->hwpwm, TWL4030_PWMXCLK_ENABLE);
0108 
0109     ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, val, TWL4030_GPBR1_REG);
0110     if (ret < 0)
0111         dev_err(chip->dev, "%s: Failed to enable PWM\n", pwm->label);
0112 
0113     val |= TWL4030_PWM_TOGGLE(pwm->hwpwm, TWL4030_PWMX_ENABLE);
0114 
0115     ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, val, TWL4030_GPBR1_REG);
0116     if (ret < 0)
0117         dev_err(chip->dev, "%s: Failed to enable PWM\n", pwm->label);
0118 
0119 out:
0120     mutex_unlock(&twl->mutex);
0121     return ret;
0122 }
0123 
0124 static void twl4030_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
0125 {
0126     struct twl_pwm_chip *twl = to_twl(chip);
0127     int ret;
0128     u8 val;
0129 
0130     mutex_lock(&twl->mutex);
0131     ret = twl_i2c_read_u8(TWL4030_MODULE_INTBR, &val, TWL4030_GPBR1_REG);
0132     if (ret < 0) {
0133         dev_err(chip->dev, "%s: Failed to read GPBR1\n", pwm->label);
0134         goto out;
0135     }
0136 
0137     val &= ~TWL4030_PWM_TOGGLE(pwm->hwpwm, TWL4030_PWMX_ENABLE);
0138 
0139     ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, val, TWL4030_GPBR1_REG);
0140     if (ret < 0)
0141         dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label);
0142 
0143     val &= ~TWL4030_PWM_TOGGLE(pwm->hwpwm, TWL4030_PWMXCLK_ENABLE);
0144 
0145     ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, val, TWL4030_GPBR1_REG);
0146     if (ret < 0)
0147         dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label);
0148 
0149 out:
0150     mutex_unlock(&twl->mutex);
0151 }
0152 
0153 static int twl4030_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
0154 {
0155     struct twl_pwm_chip *twl = to_twl(chip);
0156     int ret;
0157     u8 val, mask, bits;
0158 
0159     if (pwm->hwpwm == 1) {
0160         mask = TWL4030_GPIO7_VIBRASYNC_PWM1_MASK;
0161         bits = TWL4030_GPIO7_VIBRASYNC_PWM1_PWM1;
0162     } else {
0163         mask = TWL4030_GPIO6_PWM0_MUTE_MASK;
0164         bits = TWL4030_GPIO6_PWM0_MUTE_PWM0;
0165     }
0166 
0167     mutex_lock(&twl->mutex);
0168     ret = twl_i2c_read_u8(TWL4030_MODULE_INTBR, &val, TWL4030_PMBR1_REG);
0169     if (ret < 0) {
0170         dev_err(chip->dev, "%s: Failed to read PMBR1\n", pwm->label);
0171         goto out;
0172     }
0173 
0174     /* Save the current MUX configuration for the PWM */
0175     twl->twl4030_pwm_mux &= ~mask;
0176     twl->twl4030_pwm_mux |= (val & mask);
0177 
0178     /* Select PWM functionality */
0179     val &= ~mask;
0180     val |= bits;
0181 
0182     ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, val, TWL4030_PMBR1_REG);
0183     if (ret < 0)
0184         dev_err(chip->dev, "%s: Failed to request PWM\n", pwm->label);
0185 
0186 out:
0187     mutex_unlock(&twl->mutex);
0188     return ret;
0189 }
0190 
0191 static void twl4030_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
0192 {
0193     struct twl_pwm_chip *twl = to_twl(chip);
0194     int ret;
0195     u8 val, mask;
0196 
0197     if (pwm->hwpwm == 1)
0198         mask = TWL4030_GPIO7_VIBRASYNC_PWM1_MASK;
0199     else
0200         mask = TWL4030_GPIO6_PWM0_MUTE_MASK;
0201 
0202     mutex_lock(&twl->mutex);
0203     ret = twl_i2c_read_u8(TWL4030_MODULE_INTBR, &val, TWL4030_PMBR1_REG);
0204     if (ret < 0) {
0205         dev_err(chip->dev, "%s: Failed to read PMBR1\n", pwm->label);
0206         goto out;
0207     }
0208 
0209     /* Restore the MUX configuration for the PWM */
0210     val &= ~mask;
0211     val |= (twl->twl4030_pwm_mux & mask);
0212 
0213     ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, val, TWL4030_PMBR1_REG);
0214     if (ret < 0)
0215         dev_err(chip->dev, "%s: Failed to free PWM\n", pwm->label);
0216 
0217 out:
0218     mutex_unlock(&twl->mutex);
0219 }
0220 
0221 static int twl6030_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
0222 {
0223     struct twl_pwm_chip *twl = to_twl(chip);
0224     int ret;
0225     u8 val;
0226 
0227     mutex_lock(&twl->mutex);
0228     val = twl->twl6030_toggle3;
0229     val |= TWL6030_PWM_TOGGLE(pwm->hwpwm, TWL6030_PWMXS | TWL6030_PWMXEN);
0230     val &= ~TWL6030_PWM_TOGGLE(pwm->hwpwm, TWL6030_PWMXR);
0231 
0232     ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_TOGGLE3_REG);
0233     if (ret < 0) {
0234         dev_err(chip->dev, "%s: Failed to enable PWM\n", pwm->label);
0235         goto out;
0236     }
0237 
0238     twl->twl6030_toggle3 = val;
0239 out:
0240     mutex_unlock(&twl->mutex);
0241     return ret;
0242 }
0243 
0244 static void twl6030_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
0245 {
0246     struct twl_pwm_chip *twl = to_twl(chip);
0247     int ret;
0248     u8 val;
0249 
0250     mutex_lock(&twl->mutex);
0251     val = twl->twl6030_toggle3;
0252     val |= TWL6030_PWM_TOGGLE(pwm->hwpwm, TWL6030_PWMXR);
0253     val &= ~TWL6030_PWM_TOGGLE(pwm->hwpwm, TWL6030_PWMXS | TWL6030_PWMXEN);
0254 
0255     ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_TOGGLE3_REG);
0256     if (ret < 0) {
0257         dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label);
0258         goto out;
0259     }
0260 
0261     val |= TWL6030_PWM_TOGGLE(pwm->hwpwm, TWL6030_PWMXEN);
0262 
0263     ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_TOGGLE3_REG);
0264     if (ret < 0) {
0265         dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label);
0266         goto out;
0267     }
0268 
0269     val &= ~TWL6030_PWM_TOGGLE(pwm->hwpwm, TWL6030_PWMXEN);
0270 
0271     ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_TOGGLE3_REG);
0272     if (ret < 0) {
0273         dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label);
0274         goto out;
0275     }
0276 
0277     twl->twl6030_toggle3 = val;
0278 out:
0279     mutex_unlock(&twl->mutex);
0280 }
0281 
0282 static int twl4030_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
0283                  const struct pwm_state *state)
0284 {
0285     int err;
0286 
0287     if (state->polarity != PWM_POLARITY_NORMAL)
0288         return -EINVAL;
0289 
0290     if (!state->enabled) {
0291         if (pwm->state.enabled)
0292             twl4030_pwm_disable(chip, pwm);
0293 
0294         return 0;
0295     }
0296 
0297     err = twl_pwm_config(pwm->chip, pwm, state->duty_cycle, state->period);
0298     if (err)
0299         return err;
0300 
0301     if (!pwm->state.enabled)
0302         err = twl4030_pwm_enable(chip, pwm);
0303 
0304     return err;
0305 }
0306 
0307 static int twl6030_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
0308                  const struct pwm_state *state)
0309 {
0310     int err;
0311 
0312     if (state->polarity != PWM_POLARITY_NORMAL)
0313         return -EINVAL;
0314 
0315     if (!state->enabled) {
0316         if (pwm->state.enabled)
0317             twl6030_pwm_disable(chip, pwm);
0318 
0319         return 0;
0320     }
0321 
0322     err = twl_pwm_config(pwm->chip, pwm, state->duty_cycle, state->period);
0323     if (err)
0324         return err;
0325 
0326     if (!pwm->state.enabled)
0327         err = twl6030_pwm_enable(chip, pwm);
0328 
0329     return err;
0330 }
0331 
0332 static const struct pwm_ops twl4030_pwm_ops = {
0333     .apply = twl4030_pwm_apply,
0334     .request = twl4030_pwm_request,
0335     .free = twl4030_pwm_free,
0336     .owner = THIS_MODULE,
0337 };
0338 
0339 static const struct pwm_ops twl6030_pwm_ops = {
0340     .apply = twl6030_pwm_apply,
0341     .owner = THIS_MODULE,
0342 };
0343 
0344 static int twl_pwm_probe(struct platform_device *pdev)
0345 {
0346     struct twl_pwm_chip *twl;
0347 
0348     twl = devm_kzalloc(&pdev->dev, sizeof(*twl), GFP_KERNEL);
0349     if (!twl)
0350         return -ENOMEM;
0351 
0352     if (twl_class_is_4030())
0353         twl->chip.ops = &twl4030_pwm_ops;
0354     else
0355         twl->chip.ops = &twl6030_pwm_ops;
0356 
0357     twl->chip.dev = &pdev->dev;
0358     twl->chip.npwm = 2;
0359 
0360     mutex_init(&twl->mutex);
0361 
0362     return devm_pwmchip_add(&pdev->dev, &twl->chip);
0363 }
0364 
0365 #ifdef CONFIG_OF
0366 static const struct of_device_id twl_pwm_of_match[] = {
0367     { .compatible = "ti,twl4030-pwm" },
0368     { .compatible = "ti,twl6030-pwm" },
0369     { },
0370 };
0371 MODULE_DEVICE_TABLE(of, twl_pwm_of_match);
0372 #endif
0373 
0374 static struct platform_driver twl_pwm_driver = {
0375     .driver = {
0376         .name = "twl-pwm",
0377         .of_match_table = of_match_ptr(twl_pwm_of_match),
0378     },
0379     .probe = twl_pwm_probe,
0380 };
0381 module_platform_driver(twl_pwm_driver);
0382 
0383 MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
0384 MODULE_DESCRIPTION("PWM driver for TWL4030 and TWL6030");
0385 MODULE_ALIAS("platform:twl-pwm");
0386 MODULE_LICENSE("GPL");