diff options
Diffstat (limited to 'drivers/pwm')
-rw-r--r-- | drivers/pwm/Kconfig | 10 | ||||
-rw-r--r-- | drivers/pwm/Makefile | 1 | ||||
-rw-r--r-- | drivers/pwm/core.c | 17 | ||||
-rw-r--r-- | drivers/pwm/pwm-bcm2835.c | 10 | ||||
-rw-r--r-- | drivers/pwm/pwm-crc.c | 128 | ||||
-rw-r--r-- | drivers/pwm/pwm-img.c | 3 | ||||
-rw-r--r-- | drivers/pwm/pwm-jz4740.c | 9 | ||||
-rw-r--r-- | drivers/pwm/pwm-lpss-platform.c | 1 | ||||
-rw-r--r-- | drivers/pwm/pwm-lpss.c | 85 | ||||
-rw-r--r-- | drivers/pwm/pwm-lpss.h | 3 | ||||
-rw-r--r-- | drivers/pwm/pwm-pca9685.c | 45 | ||||
-rw-r--r-- | drivers/pwm/pwm-rockchip.c | 15 | ||||
-rw-r--r-- | drivers/pwm/pwm-sifive.c | 8 | ||||
-rw-r--r-- | drivers/pwm/pwm-sl28cpld.c | 270 | ||||
-rw-r--r-- | drivers/pwm/pwm-sprd.c | 7 | ||||
-rw-r--r-- | drivers/pwm/pwm-sun4i.c | 36 | ||||
-rw-r--r-- | drivers/pwm/sysfs.c | 4 |
17 files changed, 473 insertions, 179 deletions
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 7dbcf6973d33..78ddc127e45e 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -428,6 +428,16 @@ config PWM_SIFIVE To compile this driver as a module, choose M here: the module will be called pwm-sifive. +config PWM_SL28CPLD + tristate "Kontron sl28cpld PWM support" + depends on MFD_SL28CPLD || COMPILE_TEST + help + Generic PWM framework driver for board management controller + found on the Kontron sl28 CPLD. + + To compile this driver as a module, choose M here: the module + will be called pwm-sl28cpld. + config PWM_SPEAR tristate "STMicroelectronics SPEAr PWM support" depends on PLAT_SPEAR || COMPILE_TEST diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index 2c2ba0a03557..cbdcd55d69ee 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -40,6 +40,7 @@ obj-$(CONFIG_PWM_RENESAS_TPU) += pwm-renesas-tpu.o obj-$(CONFIG_PWM_ROCKCHIP) += pwm-rockchip.o obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o obj-$(CONFIG_PWM_SIFIVE) += pwm-sifive.o +obj-$(CONFIG_PWM_SL28CPLD) += pwm-sl28cpld.o obj-$(CONFIG_PWM_SPEAR) += pwm-spear.o obj-$(CONFIG_PWM_SPRD) += pwm-sprd.o obj-$(CONFIG_PWM_STI) += pwm-sti.o diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index 276e939a5684..1f16f5365d3c 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -1327,30 +1327,19 @@ static int pwm_seq_show(struct seq_file *s, void *v) return 0; } -static const struct seq_operations pwm_seq_ops = { +static const struct seq_operations pwm_debugfs_sops = { .start = pwm_seq_start, .next = pwm_seq_next, .stop = pwm_seq_stop, .show = pwm_seq_show, }; -static int pwm_seq_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &pwm_seq_ops); -} - -static const struct file_operations pwm_debugfs_ops = { - .owner = THIS_MODULE, - .open = pwm_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; +DEFINE_SEQ_ATTRIBUTE(pwm_debugfs); static int __init pwm_debugfs_init(void) { debugfs_create_file("pwm", S_IFREG | S_IRUGO, NULL, NULL, - &pwm_debugfs_ops); + &pwm_debugfs_fops); return 0; } diff --git a/drivers/pwm/pwm-bcm2835.c b/drivers/pwm/pwm-bcm2835.c index d78f86f8e462..6841dcfe27fc 100644 --- a/drivers/pwm/pwm-bcm2835.c +++ b/drivers/pwm/pwm-bcm2835.c @@ -152,13 +152,9 @@ static int bcm2835_pwm_probe(struct platform_device *pdev) return PTR_ERR(pc->base); pc->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(pc->clk)) { - ret = PTR_ERR(pc->clk); - if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, "clock not found: %d\n", ret); - - return ret; - } + if (IS_ERR(pc->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(pc->clk), + "clock not found\n"); ret = clk_prepare_enable(pc->clk); if (ret) diff --git a/drivers/pwm/pwm-crc.c b/drivers/pwm/pwm-crc.c index 272eeb071147..ecfdfac0c2d9 100644 --- a/drivers/pwm/pwm-crc.c +++ b/drivers/pwm/pwm-crc.c @@ -21,8 +21,8 @@ #define PWM_MAX_LEVEL 0xFF -#define PWM_BASE_CLK 6000000 /* 6 MHz */ -#define PWM_MAX_PERIOD_NS 21333 /* 46.875KHz */ +#define PWM_BASE_CLK_MHZ 6 /* 6 MHz */ +#define PWM_MAX_PERIOD_NS 5461334 /* 183 Hz */ /** * struct crystalcove_pwm - Crystal Cove PWM controller @@ -39,59 +39,121 @@ static inline struct crystalcove_pwm *to_crc_pwm(struct pwm_chip *pc) return container_of(pc, struct crystalcove_pwm, chip); } -static int crc_pwm_enable(struct pwm_chip *c, struct pwm_device *pwm) +static int crc_pwm_calc_clk_div(int period_ns) { - struct crystalcove_pwm *crc_pwm = to_crc_pwm(c); + int clk_div; - regmap_write(crc_pwm->regmap, BACKLIGHT_EN, 1); + clk_div = PWM_BASE_CLK_MHZ * period_ns / (256 * NSEC_PER_USEC); + /* clk_div 1 - 128, maps to register values 0-127 */ + if (clk_div > 0) + clk_div--; - return 0; -} - -static void crc_pwm_disable(struct pwm_chip *c, struct pwm_device *pwm) -{ - struct crystalcove_pwm *crc_pwm = to_crc_pwm(c); - - regmap_write(crc_pwm->regmap, BACKLIGHT_EN, 0); + return clk_div; } -static int crc_pwm_config(struct pwm_chip *c, struct pwm_device *pwm, - int duty_ns, int period_ns) +static int crc_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + const struct pwm_state *state) { - struct crystalcove_pwm *crc_pwm = to_crc_pwm(c); + struct crystalcove_pwm *crc_pwm = to_crc_pwm(chip); struct device *dev = crc_pwm->chip.dev; - int level; + int err; - if (period_ns > PWM_MAX_PERIOD_NS) { + if (state->period > PWM_MAX_PERIOD_NS) { dev_err(dev, "un-supported period_ns\n"); return -EINVAL; } - if (pwm_get_period(pwm) != period_ns) { - int clk_div; + if (state->polarity != PWM_POLARITY_NORMAL) + return -EOPNOTSUPP; - /* changing the clk divisor, need to disable fisrt */ - crc_pwm_disable(c, pwm); - clk_div = PWM_BASE_CLK * period_ns / NSEC_PER_SEC; + if (pwm_is_enabled(pwm) && !state->enabled) { + err = regmap_write(crc_pwm->regmap, BACKLIGHT_EN, 0); + if (err) { + dev_err(dev, "Error writing BACKLIGHT_EN %d\n", err); + return err; + } + } - regmap_write(crc_pwm->regmap, PWM0_CLK_DIV, - clk_div | PWM_OUTPUT_ENABLE); + if (pwm_get_duty_cycle(pwm) != state->duty_cycle || + pwm_get_period(pwm) != state->period) { + u64 level = state->duty_cycle * PWM_MAX_LEVEL; + + do_div(level, state->period); + + err = regmap_write(crc_pwm->regmap, PWM0_DUTY_CYCLE, level); + if (err) { + dev_err(dev, "Error writing PWM0_DUTY_CYCLE %d\n", err); + return err; + } + } + + if (pwm_is_enabled(pwm) && state->enabled && + pwm_get_period(pwm) != state->period) { + /* changing the clk divisor, clear PWM_OUTPUT_ENABLE first */ + err = regmap_write(crc_pwm->regmap, PWM0_CLK_DIV, 0); + if (err) { + dev_err(dev, "Error writing PWM0_CLK_DIV %d\n", err); + return err; + } + } - /* enable back */ - crc_pwm_enable(c, pwm); + if (pwm_get_period(pwm) != state->period || + pwm_is_enabled(pwm) != state->enabled) { + int clk_div = crc_pwm_calc_clk_div(state->period); + int pwm_output_enable = state->enabled ? PWM_OUTPUT_ENABLE : 0; + + err = regmap_write(crc_pwm->regmap, PWM0_CLK_DIV, + clk_div | pwm_output_enable); + if (err) { + dev_err(dev, "Error writing PWM0_CLK_DIV %d\n", err); + return err; + } } - /* change the pwm duty cycle */ - level = duty_ns * PWM_MAX_LEVEL / period_ns; - regmap_write(crc_pwm->regmap, PWM0_DUTY_CYCLE, level); + if (!pwm_is_enabled(pwm) && state->enabled) { + err = regmap_write(crc_pwm->regmap, BACKLIGHT_EN, 1); + if (err) { + dev_err(dev, "Error writing BACKLIGHT_EN %d\n", err); + return err; + } + } return 0; } +static void crc_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) +{ + struct crystalcove_pwm *crc_pwm = to_crc_pwm(chip); + struct device *dev = crc_pwm->chip.dev; + unsigned int clk_div, clk_div_reg, duty_cycle_reg; + int error; + + error = regmap_read(crc_pwm->regmap, PWM0_CLK_DIV, &clk_div_reg); + if (error) { + dev_err(dev, "Error reading PWM0_CLK_DIV %d\n", error); + return; + } + + error = regmap_read(crc_pwm->regmap, PWM0_DUTY_CYCLE, &duty_cycle_reg); + if (error) { + dev_err(dev, "Error reading PWM0_DUTY_CYCLE %d\n", error); + return; + } + + clk_div = (clk_div_reg & ~PWM_OUTPUT_ENABLE) + 1; + + state->period = + DIV_ROUND_UP(clk_div * NSEC_PER_USEC * 256, PWM_BASE_CLK_MHZ); + state->duty_cycle = + DIV_ROUND_UP_ULL(duty_cycle_reg * state->period, PWM_MAX_LEVEL); + state->polarity = PWM_POLARITY_NORMAL; + state->enabled = !!(clk_div_reg & PWM_OUTPUT_ENABLE); +} + static const struct pwm_ops crc_pwm_ops = { - .config = crc_pwm_config, - .enable = crc_pwm_enable, - .disable = crc_pwm_disable, + .apply = crc_pwm_apply, + .get_state = crc_pwm_get_state, }; static int crystalcove_pwm_probe(struct platform_device *pdev) diff --git a/drivers/pwm/pwm-img.c b/drivers/pwm/pwm-img.c index 599a0f66a384..a34d95ed70b2 100644 --- a/drivers/pwm/pwm-img.c +++ b/drivers/pwm/pwm-img.c @@ -277,6 +277,8 @@ static int img_pwm_probe(struct platform_device *pdev) return PTR_ERR(pwm->pwm_clk); } + platform_set_drvdata(pdev, pwm); + pm_runtime_set_autosuspend_delay(&pdev->dev, IMG_PWM_PM_TIMEOUT); pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_enable(&pdev->dev); @@ -313,7 +315,6 @@ static int img_pwm_probe(struct platform_device *pdev) goto err_suspend; } - platform_set_drvdata(pdev, pwm); return 0; err_suspend: diff --git a/drivers/pwm/pwm-jz4740.c b/drivers/pwm/pwm-jz4740.c index 5830ac2bdf6a..00c642fa2eed 100644 --- a/drivers/pwm/pwm-jz4740.c +++ b/drivers/pwm/pwm-jz4740.c @@ -60,12 +60,9 @@ static int jz4740_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) snprintf(name, sizeof(name), "timer%u", pwm->hwpwm); clk = clk_get(chip->dev, name); - if (IS_ERR(clk)) { - if (PTR_ERR(clk) != -EPROBE_DEFER) - dev_err(chip->dev, "Failed to get clock: %pe", clk); - - return PTR_ERR(clk); - } + if (IS_ERR(clk)) + return dev_err_probe(chip->dev, PTR_ERR(clk), + "Failed to get clock\n"); err = clk_prepare_enable(clk); if (err < 0) { diff --git a/drivers/pwm/pwm-lpss-platform.c b/drivers/pwm/pwm-lpss-platform.c index 48f34d20aecd..c6502cf7a7af 100644 --- a/drivers/pwm/pwm-lpss-platform.c +++ b/drivers/pwm/pwm-lpss-platform.c @@ -89,7 +89,6 @@ static int pwm_lpss_prepare(struct device *dev) static const struct dev_pm_ops pwm_lpss_platform_pm_ops = { .prepare = pwm_lpss_prepare, - SET_SYSTEM_SLEEP_PM_OPS(pwm_lpss_suspend, pwm_lpss_resume) }; static const struct acpi_device_id pwm_lpss_acpi_match[] = { diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c index 9d965ffe66d1..3444c56b4bed 100644 --- a/drivers/pwm/pwm-lpss.c +++ b/drivers/pwm/pwm-lpss.c @@ -85,7 +85,7 @@ static void pwm_lpss_prepare(struct pwm_lpss_chip *lpwm, struct pwm_device *pwm, unsigned long long on_time_div; unsigned long c = lpwm->info->clk_rate, base_unit_range; unsigned long long base_unit, freq = NSEC_PER_SEC; - u32 orig_ctrl, ctrl; + u32 ctrl; do_div(freq, period_ns); @@ -93,26 +93,25 @@ static void pwm_lpss_prepare(struct pwm_lpss_chip *lpwm, struct pwm_device *pwm, * The equation is: * base_unit = round(base_unit_range * freq / c) */ - base_unit_range = BIT(lpwm->info->base_unit_bits) - 1; + base_unit_range = BIT(lpwm->info->base_unit_bits); freq *= base_unit_range; base_unit = DIV_ROUND_CLOSEST_ULL(freq, c); + /* base_unit must not be 0 and we also want to avoid overflowing it */ + base_unit = clamp_val(base_unit, 1, base_unit_range - 1); on_time_div = 255ULL * duty_ns; do_div(on_time_div, period_ns); on_time_div = 255ULL - on_time_div; - orig_ctrl = ctrl = pwm_lpss_read(pwm); + ctrl = pwm_lpss_read(pwm); ctrl &= ~PWM_ON_TIME_DIV_MASK; - ctrl &= ~(base_unit_range << PWM_BASE_UNIT_SHIFT); - base_unit &= base_unit_range; + ctrl &= ~((base_unit_range - 1) << PWM_BASE_UNIT_SHIFT); ctrl |= (u32) base_unit << PWM_BASE_UNIT_SHIFT; ctrl |= on_time_div; - if (orig_ctrl != ctrl) { - pwm_lpss_write(pwm, ctrl); - pwm_lpss_write(pwm, ctrl | PWM_SW_UPDATE); - } + pwm_lpss_write(pwm, ctrl); + pwm_lpss_write(pwm, ctrl | PWM_SW_UPDATE); } static inline void pwm_lpss_cond_enable(struct pwm_device *pwm, bool cond) @@ -121,41 +120,47 @@ static inline void pwm_lpss_cond_enable(struct pwm_device *pwm, bool cond) pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_ENABLE); } +static int pwm_lpss_prepare_enable(struct pwm_lpss_chip *lpwm, + struct pwm_device *pwm, + const struct pwm_state *state) +{ + int ret; + + ret = pwm_lpss_is_updating(pwm); + if (ret) + return ret; + + pwm_lpss_prepare(lpwm, pwm, state->duty_cycle, state->period); + pwm_lpss_cond_enable(pwm, lpwm->info->bypass == false); + ret = pwm_lpss_wait_for_update(pwm); + if (ret) + return ret; + + pwm_lpss_cond_enable(pwm, lpwm->info->bypass == true); + return 0; +} + static int pwm_lpss_apply(struct pwm_chip *chip, struct pwm_device *pwm, const struct pwm_state *state) { struct pwm_lpss_chip *lpwm = to_lpwm(chip); - int ret; + int ret = 0; if (state->enabled) { if (!pwm_is_enabled(pwm)) { pm_runtime_get_sync(chip->dev); - ret = pwm_lpss_is_updating(pwm); - if (ret) { - pm_runtime_put(chip->dev); - return ret; - } - pwm_lpss_prepare(lpwm, pwm, state->duty_cycle, state->period); - pwm_lpss_cond_enable(pwm, lpwm->info->bypass == false); - ret = pwm_lpss_wait_for_update(pwm); - if (ret) { + ret = pwm_lpss_prepare_enable(lpwm, pwm, state); + if (ret) pm_runtime_put(chip->dev); - return ret; - } - pwm_lpss_cond_enable(pwm, lpwm->info->bypass == true); } else { - ret = pwm_lpss_is_updating(pwm); - if (ret) - return ret; - pwm_lpss_prepare(lpwm, pwm, state->duty_cycle, state->period); - return pwm_lpss_wait_for_update(pwm); + ret = pwm_lpss_prepare_enable(lpwm, pwm, state); } } else if (pwm_is_enabled(pwm)) { pwm_lpss_write(pwm, pwm_lpss_read(pwm) & ~PWM_ENABLE); pm_runtime_put(chip->dev); } - return 0; + return ret; } static void pwm_lpss_get_state(struct pwm_chip *chip, struct pwm_device *pwm, @@ -255,30 +260,6 @@ int pwm_lpss_remove(struct pwm_lpss_chip *lpwm) } EXPORT_SYMBOL_GPL(pwm_lpss_remove); -int pwm_lpss_suspend(struct device *dev) -{ - struct pwm_lpss_chip *lpwm = dev_get_drvdata(dev); - int i; - - for (i = 0; i < lpwm->info->npwm; i++) - lpwm->saved_ctrl[i] = readl(lpwm->regs + i * PWM_SIZE + PWM); - - return 0; -} -EXPORT_SYMBOL_GPL(pwm_lpss_suspend); - -int pwm_lpss_resume(struct device *dev) -{ - struct pwm_lpss_chip *lpwm = dev_get_drvdata(dev); - int i; - - for (i = 0; i < lpwm->info->npwm; i++) - writel(lpwm->saved_ctrl[i], lpwm->regs + i * PWM_SIZE + PWM); - - return 0; -} -EXPORT_SYMBOL_GPL(pwm_lpss_resume); - MODULE_DESCRIPTION("PWM driver for Intel LPSS"); MODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/pwm/pwm-lpss.h b/drivers/pwm/pwm-lpss.h index 7909fa12fca2..70db7e389d66 100644 --- a/drivers/pwm/pwm-lpss.h +++ b/drivers/pwm/pwm-lpss.h @@ -19,7 +19,6 @@ struct pwm_lpss_chip { struct pwm_chip chip; void __iomem *regs; const struct pwm_lpss_boardinfo *info; - u32 saved_ctrl[MAX_PWMS]; }; struct pwm_lpss_boardinfo { @@ -37,7 +36,5 @@ struct pwm_lpss_boardinfo { struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, struct resource *r, const struct pwm_lpss_boardinfo *info); int pwm_lpss_remove(struct pwm_lpss_chip *lpwm); -int pwm_lpss_suspend(struct device *dev); -int pwm_lpss_resume(struct device *dev); #endif /* __PWM_LPSS_H */ diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c index 76cd22bd6614..4a55dc18656c 100644 --- a/drivers/pwm/pwm-pca9685.c +++ b/drivers/pwm/pwm-pca9685.c @@ -57,10 +57,14 @@ #define PCA9685_NUMREGS 0xFF #define PCA9685_MAXCHAN 0x10 -#define LED_FULL (1 << 4) -#define MODE1_SLEEP (1 << 4) -#define MODE2_INVRT (1 << 4) -#define MODE2_OUTDRV (1 << 2) +#define LED_FULL BIT(4) +#define MODE1_ALLCALL BIT(0) +#define MODE1_SUB3 BIT(1) +#define MODE1_SUB2 BIT(2) +#define MODE1_SUB1 BIT(3) +#define MODE1_SLEEP BIT(4) +#define MODE2_INVRT BIT(4) +#define MODE2_OUTDRV BIT(2) #define LED_N_ON_H(N) (PCA9685_LEDX_ON_H + (4 * (N))) #define LED_N_ON_L(N) (PCA9685_LEDX_ON_L + (4 * (N))) @@ -91,7 +95,7 @@ static bool pca9685_pwm_test_and_set_inuse(struct pca9685 *pca, int pwm_idx) mutex_lock(&pca->lock); if (pwm_idx >= PCA9685_MAXCHAN) { /* - * "all LEDs" channel: + * "All LEDs" channel: * pretend already in use if any of the PWMs are requested */ if (!bitmap_empty(pca->pwms_inuse, PCA9685_MAXCHAN)) { @@ -100,7 +104,7 @@ static bool pca9685_pwm_test_and_set_inuse(struct pca9685 *pca, int pwm_idx) } } else { /* - * regular channel: + * Regular channel: * pretend already in use if the "all LEDs" channel is requested */ if (test_bit(PCA9685_MAXCHAN, pca->pwms_inuse)) { @@ -257,7 +261,7 @@ static int pca9685_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, if (prescale >= PCA9685_PRESCALE_MIN && prescale <= PCA9685_PRESCALE_MAX) { /* - * putting the chip briefly into SLEEP mode + * Putting the chip briefly into SLEEP mode * at this point won't interfere with the * pm_runtime framework, because the pm_runtime * state is guaranteed active here. @@ -443,8 +447,8 @@ static int pca9685_pwm_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct pca9685 *pca; + unsigned int reg; int ret; - int mode2; pca = devm_kzalloc(&client->dev, sizeof(*pca), GFP_KERNEL); if (!pca) @@ -461,26 +465,31 @@ static int pca9685_pwm_probe(struct i2c_client *client, i2c_set_clientdata(client, pca); - regmap_read(pca->regmap, PCA9685_MODE2, &mode2); + regmap_read(pca->regmap, PCA9685_MODE2, ®); if (device_property_read_bool(&client->dev, "invert")) - mode2 |= MODE2_INVRT; + reg |= MODE2_INVRT; else - mode2 &= ~MODE2_INVRT; + reg &= ~MODE2_INVRT; if (device_property_read_bool(&client->dev, "open-drain")) - mode2 &= ~MODE2_OUTDRV; + reg &= ~MODE2_OUTDRV; else - mode2 |= MODE2_OUTDRV; + reg |= MODE2_OUTDRV; + + regmap_write(pca->regmap, PCA9685_MODE2, reg); - regmap_write(pca->regmap, PCA9685_MODE2, mode2); + /* Disable all LED ALLCALL and SUBx addresses to avoid bus collisions */ + regmap_read(pca->regmap, PCA9685_MODE1, ®); + reg &= ~(MODE1_ALLCALL | MODE1_SUB1 | MODE1_SUB2 | MODE1_SUB3); + regmap_write(pca->regmap, PCA9685_MODE1, reg); - /* clear all "full off" bits */ + /* Clear all "full off" bits */ regmap_write(pca->regmap, PCA9685_ALL_LED_OFF_L, 0); regmap_write(pca->regmap, PCA9685_ALL_LED_OFF_H, 0); pca->chip.ops = &pca9685_pwm_ops; - /* add an extra channel for ALL_LED */ + /* Add an extra channel for ALL_LED */ pca->chip.npwm = PCA9685_MAXCHAN + 1; pca->chip.dev = &client->dev; @@ -496,10 +505,10 @@ static int pca9685_pwm_probe(struct i2c_client *client, return ret; } - /* the chip comes out of power-up in the active state */ + /* The chip comes out of power-up in the active state */ pm_runtime_set_active(&client->dev); /* - * enable will put the chip into suspend, which is what we + * Enable will put the chip into suspend, which is what we * want as all outputs are disabled at this point */ pm_runtime_enable(&client->dev); diff --git a/drivers/pwm/pwm-rockchip.c b/drivers/pwm/pwm-rockchip.c index eb8c9cb645a6..77c23a2c6d71 100644 --- a/drivers/pwm/pwm-rockchip.c +++ b/drivers/pwm/pwm-rockchip.c @@ -288,6 +288,7 @@ static int rockchip_pwm_probe(struct platform_device *pdev) const struct of_device_id *id; struct rockchip_pwm_chip *pc; struct resource *r; + u32 enable_conf, ctrl; int ret, count; id = of_match_device(rockchip_pwm_dt_ids, &pdev->dev); @@ -306,13 +307,9 @@ static int rockchip_pwm_probe(struct platform_device *pdev) pc->clk = devm_clk_get(&pdev->dev, "pwm"); if (IS_ERR(pc->clk)) { pc->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(pc->clk)) { - ret = PTR_ERR(pc->clk); - if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, "Can't get bus clk: %d\n", - ret); - return ret; - } + if (IS_ERR(pc->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(pc->clk), + "Can't get bus clk\n"); } count = of_count_phandle_with_args(pdev->dev.of_node, @@ -362,7 +359,9 @@ static int rockchip_pwm_probe(struct platform_device *pdev) } /* Keep the PWM clk enabled if the PWM appears to be up and running. */ - if (!pwm_is_enabled(pc->chip.pwms)) + enable_conf = pc->data->enable_conf; + ctrl = readl_relaxed(pc->base + pc->data->regs.ctrl); + if ((ctrl & enable_conf) != enable_conf) clk_disable(pc->clk); return 0; diff --git a/drivers/pwm/pwm-sifive.c b/drivers/pwm/pwm-sifive.c index 62de0bb85921..2485fbaaead2 100644 --- a/drivers/pwm/pwm-sifive.c +++ b/drivers/pwm/pwm-sifive.c @@ -254,11 +254,9 @@ static int pwm_sifive_probe(struct platform_device *pdev) return PTR_ERR(ddata->regs); ddata->clk = devm_clk_get(dev, NULL); - if (IS_ERR(ddata->clk)) { - if (PTR_ERR(ddata->clk) != -EPROBE_DEFER) - dev_err(dev, "Unable to find controller clock\n"); - return PTR_ERR(ddata->clk); - } + if (IS_ERR(ddata->clk)) + return dev_err_probe(dev, PTR_ERR(ddata->clk), + "Unable to find controller clock\n"); ret = clk_prepare_enable(ddata->clk); if (ret) { diff --git a/drivers/pwm/pwm-sl28cpld.c b/drivers/pwm/pwm-sl28cpld.c new file mode 100644 index 000000000000..5046b6b7fd35 --- /dev/null +++ b/drivers/pwm/pwm-sl28cpld.c @@ -0,0 +1,270 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * sl28cpld PWM driver + * + * Copyright (c) 2020 Michael Walle <michael@walle.cc> + * + * There is no public datasheet available for this PWM core. But it is easy + * enough to be briefly explained. It consists of one 8-bit counter. The PWM + * supports four distinct frequencies by selecting when to reset the counter. + * With the prescaler setting you can select which bit of the counter is used + * to reset it. This implies that the higher the frequency the less remaining + * bits are available for the actual counter. + * + * Let cnt[7:0] be the counter, clocked at 32kHz: + * +-----------+--------+--------------+-----------+---------------+ + * | prescaler | reset | counter bits | frequency | period length | + * +-----------+--------+--------------+-----------+---------------+ + * | 0 | cnt[7] | cnt[6:0] | 250 Hz | 4000000 ns | + * | 1 | cnt[6] | cnt[5:0] | 500 Hz | 2000000 ns | + * | 2 | cnt[5] | cnt[4:0] | 1 kHz | 1000000 ns | + * | 3 | cnt[4] | cnt[3:0] | 2 kHz | 500000 ns | + * +-----------+--------+--------------+-----------+---------------+ + * + * Limitations: + * - The hardware cannot generate a 100% duty cycle if the prescaler is 0. + * - The hardware cannot atomically set the prescaler and the counter value, + * which might lead to glitches and inconsistent states if a write fails. + * - The counter is not reset if you switch the prescaler which leads + * to glitches, too. + * - The duty cycle will switch immediately and not after a complete cycle. + * - Depending on the actual implementation, disabling the PWM might have + * side effects. For example, if the output pin is shared with a GPIO pin + * it will automatically switch back to GPIO mode. + */ + +#include <linux/bitfield.h> +#include <linux/kernel.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/pwm.h> +#include <linux/regmap.h> + +/* + * PWM timer block registers. + */ +#define SL28CPLD_PWM_CTRL 0x00 +#define SL28CPLD_PWM_CTRL_ENABLE BIT(7) +#define SL28CPLD_PWM_CTRL_PRESCALER_MASK GENMASK(1, 0) +#define SL28CPLD_PWM_CYCLE 0x01 +#define SL28CPLD_PWM_CYCLE_MAX GENMASK(6, 0) + +#define SL28CPLD_PWM_CLK 32000 /* 32 kHz */ +#define SL28CPLD_PWM_MAX_DUTY_CYCLE(prescaler) (1 << (7 - (prescaler))) +#define SL28CPLD_PWM_PERIOD(prescaler) \ + (NSEC_PER_SEC / SL28CPLD_PWM_CLK * SL28CPLD_PWM_MAX_DUTY_CYCLE(prescaler)) + +/* + * We calculate the duty cycle like this: + * duty_cycle_ns = pwm_cycle_reg * max_period_ns / max_duty_cycle + * + * With + * max_period_ns = 1 << (7 - prescaler) / SL28CPLD_PWM_CLK * NSEC_PER_SEC + * max_duty_cycle = 1 << (7 - prescaler) + * this then simplifies to: + * duty_cycle_ns = pwm_cycle_reg / SL28CPLD_PWM_CLK * NSEC_PER_SEC + * = NSEC_PER_SEC / SL28CPLD_PWM_CLK * pwm_cycle_reg + * + * NSEC_PER_SEC is a multiple of SL28CPLD_PWM_CLK, therefore we're not losing + * precision by doing the divison first. + */ +#define SL28CPLD_PWM_TO_DUTY_CYCLE(reg) \ + (NSEC_PER_SEC / SL28CPLD_PWM_CLK * (reg)) +#define SL28CPLD_PWM_FROM_DUTY_CYCLE(duty_cycle) \ + (DIV_ROUND_DOWN_ULL((duty_cycle), NSEC_PER_SEC / SL28CPLD_PWM_CLK)) + +#define sl28cpld_pwm_read(priv, reg, val) \ + regmap_read((priv)->regmap, (priv)->offset + (reg), (val)) +#define sl28cpld_pwm_write(priv, reg, val) \ + regmap_write((priv)->regmap, (priv)->offset + (reg), (val)) + +struct sl28cpld_pwm { + struct pwm_chip pwm_chip; + struct regmap *regmap; + u32 offset; +}; + +static void sl28cpld_pwm_get_state(struct pwm_chip *chip, + struct pwm_device *pwm, + struct pwm_state *state) +{ + struct sl28cpld_pwm *priv = dev_get_drvdata(chip->dev); + unsigned int reg; + int prescaler; + + sl28cpld_pwm_read(priv, SL28CPLD_PWM_CTRL, ®); + + state->enabled = reg & SL28CPLD_PWM_CTRL_ENABLE; + + prescaler = FIELD_GET(SL28CPLD_PWM_CTRL_PRESCALER_MASK, reg); + state->period = SL28CPLD_PWM_PERIOD(prescaler); + + sl28cpld_pwm_read(priv, SL28CPLD_PWM_CYCLE, ®); + state->duty_cycle = SL28CPLD_PWM_TO_DUTY_CYCLE(reg); + state->polarity = PWM_POLARITY_NORMAL; + + /* + * Sanitize values for the PWM core. Depending on the prescaler it + * might happen that we calculate a duty_cycle greater than the actual + * period. This might happen if someone (e.g. the bootloader) sets an + * invalid combination of values. The behavior of the hardware is + * undefined in this case. But we need to report sane values back to + * the PWM core. + */ + state->duty_cycle = min(state->duty_cycle, state->period); +} + +static int sl28cpld_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + const struct pwm_state *state) +{ + struct sl28cpld_pwm *priv = dev_get_drvdata(chip->dev); + unsigned int cycle, prescaler; + bool write_duty_cycle_first; + int ret; + u8 ctrl; + + /* Polarity inversion is not supported */ + if (state->polarity != PWM_POLARITY_NORMAL) + return -EINVAL; + + /* + * Calculate the prescaler. Pick the biggest period that isn't + * bigger than the requested period. + */ + prescaler = DIV_ROUND_UP_ULL(SL28CPLD_PWM_PERIOD(0), state->period); + prescaler = order_base_2(prescaler); + + if (prescaler > field_max(SL28CPLD_PWM_CTRL_PRESCALER_MASK)) + return -ERANGE; + + ctrl = FIELD_PREP(SL28CPLD_PWM_CTRL_PRESCALER_MASK, prescaler); + if (state->enabled) + ctrl |= SL28CPLD_PWM_CTRL_ENABLE; + + cycle = SL28CPLD_PWM_FROM_DUTY_CYCLE(state->duty_cycle); + cycle = min_t(unsigned int, cycle, SL28CPLD_PWM_MAX_DUTY_CYCLE(prescaler)); + + /* + * Work around the hardware limitation. See also above. Trap 100% duty + * cycle if the prescaler is 0. Set prescaler to 1 instead. We don't + * care about the frequency because its "all-one" in either case. + * + * We don't need to check the actual prescaler setting, because only + * if the prescaler is 0 we can have this particular value. + */ + if (cycle == SL28CPLD_PWM_MAX_DUTY_CYCLE(0)) { + ctrl &= ~SL28CPLD_PWM_CTRL_PRESCALER_MASK; + ctrl |= FIELD_PREP(SL28CPLD_PWM_CTRL_PRESCALER_MASK, 1); + cycle = SL28CPLD_PWM_MAX_DUTY_CYCLE(1); + } + + /* + * To avoid glitches when we switch the prescaler, we have to make sure + * we have a valid duty cycle for the new mode. + * + * Take the current prescaler (or the current period length) into + * account to decide whether we have to write the duty cycle or the new + * prescaler first. If the period length is decreasing we have to + * write the duty cycle first. + */ + write_duty_cycle_first = pwm->state.period > state->period; + + if (write_duty_cycle_first) { + ret = sl28cpld_pwm_write(priv, SL28CPLD_PWM_CYCLE, cycle); + if (ret) + return ret; + } + + ret = sl28cpld_pwm_write(priv, SL28CPLD_PWM_CTRL, ctrl); + if (ret) + return ret; + + if (!write_duty_cycle_first) { + ret = sl28cpld_pwm_write(priv, SL28CPLD_PWM_CYCLE, cycle); + if (ret) + return ret; + } + + return 0; +} + +static const struct pwm_ops sl28cpld_pwm_ops = { + .apply = sl28cpld_pwm_apply, + .get_state = sl28cpld_pwm_get_state, + .owner = THIS_MODULE, +}; + +static int sl28cpld_pwm_probe(struct platform_device *pdev) +{ + struct sl28cpld_pwm *priv; + struct pwm_chip *chip; + int ret; + + if (!pdev->dev.parent) { + dev_err(&pdev->dev, "no parent device\n"); + return -ENODEV; + } + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!priv->regmap) { + dev_err(&pdev->dev, "could not get parent regmap\n"); + return -ENODEV; + } + + ret = device_property_read_u32(&pdev->dev, "reg", &priv->offset); + if (ret) { + dev_err(&pdev->dev, "no 'reg' property found (%pe)\n", + ERR_PTR(ret)); + return -EINVAL; + } + + /* Initialize the pwm_chip structure */ + chip = &priv->pwm_chip; + chip->dev = &pdev->dev; + chip->ops = &sl28cpld_pwm_ops; + chip->base = -1; + chip->npwm = 1; + + ret = pwmchip_add(&priv->pwm_chip); + if (ret) { + dev_err(&pdev->dev, "failed to add PWM chip (%pe)", + ERR_PTR(ret)); + return ret; + } + + platform_set_drvdata(pdev, priv); + + return 0; +} + +static int sl28cpld_pwm_remove(struct platform_device *pdev) +{ + struct sl28cpld_pwm *priv = platform_get_drvdata(pdev); + + return pwmchip_remove(&priv->pwm_chip); +} + +static const struct of_device_id sl28cpld_pwm_of_match[] = { + { .compatible = "kontron,sl28cpld-pwm" }, + {} +}; +MODULE_DEVICE_TABLE(of, sl28cpld_pwm_of_match); + +static struct platform_driver sl28cpld_pwm_driver = { + .probe = sl28cpld_pwm_probe, + .remove = sl28cpld_pwm_remove, + .driver = { + .name = "sl28cpld-pwm", + .of_match_table = sl28cpld_pwm_of_match, + }, +}; +module_platform_driver(sl28cpld_pwm_driver); + +MODULE_DESCRIPTION("sl28cpld PWM Driver"); +MODULE_AUTHOR("Michael Walle <michael@walle.cc>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/pwm/pwm-sprd.c b/drivers/pwm/pwm-sprd.c index be2394227423..5123d948efd6 100644 --- a/drivers/pwm/pwm-sprd.c +++ b/drivers/pwm/pwm-sprd.c @@ -228,11 +228,8 @@ static int sprd_pwm_clk_init(struct sprd_pwm_chip *spc) if (ret == -ENOENT) break; - if (ret != -EPROBE_DEFER) - dev_err(spc->dev, - "failed to get channel clocks\n"); - - return ret; + return dev_err_probe(spc->dev, ret, + "failed to get channel clocks\n"); } clk_pwm = chn->clks[SPRD_PWM_CHN_OUTPUT_CLK].clk; diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c index 961c59c99bb3..38a4c5c1317b 100644 --- a/drivers/pwm/pwm-sun4i.c +++ b/drivers/pwm/pwm-sun4i.c @@ -423,38 +423,26 @@ static int sun4i_pwm_probe(struct platform_device *pdev) * back to the first clock of the PWM. */ pwm->clk = devm_clk_get_optional(&pdev->dev, "mod"); - if (IS_ERR(pwm->clk)) { - if (PTR_ERR(pwm->clk) != -EPROBE_DEFER) - dev_err(&pdev->dev, "get mod clock failed %pe\n", - pwm->clk); - return PTR_ERR(pwm->clk); - } + if (IS_ERR(pwm->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(pwm->clk), + "get mod clock failed\n"); if (!pwm->clk) { pwm->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(pwm->clk)) { - if (PTR_ERR(pwm->clk) != -EPROBE_DEFER) - dev_err(&pdev->dev, "get unnamed clock failed %pe\n", - pwm->clk); - return PTR_ERR(pwm->clk); - } + if (IS_ERR(pwm->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(pwm->clk), + "get unnamed clock failed\n"); } pwm->bus_clk = devm_clk_get_optional(&pdev->dev, "bus"); - if (IS_ERR(pwm->bus_clk)) { - if (PTR_ERR(pwm->bus_clk) != -EPROBE_DEFER) - dev_err(&pdev->dev, "get bus clock failed %pe\n", - pwm->bus_clk); - return PTR_ERR(pwm->bus_clk); - } + if (IS_ERR(pwm->bus_clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(pwm->bus_clk), + "get bus clock failed\n"); pwm->rst = devm_reset_control_get_optional_shared(&pdev->dev, NULL); - if (IS_ERR(pwm->rst)) { - if (PTR_ERR(pwm->rst) != -EPROBE_DEFER) - dev_err(&pdev->dev, "get reset failed %pe\n", - pwm->rst); - return PTR_ERR(pwm->rst); - } + if (IS_ERR(pwm->rst)) + return dev_err_probe(&pdev->dev, PTR_ERR(pwm->rst), + "get reset failed\n"); /* Deassert reset */ ret = reset_control_deassert(pwm->rst); diff --git a/drivers/pwm/sysfs.c b/drivers/pwm/sysfs.c index 449dbc0f49ed..9903c3a7eced 100644 --- a/drivers/pwm/sysfs.c +++ b/drivers/pwm/sysfs.c @@ -87,10 +87,10 @@ static ssize_t duty_cycle_store(struct device *child, struct pwm_export *export = child_to_pwm_export(child); struct pwm_device *pwm = export->pwm; struct pwm_state state; - unsigned int val; + u64 val; int ret; - ret = kstrtouint(buf, 0, &val); + ret = kstrtou64(buf, 0, &val); if (ret) return ret; |