diff options
Diffstat (limited to 'drivers/pwm')
-rw-r--r-- | drivers/pwm/Kconfig | 7 | ||||
-rw-r--r-- | drivers/pwm/Makefile | 1 | ||||
-rw-r--r-- | drivers/pwm/core.c | 60 | ||||
-rw-r--r-- | drivers/pwm/pwm-atmel.c | 393 | ||||
-rw-r--r-- | drivers/pwm/pwm-imx.c | 75 | ||||
-rw-r--r-- | drivers/pwm/pwm-mxs.c | 26 | ||||
-rw-r--r-- | drivers/pwm/pwm-rockchip.c | 348 | ||||
-rw-r--r-- | drivers/pwm/pwm-stm32.c | 25 | ||||
-rw-r--r-- | drivers/pwm/pxa_pwm.c | 31 |
9 files changed, 790 insertions, 176 deletions
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 0b12278e80..eb04f92c6f 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -42,4 +42,11 @@ config PWM_STM32 help This enables PWM support for STM32 MCUs and MPUs. +config PWM_ROCKCHIP + tristate "Rockchip PWM support" + depends on ARCH_ROCKCHIP || COMPILE_TEST + help + Generic PWM framework driver for the PWM controller found on + Rockchip SoCs. + endif diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index 9c3b10ae31..4adc083e6c 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_PWM_ATMEL) += pwm-atmel.o obj-$(CONFIG_PWM_IMX) += pwm-imx.o obj-$(CONFIG_PWM_MXS) += pwm-mxs.o obj-$(CONFIG_PWM_STM32) += pwm-stm32.o +obj-$(CONFIG_PWM_ROCKCHIP) += pwm-rockchip.o diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index aba6c2a709..69724e1a5c 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -35,8 +35,8 @@ struct pwm_device { unsigned long flags; #define FLAG_REQUESTED 0 struct list_head node; - struct device_d *hwdev; - struct device_d dev; + struct device *hwdev; + struct device dev; struct pwm_state params; struct pwm_args args; @@ -44,6 +44,15 @@ struct pwm_device { static LIST_HEAD(pwm_list); +void pwm_print(void) +{ + struct pwm_device *pwm; + + list_for_each_entry(pwm, &pwm_list, node) + printf("%s\n", pwm->chip->devname); +} +EXPORT_SYMBOL(pwm_print); + static struct pwm_device *_find_pwm(const char *devname) { struct pwm_device *pwm; @@ -67,7 +76,7 @@ static int set_enable(struct param_d *p, void *priv) { struct pwm_device *pwm = priv; - if (pwm->params.p_enable) + if (pwm->params.enabled) pwm_enable(pwm); else pwm_disable(pwm); @@ -82,22 +91,25 @@ static int set_enable(struct param_d *p, void *priv) * register a new pwm. pwm->devname must be initialized, usually * from dev_name(dev) from the hardware driver. */ -int pwmchip_add(struct pwm_chip *chip, struct device_d *dev) +int pwmchip_add(struct pwm_chip *chip) { struct pwm_device *pwm; struct param_d *p; int ret; + if (!chip->devname) + return -EINVAL; + if (_find_pwm(chip->devname)) return -EBUSY; pwm = xzalloc(sizeof(*pwm)); pwm->chip = chip; - pwm->hwdev = dev; + pwm->hwdev = chip->dev; dev_set_name(&pwm->dev, chip->devname); pwm->dev.id = DEVICE_ID_SINGLE; - pwm->dev.parent = dev; + pwm->dev.parent = chip->dev; ret = register_device(&pwm->dev); if (ret) @@ -106,17 +118,17 @@ int pwmchip_add(struct pwm_chip *chip, struct device_d *dev) list_add_tail(&pwm->node, &pwm_list); p = dev_add_param_uint32(&pwm->dev, "duty_ns", apply_params, - NULL, &pwm->params.duty_ns, "%u", pwm); + NULL, &pwm->params.duty_cycle, "%u", pwm); if (IS_ERR(p)) return PTR_ERR(p); p = dev_add_param_uint32(&pwm->dev, "period_ns", apply_params, - NULL, &pwm->params.period_ns, "%u", pwm); + NULL, &pwm->params.period, "%u", pwm); if (IS_ERR(p)) return PTR_ERR(p); p = dev_add_param_bool(&pwm->dev, "enable", set_enable, - NULL, &pwm->params.p_enable, pwm); + NULL, &pwm->params.enabled, pwm); if (IS_ERR(p)) return PTR_ERR(p); @@ -194,7 +206,7 @@ static struct pwm_device *of_node_to_pwm_device(struct device_node *np, int id) struct pwm_device *pwm; list_for_each_entry(pwm, &pwm_list, node) { - if (pwm->hwdev && pwm->hwdev->device_node == np && + if (pwm->hwdev && pwm->hwdev->of_node == np && pwm->chip->id == id) return pwm; } @@ -232,7 +244,7 @@ struct pwm_device *of_pwm_request(struct device_node *np, const char *con_id) pwm->args.polarity = PWM_POLARITY_NORMAL; if (args.args_count > 2 && args.args[2] & PWM_POLARITY_INVERTED) - pwm->args.polarity = PWM_POLARITY_INVERTED; + pwm->args.polarity = PWM_POLARITY_INVERSED; ret = __pwm_request(pwm); if (ret) @@ -297,9 +309,9 @@ void pwm_init_state(const struct pwm_device *pwm, /* Then fill it with the reference config */ pwm_get_args(pwm, &args); - state->period_ns = args.period_ns; + state->period = args.period_ns; state->polarity = args.polarity; - state->duty_ns = 0; + state->duty_cycle = 0; } EXPORT_SYMBOL_GPL(pwm_init_state); @@ -308,13 +320,13 @@ int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state) struct pwm_chip *chip = pwm->chip; int ret = -EINVAL; - if (state->period_ns == 0) + if (state->period == 0) goto err; - if (state->duty_ns > state->period_ns) + if (state->duty_cycle > state->period) goto err; - ret = chip->ops->apply(chip, state); + ret = chip->ops->apply(chip, pwm, state); err: if (ret == 0) chip->state = *state; @@ -334,18 +346,18 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) return -EINVAL; pwm_get_state(pwm, &state); - if (state.duty_ns == duty_ns && state.period_ns == period_ns) + if (state.duty_cycle == duty_ns && state.period == period_ns) return 0; - state.duty_ns = duty_ns; - state.period_ns = period_ns; + state.duty_cycle = duty_ns; + state.period = period_ns; return pwm_apply_state(pwm, &state); } EXPORT_SYMBOL_GPL(pwm_config); unsigned int pwm_get_period(struct pwm_device *pwm) { - return pwm->chip->state.period_ns; + return pwm->chip->state.period; } /* @@ -356,10 +368,10 @@ int pwm_enable(struct pwm_device *pwm) struct pwm_state state; pwm_get_state(pwm, &state); - if (state.p_enable) + if (state.enabled) return 0; - state.p_enable = true; + state.enabled = true; return pwm_apply_state(pwm, &state); } EXPORT_SYMBOL_GPL(pwm_enable); @@ -372,10 +384,10 @@ void pwm_disable(struct pwm_device *pwm) struct pwm_state state; pwm_get_state(pwm, &state); - if (!state.p_enable) + if (!state.enabled) return; - state.p_enable = false; + state.enabled = false; pwm_apply_state(pwm, &state); } EXPORT_SYMBOL_GPL(pwm_disable); diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c index 648f75fb72..851676c0dd 100644 --- a/drivers/pwm/pwm-atmel.c +++ b/drivers/pwm/pwm-atmel.c @@ -55,15 +55,7 @@ #define PWMV2_CPRD 0x0C #define PWMV2_CPRDUPD 0x10 -/* - * Max value for duty and period - * - * Although the duty and period register is 32 bit, - * however only the LSB 16 bits are significant. - */ -#define PWM_MAX_DTY 0xFFFF -#define PWM_MAX_PRD 0xFFFF -#define PRD_MAX_PRES 10 +#define PWM_MAX_PRES 10 struct atmel_pwm_registers { u8 period; @@ -72,30 +64,53 @@ struct atmel_pwm_registers { u8 duty_upd; }; -struct atmel_pwm; +struct atmel_pwm_config { + u32 period_bits; +}; -struct atmel_pwm_chip { - struct pwm_chip chip; - struct atmel_pwm *atmel; +struct atmel_pwm_data { + struct atmel_pwm_registers regs; + struct atmel_pwm_config cfg; }; -struct atmel_pwm { - struct atmel_pwm_chip atmel_pwm_chip[PWM_CHANNELS]; - const struct atmel_pwm_registers *regs; +struct atmel_pwm_chip { + struct pwm_chip chips[PWM_CHANNELS]; struct clk *clk; void __iomem *base; - struct device_d *dev; + struct device *dev; + const struct atmel_pwm_data *data; + + /* + * The hardware supports a mechanism to update a channel's duty cycle at + * the end of the currently running period. When such an update is + * pending we delay disabling the PWM until the new configuration is + * active because otherwise pmw_config(duty_cycle=0); pwm_disable(); + * might not result in an inactive output. + * This bitmask tracks for which channels an update is pending in + * hardware. + */ + u32 update_pending; + + /* Protects .update_pending */ + spinlock_t lock; }; static inline struct atmel_pwm_chip *to_atmel_pwm_chip(struct pwm_chip *chip) { - return container_of(chip, struct atmel_pwm_chip, chip); + struct pwm_chip (*chips)[4] = (void *)&chip[-chip->id]; + return container_of(chips, struct atmel_pwm_chip, chips); +} + +static inline u32 atmel_pwm_readl(struct atmel_pwm_chip *chip, + unsigned long offset) +{ + return readl_relaxed(chip->base + offset); } static inline void atmel_pwm_writel(struct atmel_pwm_chip *chip, unsigned long offset, unsigned long val) { - writel(val, chip->atmel->base + offset); + writel_relaxed(val, chip->base + offset); } static inline u32 atmel_pwm_ch_readl(struct atmel_pwm_chip *chip, @@ -103,7 +118,7 @@ static inline u32 atmel_pwm_ch_readl(struct atmel_pwm_chip *chip, { unsigned long base = PWM_CH_REG_OFFSET + ch * PWM_CH_REG_SIZE; - return readl(chip->atmel->base + base + offset); + return atmel_pwm_readl(chip, base + offset); } static inline void atmel_pwm_ch_writel(struct atmel_pwm_chip *chip, @@ -112,24 +127,95 @@ static inline void atmel_pwm_ch_writel(struct atmel_pwm_chip *chip, { unsigned long base = PWM_CH_REG_OFFSET + ch * PWM_CH_REG_SIZE; - writel(val, chip->atmel->base + base + offset); + atmel_pwm_writel(chip, base + offset, val); +} + +static void atmel_pwm_update_pending(struct atmel_pwm_chip *chip) +{ + /* + * Each channel that has its bit in ISR set started a new period since + * ISR was cleared and so there is no more update pending. Note that + * reading ISR clears it, so this needs to handle all channels to not + * loose information. + */ + u32 isr = atmel_pwm_readl(chip, PWM_ISR); + + chip->update_pending &= ~isr; +} + +static void atmel_pwm_set_pending(struct atmel_pwm_chip *chip, unsigned int ch) +{ + spin_lock(&chip->lock); + + /* + * Clear pending flags in hardware because otherwise there might still + * be a stale flag in ISR. + */ + atmel_pwm_update_pending(chip); + + chip->update_pending |= (1 << ch); + + spin_unlock(&chip->lock); +} + +static int atmel_pwm_test_pending(struct atmel_pwm_chip *chip, unsigned int ch) +{ + int ret = 0; + + spin_lock(&chip->lock); + + if (chip->update_pending & (1 << ch)) { + atmel_pwm_update_pending(chip); + + if (chip->update_pending & (1 << ch)) + ret = 1; + } + + spin_unlock(&chip->lock); + + return ret; +} + +static int atmel_pwm_wait_nonpending(struct atmel_pwm_chip *chip, unsigned int ch) +{ + unsigned long timeout = get_time_ns() + 2 * HZ; + int ret; + + while ((ret = atmel_pwm_test_pending(chip, ch)) && + !is_timeout(get_time_ns(), timeout)) + udelay(100); + + return ret ? -ETIMEDOUT : 0; } -static int atmel_pwm_calculate_cprd_and_pres(struct atmel_pwm_chip *atmel_pwm, - int period, +static int atmel_pwm_calculate_cprd_and_pres(struct pwm_chip *chip, + unsigned long clkrate, + const struct pwm_state *state, unsigned long *cprd, u32 *pres) { - unsigned long long cycles = period; + struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip); + unsigned long long cycles = state->period; + int shift; + /* Calculate the period cycles and prescale value */ - cycles *= clk_get_rate(atmel_pwm->atmel->clk); + cycles *= clkrate; do_div(cycles, NSEC_PER_SEC); - for (*pres = 0; cycles > PWM_MAX_PRD; cycles >>= 1) - (*pres)++; + /* + * The register for the period length is cfg.period_bits bits wide. + * So for each bit the number of clock cycles is wider divide the input + * clock frequency by two using pres and shift cprd accordingly. + */ + shift = fls(cycles) - atmel_pwm->data->cfg.period_bits; - if (*pres > PRD_MAX_PRES) { - dev_err(atmel_pwm->atmel->dev, "pres exceeds the maximum value\n"); + if (shift > PWM_MAX_PRES) { + dev_err(atmel_pwm->dev, "pres exceeds the maximum value\n"); return -EINVAL; + } else if (shift > 0) { + *pres = shift; + cycles >>= *pres; + } else { + *pres = 0; } *cprd = cycles; @@ -137,137 +223,242 @@ static int atmel_pwm_calculate_cprd_and_pres(struct atmel_pwm_chip *atmel_pwm, return 0; } -static void atmel_pwm_calculate_cdty(int duty, int period, - unsigned long cprd, unsigned long *cdty) +static void atmel_pwm_calculate_cdty(const struct pwm_state *state, + unsigned long clkrate, unsigned long cprd, + u32 pres, unsigned long *cdty) { - unsigned long long cycles = duty; + unsigned long long cycles = state->duty_cycle; - cycles *= cprd; - do_div(cycles, period); + cycles *= clkrate; + do_div(cycles, NSEC_PER_SEC); + cycles >>= pres; *cdty = cprd - cycles; } -static void atmel_pwm_set_cprd_cdty(struct atmel_pwm_chip *atmel_pwm, int ch, +static void atmel_pwm_update_cdty(struct pwm_chip *chip, unsigned long cdty) +{ + struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip); + u32 val; + + if (atmel_pwm->data->regs.duty_upd == + atmel_pwm->data->regs.period_upd) { + val = atmel_pwm_ch_readl(atmel_pwm, chip->id, PWM_CMR); + val &= ~PWM_CMR_UPD_CDTY; + atmel_pwm_ch_writel(atmel_pwm, chip->id, PWM_CMR, val); + } + + atmel_pwm_ch_writel(atmel_pwm, chip->id, + atmel_pwm->data->regs.duty_upd, cdty); + atmel_pwm_set_pending(atmel_pwm, chip->id); +} + +static void atmel_pwm_set_cprd_cdty(struct pwm_chip *chip, unsigned long cprd, unsigned long cdty) { - const struct atmel_pwm_registers *regs = atmel_pwm->atmel->regs; + struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip); - atmel_pwm_ch_writel(atmel_pwm, ch, regs->duty, cdty); - atmel_pwm_ch_writel(atmel_pwm, ch, regs->period, cprd); + atmel_pwm_ch_writel(atmel_pwm, chip->id, + atmel_pwm->data->regs.duty, cdty); + atmel_pwm_ch_writel(atmel_pwm, chip->id, + atmel_pwm->data->regs.period, cprd); } -static int atmel_pwm_config(struct pwm_chip *chip, int duty_ns, int period_ns) +static void atmel_pwm_disable(struct pwm_chip *chip, bool disable_clk) { struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip); - unsigned long cprd, cdty; - u32 pres, val; - int ret; - int ch; + unsigned long timeout; - ch = atmel_pwm->chip.id; - ret = atmel_pwm_calculate_cprd_and_pres(atmel_pwm, period_ns, &cprd, &pres); - if (ret) - return ret; + atmel_pwm_wait_nonpending(atmel_pwm, chip->id); - atmel_pwm_calculate_cdty(duty_ns, period_ns, cprd, &cdty); + atmel_pwm_writel(atmel_pwm, PWM_DIS, 1 << chip->id); - /* It is necessary to preserve CPOL, inside CMR */ - val = atmel_pwm_ch_readl(atmel_pwm, ch, PWM_CMR); - val = (val & ~PWM_CMR_CPRE_MSK) | (pres & PWM_CMR_CPRE_MSK); - /* Assuming normal polarity */ - val &= ~PWM_CMR_CPOL; + /* + * Wait for the PWM channel disable operation to be effective before + * stopping the clock. + */ + timeout = get_time_ns() + 2 * HZ; - atmel_pwm_ch_writel(atmel_pwm, ch, PWM_CMR, val); - atmel_pwm_set_cprd_cdty(atmel_pwm, ch, cprd, cdty); + while ((atmel_pwm_readl(atmel_pwm, PWM_SR) & (1 << chip->id)) && + !is_timeout(get_time_ns(), timeout)) + udelay(100); - return 0; + if (disable_clk) + clk_disable(atmel_pwm->clk); } -static int atmel_pwm_enable(struct pwm_chip *chip) +static int atmel_pwm_apply(struct pwm_chip *chip, + struct pwm_device *pwm, + const struct pwm_state *state) { struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip); + struct pwm_state cstate; + unsigned long cprd, cdty; + u32 pres, val; + int ret; - atmel_pwm_writel(atmel_pwm, PWM_ENA, 1 << atmel_pwm->chip.id); - return 0; -} + cstate = chip->state; -static void atmel_pwm_disable(struct pwm_chip *chip) -{ - struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip); + if (state->enabled) { + unsigned long clkrate = clk_get_rate(atmel_pwm->clk); + + if (cstate.enabled && + cstate.polarity == state->polarity && + cstate.period == state->period) { + u32 cmr = atmel_pwm_ch_readl(atmel_pwm, chip->id, PWM_CMR); + + cprd = atmel_pwm_ch_readl(atmel_pwm, chip->id, + atmel_pwm->data->regs.period); + pres = cmr & PWM_CMR_CPRE_MSK; + + atmel_pwm_calculate_cdty(state, clkrate, cprd, pres, &cdty); + atmel_pwm_update_cdty(chip, cdty); + return 0; + } + + ret = atmel_pwm_calculate_cprd_and_pres(chip, clkrate, state, &cprd, + &pres); + if (ret) { + dev_err(atmel_pwm->dev, + "failed to calculate cprd and prescaler\n"); + return ret; + } + + atmel_pwm_calculate_cdty(state, clkrate, cprd, pres, &cdty); - atmel_pwm_writel(atmel_pwm, PWM_DIS, 1 << atmel_pwm->chip.id); + if (cstate.enabled) { + atmel_pwm_disable(chip, false); + } else { + ret = clk_enable(atmel_pwm->clk); + if (ret) { + dev_err(atmel_pwm->dev, "failed to enable clock\n"); + return ret; + } + } + + /* It is necessary to preserve CPOL, inside CMR */ + val = atmel_pwm_ch_readl(atmel_pwm, chip->id, PWM_CMR); + val = (val & ~PWM_CMR_CPRE_MSK) | (pres & PWM_CMR_CPRE_MSK); + if (state->polarity == PWM_POLARITY_NORMAL) + val &= ~PWM_CMR_CPOL; + else + val |= PWM_CMR_CPOL; + atmel_pwm_ch_writel(atmel_pwm, chip->id, PWM_CMR, val); + atmel_pwm_set_cprd_cdty(chip, cprd, cdty); + atmel_pwm_writel(atmel_pwm, PWM_ENA, 1 << chip->id); + } else if (cstate.enabled) { + atmel_pwm_disable(chip, true); + } + + return 0; } -static struct pwm_ops atmel_pwm_ops = { - .config = atmel_pwm_config, - .enable = atmel_pwm_enable, - .disable = atmel_pwm_disable, +static const struct pwm_ops atmel_pwm_ops = { + .apply = atmel_pwm_apply, }; -static const struct atmel_pwm_registers atmel_pwm_regs_v1 = { - .period = PWMV1_CPRD, - .period_upd = PWMV1_CUPD, - .duty = PWMV1_CDTY, - .duty_upd = PWMV1_CUPD, +static const struct atmel_pwm_data atmel_sam9rl_pwm_data = { + .regs = { + .period = PWMV1_CPRD, + .period_upd = PWMV1_CUPD, + .duty = PWMV1_CDTY, + .duty_upd = PWMV1_CUPD, + }, + .cfg = { + /* 16 bits to keep period and duty. */ + .period_bits = 16, + }, +}; + +static const struct atmel_pwm_data atmel_sama5_pwm_data = { + .regs = { + .period = PWMV2_CPRD, + .period_upd = PWMV2_CPRDUPD, + .duty = PWMV2_CDTY, + .duty_upd = PWMV2_CDTYUPD, + }, + .cfg = { + /* 16 bits to keep period and duty. */ + .period_bits = 16, + }, }; -static const struct atmel_pwm_registers atmel_pwm_regs_v2 = { - .period = PWMV2_CPRD, - .period_upd = PWMV2_CPRDUPD, - .duty = PWMV2_CDTY, - .duty_upd = PWMV2_CDTYUPD, +static const struct atmel_pwm_data mchp_sam9x60_pwm_data = { + .regs = { + .period = PWMV1_CPRD, + .period_upd = PWMV1_CUPD, + .duty = PWMV1_CDTY, + .duty_upd = PWMV1_CUPD, + }, + .cfg = { + /* 32 bits to keep period and duty. */ + .period_bits = 32, + }, }; static const struct of_device_id atmel_pwm_dt_ids[] = { { .compatible = "atmel,at91sam9rl-pwm", - .data = &atmel_pwm_regs_v1, + .data = &atmel_sam9rl_pwm_data, }, { .compatible = "atmel,sama5d3-pwm", - .data = &atmel_pwm_regs_v2, + .data = &atmel_sama5_pwm_data, }, { .compatible = "atmel,sama5d2-pwm", - .data = &atmel_pwm_regs_v2, + .data = &atmel_sama5_pwm_data, + }, { + .compatible = "microchip,sam9x60-pwm", + .data = &mchp_sam9x60_pwm_data, }, { /* sentinel */ }, }; +MODULE_DEVICE_TABLE(of, atmel_pwm_dt_ids); + +static int id = -1; -static int atmel_pwm_probe(struct device_d *dev) +static int atmel_pwm_probe(struct device *dev) { - const struct atmel_pwm_registers *regs; - struct atmel_pwm *atmel_pwm; - struct resource *res; + const struct atmel_pwm_data *data; + struct atmel_pwm_chip *atmel_pwm; + struct resource *iores; + const char *alias; int ret; int i; - ret = dev_get_drvdata(dev, (const void **)®s); + ret = dev_get_drvdata(dev, (const void **)&data); if (ret) return ret; atmel_pwm = xzalloc(sizeof(*atmel_pwm)); - atmel_pwm->regs = regs; + atmel_pwm->data = data; atmel_pwm->dev = dev; atmel_pwm->clk = clk_get(dev, "pwm_clk"); if (IS_ERR(atmel_pwm->clk)) return PTR_ERR(atmel_pwm->clk); - res = dev_request_mem_resource(dev, 0); - if (IS_ERR(res)) - return PTR_ERR(res); + iores = dev_request_mem_resource(dev, 0); + if (IS_ERR(iores)) + return PTR_ERR(iores); - atmel_pwm->base = IOMEM(res->start); + atmel_pwm->base = IOMEM(iores->start); + alias = of_alias_get(dev->of_node); + if (!alias) + id++; for (i = 0; i < PWM_CHANNELS; i++) { - struct atmel_pwm_chip *chip = &atmel_pwm->atmel_pwm_chip[i]; - chip->chip.ops = &atmel_pwm_ops; - chip->chip.devname = basprintf("pwm%d", i); - chip->chip.id = i; - chip->atmel = atmel_pwm; - - ret = pwmchip_add(&chip->chip, dev); - if (ret < 0) { - dev_err(dev, "failed to add pwm chip[%d] %d\n", i, ret); + struct pwm_chip *chip = &atmel_pwm->chips[i]; + + if (alias) + chip->devname = basprintf("%sch%u", alias, i + 1); + else + chip->devname = basprintf("pwm%uch%u", id, i + 1); + + chip->ops = &atmel_pwm_ops; + chip->id = i; + chip->dev = dev; + ret = pwmchip_add(chip); + if (ret) { + dev_err(dev, "failed to add pwm chip %d\n", ret); return ret; } } @@ -275,7 +466,7 @@ static int atmel_pwm_probe(struct device_d *dev) return 0; } -static struct driver_d atmel_pwm_driver = { +static struct driver atmel_pwm_driver = { .name = "atmel-pwm", .of_compatible = atmel_pwm_dt_ids, .probe = atmel_pwm_probe, diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c index 609765d895..2a75400593 100644 --- a/drivers/pwm/pwm-imx.c +++ b/drivers/pwm/pwm-imx.c @@ -36,7 +36,7 @@ #define MX3_PWMCR_EN (1 << 0) struct imx_chip { - struct clk *clk_per; + struct clk *clk_per, *clk_ipg; void __iomem *mmio_base; @@ -93,14 +93,42 @@ static void imx_pwm_set_enable_v1(struct pwm_chip *chip, bool enable) writel(val, imx->mmio_base + MX1_PWMC); } +static int imx_pwm_clk_enable_v2(struct imx_chip *imx) +{ + int ret; + + ret = clk_enable(imx->clk_ipg); + if (ret) + return ret; + + ret = clk_prepare_enable(imx->clk_per); + if (ret) { + clk_disable_unprepare(imx->clk_ipg); + return ret; + } + + return 0; +} + +static void imx_pwm_clk_disable_v2(struct imx_chip *imx) +{ + clk_disable_unprepare(imx->clk_per); + clk_disable_unprepare(imx->clk_ipg); +} + static int imx_pwm_config_v2(struct pwm_chip *chip, int duty_ns, int period_ns) { struct imx_chip *imx = to_imx_chip(chip); unsigned long long c; unsigned long period_cycles, duty_cycles, prescale; + int ret; u32 cr; + ret = imx_pwm_clk_enable_v2(imx); + if (ret) + return ret; + c = clk_get_rate(imx->clk_per); c = c * period_ns; do_div(c, 1000000000); @@ -134,6 +162,9 @@ static int imx_pwm_config_v2(struct pwm_chip *chip, writel(cr, imx->mmio_base + MX3_PWMCR); + if (!chip->state.enabled) + imx_pwm_clk_disable_v2(imx); + return 0; } @@ -141,6 +172,11 @@ static void imx_pwm_set_enable_v2(struct pwm_chip *chip, bool enable) { struct imx_chip *imx = to_imx_chip(chip); u32 val; + int ret; + + ret = imx_pwm_clk_enable_v2(imx); + if (WARN_ON(ret)) + return; val = readl(imx->mmio_base + MX3_PWMCR); @@ -150,26 +186,31 @@ static void imx_pwm_set_enable_v2(struct pwm_chip *chip, bool enable) val &= ~MX3_PWMCR_EN; writel(val, imx->mmio_base + MX3_PWMCR); + + if (!enable) + imx_pwm_clk_disable_v2(imx); } -static int imx_pwm_apply(struct pwm_chip *chip, const struct pwm_state *state) +static int imx_pwm_apply(struct pwm_chip *chip, + struct pwm_device *pwm, + const struct pwm_state *state) { struct imx_chip *imx = to_imx_chip(chip); bool enabled; int ret; - enabled = chip->state.p_enable; + enabled = chip->state.enabled; - if (enabled && !state->p_enable) { + if (enabled && !state->enabled) { imx->set_enable(chip, false); return 0; } - ret = imx->config(chip, state->duty_ns, state->period_ns); + ret = imx->config(chip, state->duty_cycle, state->period); if (ret) return ret; - if (!enabled && state->p_enable) + if (!enabled && state->enabled) imx->set_enable(chip, true); return 0; @@ -200,13 +241,14 @@ static struct of_device_id imx_pwm_dt_ids[] = { { .compatible = "fsl,imx27-pwm", .data = &imx_pwm_data_v2, }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, imx_pwm_dt_ids); -static int imx_pwm_probe(struct device_d *dev) +static int imx_pwm_probe(struct device *dev) { struct resource *iores; const struct imx_pwm_data *data; struct imx_chip *imx; - int ret = 0; + int ret; ret = dev_get_drvdata(dev, (const void **)&data); if (ret) @@ -214,6 +256,10 @@ static int imx_pwm_probe(struct device_d *dev) imx = xzalloc(sizeof(*imx)); + imx->clk_ipg = clk_get_optional(dev, "ipg"); + if (IS_ERR(imx->clk_ipg)) + return PTR_ERR(imx->clk_ipg); + imx->clk_per = clk_get(dev, "per"); if (IS_ERR(imx->clk_per)) return PTR_ERR(imx->clk_per); @@ -223,9 +269,10 @@ static int imx_pwm_probe(struct device_d *dev) return PTR_ERR(iores); imx->mmio_base = IOMEM(iores->start); + imx->chip.dev = dev; imx->chip.ops = &imx_pwm_ops; - if (dev->device_node) { - imx->chip.devname = of_alias_get(dev->device_node); + if (dev->of_node) { + imx->chip.devname = of_alias_get(dev->of_node); if (!imx->chip.devname) imx->chip.devname = basprintf("pwm_%p", imx->mmio_base); @@ -236,14 +283,10 @@ static int imx_pwm_probe(struct device_d *dev) imx->config = data->config; imx->set_enable = data->set_enable; - ret = pwmchip_add(&imx->chip, dev); - if (ret < 0) - return ret; - - return 0; + return pwmchip_add(&imx->chip); } -static struct driver_d imx_pwm_driver = { +static struct driver imx_pwm_driver = { .name = "imx-pwm", .of_compatible = imx_pwm_dt_ids, .probe = imx_pwm_probe, diff --git a/drivers/pwm/pwm-mxs.c b/drivers/pwm/pwm-mxs.c index 8f77ca07a6..3e3efade68 100644 --- a/drivers/pwm/pwm-mxs.c +++ b/drivers/pwm/pwm-mxs.c @@ -44,7 +44,9 @@ struct mxs_pwm { #define to_mxs_pwm_chip(_chip) container_of(_chip, struct mxs_pwm_chip, chip) -static int mxs_pwm_apply(struct pwm_chip *chip, const struct pwm_state *state) +static int mxs_pwm_apply(struct pwm_chip *chip, + struct pwm_device *pwm, + const struct pwm_state *state) { struct mxs_pwm_chip *mxs = to_mxs_pwm_chip(chip); int div = 0; @@ -53,9 +55,9 @@ static int mxs_pwm_apply(struct pwm_chip *chip, const struct pwm_state *state) unsigned long long c; bool enabled; - enabled = chip->state.p_enable; + enabled = chip->state.enabled; - if (enabled && !state->p_enable) { + if (enabled && !state->enabled) { writel(1 << mxs->chip.id, mxs->mxs->base + PWM_CTRL + CLR); return 0; } @@ -63,7 +65,7 @@ static int mxs_pwm_apply(struct pwm_chip *chip, const struct pwm_state *state) rate = clk_get_rate(mxs->mxs->clk); while (1) { c = rate / cdiv[div]; - c = c * state->period_ns; + c = c * state->period; do_div(c, 1000000000); if (c < PERIOD_PERIOD_MAX) break; @@ -73,8 +75,8 @@ static int mxs_pwm_apply(struct pwm_chip *chip, const struct pwm_state *state) } period_cycles = c; - c *= state->duty_ns; - do_div(c, state->period_ns); + c *= state->duty_cycle; + do_div(c, state->period); duty_cycles = c; writel(duty_cycles << 16, @@ -83,7 +85,7 @@ static int mxs_pwm_apply(struct pwm_chip *chip, const struct pwm_state *state) PERIOD_INACTIVE_LOW | PERIOD_CDIV(div), mxs->mxs->base + PWM_PERIOD0 + mxs->chip.id * 0x20); - if (!enabled && state->p_enable) + if (!enabled && state->enabled) writel(1 << mxs->chip.id, mxs->mxs->base + PWM_CTRL + SET); return 0; @@ -93,10 +95,10 @@ static struct pwm_ops mxs_pwm_ops = { .apply = mxs_pwm_apply, }; -static int mxs_pwm_probe(struct device_d *dev) +static int mxs_pwm_probe(struct device *dev) { struct resource *iores; - struct device_node *np = dev->device_node; + struct device_node *np = dev->of_node; struct mxs_pwm *mxs; int ret, i; uint32_t npwm; @@ -130,9 +132,10 @@ static int mxs_pwm_probe(struct device_d *dev) mxspwm->chip.ops = &mxs_pwm_ops; mxspwm->chip.devname = basprintf("pwm%d", i); mxspwm->chip.id = i; + mxspwm->chip.dev = dev; mxspwm->mxs = mxs; - ret = pwmchip_add(&mxspwm->chip, dev); + ret = pwmchip_add(&mxspwm->chip); if (ret < 0) { dev_err(dev, "failed to add pwm chip %d\n", ret); return ret; @@ -146,8 +149,9 @@ static const struct of_device_id mxs_pwm_dt_ids[] = { { .compatible = "fsl,imx23-pwm", }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, mxs_pwm_dt_ids); -static struct driver_d mxs_pwm_driver = { +static struct driver mxs_pwm_driver = { .name = "mxs-pwm", .of_compatible = mxs_pwm_dt_ids, .probe = mxs_pwm_probe, diff --git a/drivers/pwm/pwm-rockchip.c b/drivers/pwm/pwm-rockchip.c new file mode 100644 index 0000000000..960867c520 --- /dev/null +++ b/drivers/pwm/pwm-rockchip.c @@ -0,0 +1,348 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * PWM driver for Rockchip SoCs + * + * Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com> + * Copyright (C) 2014 ROCKCHIP, Inc. + */ + +#include <linux/clk.h> +#include <linux/io.h> +#include <module.h> +#include <of.h> +#include <linux/device.h> +#include <pwm.h> +#include <linux/time.h> + +#define PWM_CTRL_TIMER_EN (1 << 0) +#define PWM_CTRL_OUTPUT_EN (1 << 3) + +#define PWM_ENABLE (1 << 0) +#define PWM_CONTINUOUS (1 << 1) +#define PWM_DUTY_POSITIVE (1 << 3) +#define PWM_DUTY_NEGATIVE (0 << 3) +#define PWM_INACTIVE_NEGATIVE (0 << 4) +#define PWM_INACTIVE_POSITIVE (1 << 4) +#define PWM_POLARITY_MASK (PWM_DUTY_POSITIVE | PWM_INACTIVE_POSITIVE) +#define PWM_OUTPUT_LEFT (0 << 5) +#define PWM_LOCK_EN (1 << 6) +#define PWM_LP_DISABLE (0 << 8) + +struct rockchip_pwm_chip { + struct pwm_chip chip; + struct clk *clk; + struct clk *pclk; + const struct rockchip_pwm_data *data; + void __iomem *base; +}; + +struct rockchip_pwm_regs { + unsigned long duty; + unsigned long period; + unsigned long cntr; + unsigned long ctrl; +}; + +struct rockchip_pwm_data { + struct rockchip_pwm_regs regs; + unsigned int prescaler; + bool supports_polarity; + bool supports_lock; + u32 enable_conf; +}; + +static inline struct rockchip_pwm_chip *to_rockchip_pwm_chip(struct pwm_chip *chip) +{ + return container_of(chip, struct rockchip_pwm_chip, chip); +} + +static void rockchip_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, + const struct pwm_state *state) +{ + struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip); + unsigned long period, duty; + u64 clk_rate, div; + u32 ctrl; + + clk_rate = clk_get_rate(pc->clk); + + /* + * Since period and duty cycle registers have a width of 32 + * bits, every possible input period can be obtained using the + * default prescaler value for all practical clock rate values. + */ + div = clk_rate * state->period; + period = DIV_ROUND_CLOSEST_ULL(div, + pc->data->prescaler * NSEC_PER_SEC); + + div = clk_rate * state->duty_cycle; + duty = DIV_ROUND_CLOSEST_ULL(div, pc->data->prescaler * NSEC_PER_SEC); + + /* + * Lock the period and duty of previous configuration, then + * change the duty and period, that would not be effective. + */ + ctrl = readl_relaxed(pc->base + pc->data->regs.ctrl); + if (pc->data->supports_lock) { + ctrl |= PWM_LOCK_EN; + writel_relaxed(ctrl, pc->base + pc->data->regs.ctrl); + } + + writel(period, pc->base + pc->data->regs.period); + writel(duty, pc->base + pc->data->regs.duty); + + if (pc->data->supports_polarity) { + ctrl &= ~PWM_POLARITY_MASK; + if (state->polarity == PWM_POLARITY_INVERSED) + ctrl |= PWM_DUTY_NEGATIVE | PWM_INACTIVE_POSITIVE; + else + ctrl |= PWM_DUTY_POSITIVE | PWM_INACTIVE_NEGATIVE; + } + + /* + * Unlock and set polarity at the same time, + * the configuration of duty, period and polarity + * would be effective together at next period. + */ + if (pc->data->supports_lock) + ctrl &= ~PWM_LOCK_EN; + + writel(ctrl, pc->base + pc->data->regs.ctrl); +} + +static int rockchip_pwm_enable(struct pwm_chip *chip, + struct pwm_device *pwm, + bool enable) +{ + struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip); + u32 enable_conf = pc->data->enable_conf; + int ret; + u32 val; + + if (enable) { + ret = clk_enable(pc->clk); + if (ret) + return ret; + } + + val = readl_relaxed(pc->base + pc->data->regs.ctrl); + + if (enable) + val |= enable_conf; + else + val &= ~enable_conf; + + writel_relaxed(val, pc->base + pc->data->regs.ctrl); + + if (!enable) + clk_disable(pc->clk); + + return 0; +} + +static int rockchip_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + const struct pwm_state *state) +{ + struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip); + struct pwm_state curstate; + bool enabled; + int ret = 0; + + ret = clk_enable(pc->pclk); + if (ret) + return ret; + + ret = clk_enable(pc->clk); + if (ret) + return ret; + + pwm_get_state(pwm, &curstate); + enabled = curstate.enabled; + + if (state->polarity != curstate.polarity && enabled && + !pc->data->supports_lock) { + ret = rockchip_pwm_enable(chip, pwm, false); + if (ret) + goto out; + enabled = false; + } + + rockchip_pwm_config(chip, pwm, state); + if (state->enabled != enabled) { + ret = rockchip_pwm_enable(chip, pwm, state->enabled); + if (ret) + goto out; + } + +out: + clk_disable(pc->clk); + clk_disable(pc->pclk); + + return ret; +} + +static const struct pwm_ops rockchip_pwm_ops = { + .apply = rockchip_pwm_apply, +}; + +static const struct rockchip_pwm_data pwm_data_v1 = { + .regs = { + .duty = 0x04, + .period = 0x08, + .cntr = 0x00, + .ctrl = 0x0c, + }, + .prescaler = 2, + .supports_polarity = false, + .supports_lock = false, + .enable_conf = PWM_CTRL_OUTPUT_EN | PWM_CTRL_TIMER_EN, +}; + +static const struct rockchip_pwm_data pwm_data_v2 = { + .regs = { + .duty = 0x08, + .period = 0x04, + .cntr = 0x00, + .ctrl = 0x0c, + }, + .prescaler = 1, + .supports_polarity = true, + .supports_lock = false, + .enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | PWM_ENABLE | + PWM_CONTINUOUS, +}; + +static const struct rockchip_pwm_data pwm_data_vop = { + .regs = { + .duty = 0x08, + .period = 0x04, + .cntr = 0x0c, + .ctrl = 0x00, + }, + .prescaler = 1, + .supports_polarity = true, + .supports_lock = false, + .enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | PWM_ENABLE | + PWM_CONTINUOUS, +}; + +static const struct rockchip_pwm_data pwm_data_v3 = { + .regs = { + .duty = 0x08, + .period = 0x04, + .cntr = 0x00, + .ctrl = 0x0c, + }, + .prescaler = 1, + .supports_polarity = true, + .supports_lock = true, + .enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | PWM_ENABLE | + PWM_CONTINUOUS, +}; + +static const struct of_device_id rockchip_pwm_dt_ids[] = { + { .compatible = "rockchip,rk2928-pwm", .data = &pwm_data_v1}, + { .compatible = "rockchip,rk3288-pwm", .data = &pwm_data_v2}, + { .compatible = "rockchip,vop-pwm", .data = &pwm_data_vop}, + { .compatible = "rockchip,rk3328-pwm", .data = &pwm_data_v3}, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, rockchip_pwm_dt_ids); + +static int rockchip_pwm_probe(struct device *dev) +{ + struct rockchip_pwm_chip *pc; + u32 enable_conf, ctrl; + bool enabled; + int ret, count; + + pc = devm_kzalloc(dev, sizeof(*pc), GFP_KERNEL); + if (!pc) + return -ENOMEM; + + pc->base = dev_platform_ioremap_resource(dev, 0); + if (IS_ERR(pc->base)) + return PTR_ERR(pc->base); + + pc->clk = clk_get(dev, "pwm"); + if (IS_ERR(pc->clk)) { + pc->clk = clk_get(dev, NULL); + if (IS_ERR(pc->clk)) + return dev_err_probe(dev, PTR_ERR(pc->clk), + "Can't get PWM clk\n"); + } + + count = of_count_phandle_with_args(dev->of_node, + "clocks", "#clock-cells"); + if (count == 2) + pc->pclk = clk_get(dev, "pclk"); + else + pc->pclk = pc->clk; + + if (IS_ERR(pc->pclk)) + return dev_err_probe(dev, PTR_ERR(pc->pclk), "Can't get APB clk\n"); + + ret = clk_prepare_enable(pc->clk); + if (ret) + return dev_err_probe(dev, ret, "Can't prepare enable PWM clk\n"); + + ret = clk_prepare_enable(pc->pclk); + if (ret) { + dev_err_probe(dev, ret, "Can't prepare enable APB clk\n"); + goto err_clk; + } + + dev->priv = pc; + + pc->data = device_get_match_data(dev); + pc->chip.dev = dev; + pc->chip.ops = &rockchip_pwm_ops; + + enable_conf = pc->data->enable_conf; + ctrl = readl_relaxed(pc->base + pc->data->regs.ctrl); + enabled = (ctrl & enable_conf) == enable_conf; + + pc->chip.devname = of_alias_get(dev->of_node); + if (!pc->chip.devname) + pc->chip.devname = basprintf("pwm_%p", pc->base); + + ret = pwmchip_add(&pc->chip); + if (ret < 0) { + dev_err_probe(dev, ret, "pwmchip_add() failed\n"); + goto err_pclk; + } + + /* Keep the PWM clk enabled if the PWM appears to be up and running. */ + if (!enabled) + clk_disable(pc->clk); + + clk_disable(pc->pclk); + + return 0; + +err_pclk: + clk_disable_unprepare(pc->pclk); +err_clk: + clk_disable_unprepare(pc->clk); + + return ret; +} + +static void rockchip_pwm_remove(struct device *dev) +{ + struct rockchip_pwm_chip *pc = dev->priv; + + pwmchip_remove(&pc->chip); +} + +static struct driver rockchip_pwm_driver = { + .name = "rockchip-pwm", + .of_match_table = rockchip_pwm_dt_ids, + .probe = rockchip_pwm_probe, + .remove = rockchip_pwm_remove, +}; +device_platform_driver(rockchip_pwm_driver); + +MODULE_AUTHOR("Beniamino Galvani <b.galvani@gmail.com>"); +MODULE_DESCRIPTION("Rockchip SoC PWM driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c index 4e1a65207e..16f80381c2 100644 --- a/drivers/pwm/pwm-stm32.c +++ b/drivers/pwm/pwm-stm32.c @@ -14,6 +14,7 @@ #include <io.h> #include <linux/bitfield.h> #include <linux/mfd/stm32-timers.h> +#include <linux/regmap.h> #include <linux/math64.h> #include <of.h> #include <pwm.h> @@ -197,15 +198,17 @@ static void stm32_pwm_disable(struct stm32_pwm *priv, unsigned ch) clk_disable(priv->clk); } -static int stm32_pwm_apply(struct pwm_chip *chip, const struct pwm_state *state) +static int stm32_pwm_apply(struct pwm_chip *chip, + struct pwm_device *pwm, + const struct pwm_state *state) { bool enabled; struct stm32_pwm *priv = to_stm32_pwm_dev(chip); int ret; - enabled = chip->state.p_enable; + enabled = chip->state.enabled; - if (enabled && !state->p_enable) { + if (enabled && !state->enabled) { stm32_pwm_disable(priv, chip->id); return 0; } @@ -214,11 +217,11 @@ static int stm32_pwm_apply(struct pwm_chip *chip, const struct pwm_state *state) stm32_pwm_set_polarity(priv, chip->id, state->polarity); ret = stm32_pwm_config(priv, chip->id, - state->duty_ns, state->period_ns); + state->duty_cycle, state->period); if (ret) return ret; - if (!enabled && state->p_enable) + if (!enabled && state->enabled) ret = stm32_pwm_enable(priv, chip->id); return ret; @@ -335,9 +338,9 @@ static int stm32_pwm_detect_channels(struct stm32_pwm *priv) static int id = -1; -static int stm32_pwm_probe(struct device_d *dev) +static int stm32_pwm_probe(struct device *dev) { - struct device_node *np = dev->device_node; + struct device_node *np = dev->of_node; struct stm32_timers *ddata = dev->parent->priv; struct stm32_pwm *priv; const char *alias; @@ -362,7 +365,7 @@ static int stm32_pwm_probe(struct device_d *dev) npwms = stm32_pwm_detect_channels(priv); - alias = of_alias_get(dev->device_node); + alias = of_alias_get(dev->of_node); if (!alias) id++; @@ -376,8 +379,9 @@ static int stm32_pwm_probe(struct device_d *dev) chip->ops = &stm32pwm_ops; chip->id = i; + chip->dev = dev; - ret = pwmchip_add(chip, dev); + ret = pwmchip_add(chip); if (ret < 0) { dev_err(dev, "failed to add pwm chip %d\n", ret); return ret; @@ -391,8 +395,9 @@ static const struct of_device_id stm32_pwm_of_match[] = { { .compatible = "st,stm32-pwm", }, { /* sentinel */ }, }; +MODULE_DEVICE_TABLE(of, stm32_pwm_of_match); -static struct driver_d stm32_pwm_driver = { +static struct driver stm32_pwm_driver = { .name = "stm32-pwm", .probe = stm32_pwm_probe, .of_compatible = stm32_pwm_of_match, diff --git a/drivers/pwm/pxa_pwm.c b/drivers/pwm/pxa_pwm.c index 61c4b8da43..42ccb37b9a 100644 --- a/drivers/pwm/pxa_pwm.c +++ b/drivers/pwm/pxa_pwm.c @@ -13,10 +13,10 @@ #include <io.h> #include <pwm.h> -#include <mach/hardware.h> -#include <mach/clock.h> -#include <mach/pxa-regs.h> -#include <mach/regs-pwm.h> +#include <mach/pxa/hardware.h> +#include <mach/pxa/clock.h> +#include <mach/pxa/pxa-regs.h> +#include <mach/pxa/regs-pwm.h> #include <linux/math64.h> #include <linux/compiler.h> @@ -77,22 +77,24 @@ static void pxa_pwm_disable(struct pxa_pwm_chip *pxa_pwm) * duty_ns = 10^9 * (PRESCALE + 1) * DC / PWM_CLK_RATE * PWM_CLK_RATE = 13 MHz */ -static int pxa_pwm_apply(struct pwm_chip *chip, const struct pwm_state *state) +static int pxa_pwm_apply(struct pwm_chip *chip, + struct pwm_device *pwm, + const struct pwm_state *state) { unsigned long long c; unsigned long period_cycles, prescale, pv, dc; struct pxa_pwm_chip *pxa_pwm = to_pxa_pwm_chip(chip); bool enabled; - enabled = chip->state.p_enable; + enabled = chip->state.enabled; - if (enabled && !state->p_enable) { + if (enabled && !state->enabled) { pxa_pwm_disable(pxa_pwm); return 0; } c = pxa_get_pwmclk(); - c = c * state->period_ns; + c = c * state->period; do_div(c, 1000000000); period_cycles = c; @@ -104,10 +106,10 @@ static int pxa_pwm_apply(struct pwm_chip *chip, const struct pwm_state *state) if (prescale > 63) return -EINVAL; - if (state->duty_ns == state->period_ns) + if (state->duty_cycle == state->period) dc = PWMDCR_FD; else - dc = (pv + 1) * state->duty_ns / state->period_ns; + dc = (pv + 1) * state->duty_cycle / state->period; /* NOTE: the clock to PWM has to be enabled first * before writing to the registers @@ -116,7 +118,7 @@ static int pxa_pwm_apply(struct pwm_chip *chip, const struct pwm_state *state) writel(dc, pxa_pwm->iobase + PWMDCR); writel(pv, pxa_pwm->iobase + PWMPCR); - if (!enabled && state->p_enable) { + if (!enabled && state->enabled) { pxa_pwm_enable(pxa_pwm); return 0; } @@ -128,7 +130,7 @@ static struct pwm_ops pxa_pwm_ops = { .apply = pxa_pwm_apply, }; -static int pxa_pwm_probe(struct device_d *dev) +static int pxa_pwm_probe(struct device *dev) { struct resource *iores; struct pxa_pwm_chip *chip; @@ -141,12 +143,13 @@ static int pxa_pwm_probe(struct device_d *dev) return PTR_ERR(iores); chip->iobase = IOMEM(iores->start); chip->id = dev->id; + chip->chip.dev = dev; dev->priv = chip; - return pwmchip_add(&chip->chip, dev); + return pwmchip_add(&chip->chip); } -static struct driver_d pxa_pwm_driver = { +static struct driver pxa_pwm_driver = { .name = "pxa_pwm", .probe = pxa_pwm_probe, }; |