linux/drivers/pwm/pwm-twl.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Driver for TWL4030/6030 Generic Pulse Width Modulator
   4 *
   5 * Copyright (C) 2012 Texas Instruments
   6 * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
   7 */
   8
   9#include <linux/module.h>
  10#include <linux/of.h>
  11#include <linux/platform_device.h>
  12#include <linux/pwm.h>
  13#include <linux/mfd/twl.h>
  14#include <linux/slab.h>
  15
  16/*
  17 * This driver handles the PWMs of TWL4030 and TWL6030.
  18 * The TRM names for the PWMs on TWL4030 are: PWM0, PWM1
  19 * TWL6030 also have two PWMs named in the TRM as PWM1, PWM2
  20 */
  21
  22#define TWL_PWM_MAX             0x7f
  23
  24/* Registers, bits and macro for TWL4030 */
  25#define TWL4030_GPBR1_REG       0x0c
  26#define TWL4030_PMBR1_REG       0x0d
  27
  28/* GPBR1 register bits */
  29#define TWL4030_PWMXCLK_ENABLE  (1 << 0)
  30#define TWL4030_PWMX_ENABLE     (1 << 2)
  31#define TWL4030_PWMX_BITS       (TWL4030_PWMX_ENABLE | TWL4030_PWMXCLK_ENABLE)
  32#define TWL4030_PWM_TOGGLE(pwm, x)      ((x) << (pwm))
  33
  34/* PMBR1 register bits */
  35#define TWL4030_GPIO6_PWM0_MUTE_MASK            (0x03 << 2)
  36#define TWL4030_GPIO6_PWM0_MUTE_PWM0            (0x01 << 2)
  37#define TWL4030_GPIO7_VIBRASYNC_PWM1_MASK       (0x03 << 4)
  38#define TWL4030_GPIO7_VIBRASYNC_PWM1_PWM1       (0x03 << 4)
  39
  40/* Register, bits and macro for TWL6030 */
  41#define TWL6030_TOGGLE3_REG     0x92
  42
  43#define TWL6030_PWMXR           (1 << 0)
  44#define TWL6030_PWMXS           (1 << 1)
  45#define TWL6030_PWMXEN          (1 << 2)
  46#define TWL6030_PWM_TOGGLE(pwm, x)      ((x) << (pwm * 3))
  47
  48struct twl_pwm_chip {
  49        struct pwm_chip chip;
  50        struct mutex mutex;
  51        u8 twl6030_toggle3;
  52        u8 twl4030_pwm_mux;
  53};
  54
  55static inline struct twl_pwm_chip *to_twl(struct pwm_chip *chip)
  56{
  57        return container_of(chip, struct twl_pwm_chip, chip);
  58}
  59
  60static int twl_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
  61                              int duty_ns, int period_ns)
  62{
  63        int duty_cycle = DIV_ROUND_UP(duty_ns * TWL_PWM_MAX, period_ns) + 1;
  64        u8 pwm_config[2] = { 1, 0 };
  65        int base, ret;
  66
  67        /*
  68         * To configure the duty period:
  69         * On-cycle is set to 1 (the minimum allowed value)
  70         * The off time of 0 is not configurable, so the mapping is:
  71         * 0 -> off cycle = 2,
  72         * 1 -> off cycle = 2,
  73         * 2 -> off cycle = 3,
  74         * 126 - > off cycle 127,
  75         * 127 - > off cycle 1
  76         * When on cycle == off cycle the PWM will be always on
  77         */
  78        if (duty_cycle == 1)
  79                duty_cycle = 2;
  80        else if (duty_cycle > TWL_PWM_MAX)
  81                duty_cycle = 1;
  82
  83        base = pwm->hwpwm * 3;
  84
  85        pwm_config[1] = duty_cycle;
  86
  87        ret = twl_i2c_write(TWL_MODULE_PWM, pwm_config, base, 2);
  88        if (ret < 0)
  89                dev_err(chip->dev, "%s: Failed to configure PWM\n", pwm->label);
  90
  91        return ret;
  92}
  93
  94static int twl4030_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
  95{
  96        struct twl_pwm_chip *twl = to_twl(chip);
  97        int ret;
  98        u8 val;
  99
 100        mutex_lock(&twl->mutex);
 101        ret = twl_i2c_read_u8(TWL4030_MODULE_INTBR, &val, TWL4030_GPBR1_REG);
 102        if (ret < 0) {
 103                dev_err(chip->dev, "%s: Failed to read GPBR1\n", pwm->label);
 104                goto out;
 105        }
 106
 107        val |= TWL4030_PWM_TOGGLE(pwm->hwpwm, TWL4030_PWMXCLK_ENABLE);
 108
 109        ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, val, TWL4030_GPBR1_REG);
 110        if (ret < 0)
 111                dev_err(chip->dev, "%s: Failed to enable PWM\n", pwm->label);
 112
 113        val |= TWL4030_PWM_TOGGLE(pwm->hwpwm, TWL4030_PWMX_ENABLE);
 114
 115        ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, val, TWL4030_GPBR1_REG);
 116        if (ret < 0)
 117                dev_err(chip->dev, "%s: Failed to enable PWM\n", pwm->label);
 118
 119out:
 120        mutex_unlock(&twl->mutex);
 121        return ret;
 122}
 123
 124static void twl4030_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
 125{
 126        struct twl_pwm_chip *twl = to_twl(chip);
 127        int ret;
 128        u8 val;
 129
 130        mutex_lock(&twl->mutex);
 131        ret = twl_i2c_read_u8(TWL4030_MODULE_INTBR, &val, TWL4030_GPBR1_REG);
 132        if (ret < 0) {
 133                dev_err(chip->dev, "%s: Failed to read GPBR1\n", pwm->label);
 134                goto out;
 135        }
 136
 137        val &= ~TWL4030_PWM_TOGGLE(pwm->hwpwm, TWL4030_PWMX_ENABLE);
 138
 139        ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, val, TWL4030_GPBR1_REG);
 140        if (ret < 0)
 141                dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label);
 142
 143        val &= ~TWL4030_PWM_TOGGLE(pwm->hwpwm, TWL4030_PWMXCLK_ENABLE);
 144
 145        ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, val, TWL4030_GPBR1_REG);
 146        if (ret < 0)
 147                dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label);
 148
 149out:
 150        mutex_unlock(&twl->mutex);
 151}
 152
 153static int twl4030_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
 154{
 155        struct twl_pwm_chip *twl = to_twl(chip);
 156        int ret;
 157        u8 val, mask, bits;
 158
 159        if (pwm->hwpwm == 1) {
 160                mask = TWL4030_GPIO7_VIBRASYNC_PWM1_MASK;
 161                bits = TWL4030_GPIO7_VIBRASYNC_PWM1_PWM1;
 162        } else {
 163                mask = TWL4030_GPIO6_PWM0_MUTE_MASK;
 164                bits = TWL4030_GPIO6_PWM0_MUTE_PWM0;
 165        }
 166
 167        mutex_lock(&twl->mutex);
 168        ret = twl_i2c_read_u8(TWL4030_MODULE_INTBR, &val, TWL4030_PMBR1_REG);
 169        if (ret < 0) {
 170                dev_err(chip->dev, "%s: Failed to read PMBR1\n", pwm->label);
 171                goto out;
 172        }
 173
 174        /* Save the current MUX configuration for the PWM */
 175        twl->twl4030_pwm_mux &= ~mask;
 176        twl->twl4030_pwm_mux |= (val & mask);
 177
 178        /* Select PWM functionality */
 179        val &= ~mask;
 180        val |= bits;
 181
 182        ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, val, TWL4030_PMBR1_REG);
 183        if (ret < 0)
 184                dev_err(chip->dev, "%s: Failed to request PWM\n", pwm->label);
 185
 186out:
 187        mutex_unlock(&twl->mutex);
 188        return ret;
 189}
 190
 191static void twl4030_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
 192{
 193        struct twl_pwm_chip *twl = to_twl(chip);
 194        int ret;
 195        u8 val, mask;
 196
 197        if (pwm->hwpwm == 1)
 198                mask = TWL4030_GPIO7_VIBRASYNC_PWM1_MASK;
 199        else
 200                mask = TWL4030_GPIO6_PWM0_MUTE_MASK;
 201
 202        mutex_lock(&twl->mutex);
 203        ret = twl_i2c_read_u8(TWL4030_MODULE_INTBR, &val, TWL4030_PMBR1_REG);
 204        if (ret < 0) {
 205                dev_err(chip->dev, "%s: Failed to read PMBR1\n", pwm->label);
 206                goto out;
 207        }
 208
 209        /* Restore the MUX configuration for the PWM */
 210        val &= ~mask;
 211        val |= (twl->twl4030_pwm_mux & mask);
 212
 213        ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, val, TWL4030_PMBR1_REG);
 214        if (ret < 0)
 215                dev_err(chip->dev, "%s: Failed to free PWM\n", pwm->label);
 216
 217out:
 218        mutex_unlock(&twl->mutex);
 219}
 220
 221static int twl6030_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
 222{
 223        struct twl_pwm_chip *twl = to_twl(chip);
 224        int ret;
 225        u8 val;
 226
 227        mutex_lock(&twl->mutex);
 228        val = twl->twl6030_toggle3;
 229        val |= TWL6030_PWM_TOGGLE(pwm->hwpwm, TWL6030_PWMXS | TWL6030_PWMXEN);
 230        val &= ~TWL6030_PWM_TOGGLE(pwm->hwpwm, TWL6030_PWMXR);
 231
 232        ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_TOGGLE3_REG);
 233        if (ret < 0) {
 234                dev_err(chip->dev, "%s: Failed to enable PWM\n", pwm->label);
 235                goto out;
 236        }
 237
 238        twl->twl6030_toggle3 = val;
 239out:
 240        mutex_unlock(&twl->mutex);
 241        return ret;
 242}
 243
 244static void twl6030_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
 245{
 246        struct twl_pwm_chip *twl = to_twl(chip);
 247        int ret;
 248        u8 val;
 249
 250        mutex_lock(&twl->mutex);
 251        val = twl->twl6030_toggle3;
 252        val |= TWL6030_PWM_TOGGLE(pwm->hwpwm, TWL6030_PWMXR);
 253        val &= ~TWL6030_PWM_TOGGLE(pwm->hwpwm, TWL6030_PWMXS | TWL6030_PWMXEN);
 254
 255        ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_TOGGLE3_REG);
 256        if (ret < 0) {
 257                dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label);
 258                goto out;
 259        }
 260
 261        val |= TWL6030_PWM_TOGGLE(pwm->hwpwm, TWL6030_PWMXEN);
 262
 263        ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_TOGGLE3_REG);
 264        if (ret < 0) {
 265                dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label);
 266                goto out;
 267        }
 268
 269        val &= ~TWL6030_PWM_TOGGLE(pwm->hwpwm, TWL6030_PWMXEN);
 270
 271        ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_TOGGLE3_REG);
 272        if (ret < 0) {
 273                dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label);
 274                goto out;
 275        }
 276
 277        twl->twl6030_toggle3 = val;
 278out:
 279        mutex_unlock(&twl->mutex);
 280}
 281
 282static const struct pwm_ops twl4030_pwm_ops = {
 283        .config = twl_pwm_config,
 284        .enable = twl4030_pwm_enable,
 285        .disable = twl4030_pwm_disable,
 286        .request = twl4030_pwm_request,
 287        .free = twl4030_pwm_free,
 288        .owner = THIS_MODULE,
 289};
 290
 291static const struct pwm_ops twl6030_pwm_ops = {
 292        .config = twl_pwm_config,
 293        .enable = twl6030_pwm_enable,
 294        .disable = twl6030_pwm_disable,
 295        .owner = THIS_MODULE,
 296};
 297
 298static int twl_pwm_probe(struct platform_device *pdev)
 299{
 300        struct twl_pwm_chip *twl;
 301
 302        twl = devm_kzalloc(&pdev->dev, sizeof(*twl), GFP_KERNEL);
 303        if (!twl)
 304                return -ENOMEM;
 305
 306        if (twl_class_is_4030())
 307                twl->chip.ops = &twl4030_pwm_ops;
 308        else
 309                twl->chip.ops = &twl6030_pwm_ops;
 310
 311        twl->chip.dev = &pdev->dev;
 312        twl->chip.npwm = 2;
 313
 314        mutex_init(&twl->mutex);
 315
 316        return devm_pwmchip_add(&pdev->dev, &twl->chip);
 317}
 318
 319#ifdef CONFIG_OF
 320static const struct of_device_id twl_pwm_of_match[] = {
 321        { .compatible = "ti,twl4030-pwm" },
 322        { .compatible = "ti,twl6030-pwm" },
 323        { },
 324};
 325MODULE_DEVICE_TABLE(of, twl_pwm_of_match);
 326#endif
 327
 328static struct platform_driver twl_pwm_driver = {
 329        .driver = {
 330                .name = "twl-pwm",
 331                .of_match_table = of_match_ptr(twl_pwm_of_match),
 332        },
 333        .probe = twl_pwm_probe,
 334};
 335module_platform_driver(twl_pwm_driver);
 336
 337MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
 338MODULE_DESCRIPTION("PWM driver for TWL4030 and TWL6030");
 339MODULE_ALIAS("platform:twl-pwm");
 340MODULE_LICENSE("GPL");
 341