pwm: lpc32xx - Add a driver for the motor PWM
Subsystems (3)
PATCH 1/1 pwm: lpc32xx - Add a driver for the motor PWM
--- .../devicetree/bindings/pwm/lpc32xx-motor-pwm.txt | 24 ++ arch/arm/boot/dts/lpc32xx.dtsi | 7 + drivers/pwm/Kconfig | 10 + drivers/pwm/Makefile | 1 + drivers/pwm/pwm-lpc32xx-motor.c | 230 ++++++++++++++++++++ 5 files changed, 272 insertions(+), 0 deletions(-) create mode 100644 Documentation/devicetree/bindings/pwm/lpc32xx-motor-pwm.txt create mode 100644 drivers/pwm/pwm-lpc32xx-motor.c
Documentation/devicetree/bindings/pwm/lpc32xx-motor-pwm.txt new file +24 -0
@@ -0,0 +1,24 @@ +LPC32XX Motor PWM controller + +The LPC32xx motor PWMs have two output pin, A and B, with B=!A. +Per default the output A should be used, if the output B is used the +PWM polarity should be inverted using the linux,polarity property. + +Required properties: +- compatible: should be "nxp,lpc3220-motor-pwm" +- reg: physical base address and length of the controller's registers + +Optional properites: +- linux,polarity: Bit mask of the polarity to use for each output, + a bit set to 0 indicate the default polarity, a bit set to 1 + indicate an inverted polarity. In other word this set if output + A or output B has the correct polarity. + +Examples: + +mpwm at 400e8000 { + compatible = "nxp,lpc3220-motor-pwm"; + reg = <0x400E8000 0x78>; + linux,polarity = 5; /* Use outputs B0, A1 and B2 */ + #pwm-cells = <2>; +};
arch/arm/boot/dts/lpc32xx.dtsi +7 -0
@@ -182,6 +182,13 @@ pnx,timeout = <0x64>; }; + mpwm: mpwm at 400E8000 { + compatible = "nxp,lpc3220-motor-pwm"; + reg = <0x400E8000 0x78>; + status = "disabled"; + #pwm-cells = <2>; + }; + i2cusb: i2c at 31020300 { compatible = "nxp,pnx-i2c"; reg = <0x31020300 0x100>;
drivers/pwm/Kconfig +10 -0
@@ -57,6 +57,16 @@ config PWM_LPC32XX To compile this driver as a module, choose M here: the module will be called pwm-lpc32xx. +config PWM_LPC32XX_MOTOR + tristate "LPC32XX Motor PWM support" + depends on ARCH_LPC32XX + help + Generic PWM framework driver for LPC32XX motor PWM. The LPC32XX SOC + has one motor PWM controllers. + + To compile this driver as a module, choose M here: the module + will be called pwm-motor-lpc32xx. + config PWM_MXS tristate "Freescale MXS PWM support" depends on ARCH_MXS && OF
drivers/pwm/Makefile +1 -0
@@ -2,6 +2,7 @@ obj-$(CONFIG_PWM) += core.o obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o obj-$(CONFIG_PWM_IMX) += pwm-imx.o obj-$(CONFIG_PWM_LPC32XX) += pwm-lpc32xx.o +obj-$(CONFIG_PWM_LPC32XX_MOTOR) += pwm-lpc32xx-motor.o obj-$(CONFIG_PWM_MXS) += pwm-mxs.o obj-$(CONFIG_PWM_PXA) += pwm-pxa.o obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o
drivers/pwm/pwm-lpc32xx-motor.c new file +230 -0
230 lines not on this page · raw message
Signature · 1 line
1.7.0.4
PATCH 1/1 pwm: lpc32xx - Add a driver for the motor PWM
Quoted 4 lines · Alban Bedel
Signed-off-by Alban Bedel <[email protected]>--- .../devicetree/bindings/pwm/lpc32xx-motor-pwm.txt | 24 ++ arch/arm/boot/dts/lpc32xx.dtsi | 7 +
Is all this supposed to go via mach-lpc32xx -> arm-soc.git? Then, I can take this into the lpc32xx tree. Otherwise, you can split off the .dtsi file and I include it via lpc32xx.
Thanks,
Roland
Quoted 324 lines
drivers/pwm/Kconfig | 10 + drivers/pwm/Makefile | 1 + drivers/pwm/pwm-lpc32xx-motor.c | 230 ++++++++++++++++++++ 5 files changed, 272 insertions(+), 0 deletions(-) create mode 100644 Documentation/devicetree/bindings/pwm/lpc32xx-motor-pwm.txt create mode 100644 drivers/pwm/pwm-lpc32xx-motor.cDocumentation/devicetree/bindings/pwm/lpc32xx-motor-pwm.txt new file +24
-0@@ -0,0 +1,24 @@ +LPC32XX Motor PWM controller + +The LPC32xx motor PWMs have two output pin, A and B, with B=!A. +Per default the output A should be used, if the output B is used the +PWM polarity should be inverted using the linux,polarity property. + +Required properties: +- compatible: should be "nxp,lpc3220-motor-pwm" +- reg: physical base address and length of the controller's registers + +Optional properites: +- linux,polarity: Bit mask of the polarity to use for each output, + a bit set to 0 indicate the default polarity, a bit set to 1 + indicate an inverted polarity. In other word this set if output + A or output B has the correct polarity. + +Examples: + +mpwm at 400e8000 { + compatible = "nxp,lpc3220-motor-pwm"; + reg = <0x400E8000 0x78>; + linux,polarity = 5; /* Use outputs B0, A1 and B2 */ + #pwm-cells = <2>; +};arch/arm/boot/dts/lpc32xx.dtsi +7
-0@@ -182,6 +182,13 @@ pnx,timeout = <0x64>; }; + mpwm: mpwm at 400E8000 { + compatible = "nxp,lpc3220-motor-pwm"; + reg = <0x400E8000 0x78>; + status = "disabled"; + #pwm-cells = <2>; + }; + i2cusb: i2c at 31020300 { compatible = "nxp,pnx-i2c"; reg = <0x31020300 0x100>;drivers/pwm/Kconfig +10
-0@@ -57,6 +57,16 @@ config PWM_LPC32XX To compile this driver as a module, choose M here: the module will be called pwm-lpc32xx. +config PWM_LPC32XX_MOTOR + tristate "LPC32XX Motor PWM support" + depends on ARCH_LPC32XX + help + Generic PWM framework driver for LPC32XX motor PWM. The LPC32XX SOC + has one motor PWM controllers. + + To compile this driver as a module, choose M here: the module + will be called pwm-motor-lpc32xx. + config PWM_MXS tristate "Freescale MXS PWM support" depends on ARCH_MXS && OFdrivers/pwm/Makefile +1
-0@@ -2,6 +2,7 @@ obj-$(CONFIG_PWM) += core.o obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o obj-$(CONFIG_PWM_IMX) += pwm-imx.o obj-$(CONFIG_PWM_LPC32XX) += pwm-lpc32xx.o +obj-$(CONFIG_PWM_LPC32XX_MOTOR) += pwm-lpc32xx-motor.o obj-$(CONFIG_PWM_MXS) += pwm-mxs.o obj-$(CONFIG_PWM_PXA) += pwm-pxa.o obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.odrivers/pwm/pwm-lpc32xx-motor.c new file +230
-0@@ -0,0 +1,230 @@ +/* +* Copyright 2012 Alban Bedel <[email protected]> +* +* Based on pwm-lpc32xx.c from Alexandre Pereira da Silva +* <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; version 2. +* +*/ + +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/platform_device.h> +#include <linux/pwm.h> +#include <linux/slab.h> + +struct lpc32xx_motor_pwm_chip { +struct pwm_chip chip; +struct clk *clk; +spinlock_t lock; +unsigned int clk_enabled; +unsigned int pins; +void __iomem *base; +}; + +#define to_lpc32xx_motor_pwm_chip (_chip) \ + container_of(_chip, struct lpc32xx_motor_pwm_chip, chip) + +/* Register mapping for MCPWM modules */ +#define LPC32XX_MCPWM_MCCON 0x00 +#define LPC32XX_MCPWM_MCCON_SET 0x04 +#define LPC32XX_MCPWM_MCCON_CLR 0x08 +#define LPC32XX_MCPWM_MCCAPCON 0x0C +#define LPC32XX_MCPWM_MCCAPCON_SET 0x10 +#define LPC32XX_MCPWM_MCCAPCON_CLR 0x14 +#define LPC32XX_MCPWM_MCLIM0 0x24 +#define LPC32XX_MCPWM_MCLIM1 0x28 +#define LPC32XX_MCPWM_MCLIM2 0x2C +#define LPC32XX_MCPWM_MCMAT0 0x30 +#define LPC32XX_MCPWM_MCMAT1 0x34 +#define LPC32XX_MCPWM_MCMAT2 0x38 +#define LPC32XX_MCPWM_MCINTEN_CLR 0x58 + +#define LPC32XX_MCPWM_COUNT 3 + +#define PWM_EN_MASK (pwm) BIT(0 + (pwm)->hwpwm*8) +#define MCLIM_REG_OFFSET (pwm) (LPC32XX_MCPWM_MCLIM0 + (pwm)->hwpwm*4) +#define MCMAT_REG_OFFSET (pwm) (LPC32XX_MCPWM_MCMAT0 + (pwm)->hwpwm*4) + +static int lpc32xx_motor_pwm_enable_clock ( +struct lpc32xx_motor_pwm_chip *lpc32xx) +{ +int err =0 ; +spin_lock (&lpc32xx->lock); +if (lpc32xx->clk_enabled ==0 ) + err =clk_enable (lpc32xx->clk); + lpc32xx->clk_enabled +=1 ; +spin_unlock (&lpc32xx->lock); +return err; +} + +static void lpc32xx_motor_pwm_disable_clock ( +struct lpc32xx_motor_pwm_chip *lpc32xx) +{ +spin_lock (&lpc32xx->lock); +if (lpc32xx->clk_enabled >0 ) { + lpc32xx->clk_enabled -=1 ; +if (lpc32xx->clk_enabled ==0 ) +clk_disable (lpc32xx->clk); + } +spin_unlock (&lpc32xx->lock); +} + +static int lpc32xx_motor_pwm_config (struct pwm_chip *chip, +struct pwm_device *pwm, +int duty_ns,int period_ns) +{ +struct lpc32xx_motor_pwm_chip *lpc32xx = +to_lpc32xx_motor_pwm_chip (chip); +u64 rate, per, duty; +int err =0 ; + +/* The clock is needed to access the registers */ + err =lpc32xx_motor_pwm_enable_clock (lpc32xx); +if (err) +return err; + +/* Calculate period */ + rate =clk_get_rate (lpc32xx->clk); + per = (u64 )period_ns * rate; + duty = (u64 )duty_ns * rate; +do_div (per,1000000000 ); +do_div (duty,1000000000 ); + +/* Write to limit register -> period */ +__raw_writel (per, lpc32xx->base +MCLIM_REG_OFFSET (pwm)); + +/* Write to match register -> duty */ +__raw_writel (per - duty, lpc32xx->base +MCMAT_REG_OFFSET (pwm)); + +/* Disable the clock now that we are done */ +lpc32xx_motor_pwm_disable_clock (lpc32xx); +return 0 ; +} + +static int lpc32xx_motor_pwm_enable (struct pwm_chip *chip, +struct pwm_device *pwm) +{ +struct lpc32xx_motor_pwm_chip *lpc32xx = +to_lpc32xx_motor_pwm_chip (chip); +int err; + + err =lpc32xx_motor_pwm_enable_clock (lpc32xx); +if (err) +return err; + +__raw_writel (PWM_EN_MASK (pwm), lpc32xx->base +LPC32XX_MCPWM_MCCON_SET ); + +return 0 ; +} + +static void lpc32xx_motor_pwm_disable (struct pwm_chip *chip, +struct pwm_device *pwm) +{ +struct lpc32xx_motor_pwm_chip *lpc32xx = +to_lpc32xx_motor_pwm_chip (chip); + +__raw_writel (PWM_EN_MASK (pwm), lpc32xx->base +LPC32XX_MCPWM_MCCON_CLR ); + +lpc32xx_motor_pwm_disable_clock (lpc32xx); +} + +static const struct pwm_ops lpc32xx_motor_pwm_ops = { + .config = lpc32xx_motor_pwm_config, + .enable = lpc32xx_motor_pwm_enable, + .disable = lpc32xx_motor_pwm_disable, + .owner =THIS_MODULE , +}; + +static int lpc32xx_motor_pwm_probe (struct platform_device *pdev) +{ +struct lpc32xx_motor_pwm_chip *lpc32xx; +struct resource *res; +int ret; + + lpc32xx =devm_kzalloc (&pdev->dev,sizeof (*lpc32xx),GFP_KERNEL ); +if (!lpc32xx) +return -ENOMEM ; + + res =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); +if (!res) +return -EINVAL ; + + lpc32xx->base =devm_request_and_ioremap (&pdev->dev, res); +if (!lpc32xx->base) +return -EADDRNOTAVAIL ; + + lpc32xx->clk =devm_clk_get (&pdev->dev,NULL ); +if (IS_ERR (lpc32xx->clk)) +return PTR_ERR (lpc32xx->clk); + +spin_lock_init (&lpc32xx->lock); + +/* Configure the pins polarity */ + ret =of_property_read_u32 (pdev->dev.of_node,"linux,polarity" , + &lpc32xx->pins); +if (!ret) { +u32 set =0 , clr =0 ; +int i; +for (i =0 ; i <LPC32XX_MCPWM_COUNT ; i +=1 ) +if (lpc32xx->pins &BIT (i)) + set |=BIT (2 + i*8 ); +else + clr |=BIT (2 + i*8 ); +__raw_writel (set, lpc32xx->base +LPC32XX_MCPWM_MCCON_SET ); +__raw_writel (clr, lpc32xx->base +LPC32XX_MCPWM_MCCON_CLR ); + } + + lpc32xx->chip.dev = &pdev->dev; + lpc32xx->chip.ops = &lpc32xx_motor_pwm_ops; + lpc32xx->chip.npwm =LPC32XX_MCPWM_COUNT ; + lpc32xx->chip.base =-1 ; + + ret =pwmchip_add (&lpc32xx->chip); +if (ret <0 ) { +dev_err (&pdev->dev,"failed to add PWM chip, error %d\n" , ret); +return ret; + } + +platform_set_drvdata (pdev, lpc32xx); + +return 0 ; +} + +static int __devexit lpc32xx_motor_pwm_remove(struct platform_device *pdev) +{ +struct lpc32xx_motor_pwm_chip *lpc32xx =platform_get_drvdata (pdev); + +clk_disable (lpc32xx->clk); +return pwmchip_remove (&lpc32xx->chip); +} + +static const struct of_device_id lpc32xx_motor_pwm_dt_ids[]__devinitconst = { + { .compatible ="nxp,lpc3220-motor-pwm" , }, + {/* sentinel */ } +}; +MODULE_DEVICE_TABLE (of, lpc32xx_motor_pwm_dt_ids); + +static struct platform_driver lpc32xx_motor_pwm_driver = { + .driver = { + .name ="lpc32xx-motor-pwm" , + .owner =THIS_MODULE , + .of_match_table =of_match_ptr (lpc32xx_motor_pwm_dt_ids), + }, + .probe = lpc32xx_motor_pwm_probe, + .remove =__devexit_p (lpc32xx_motor_pwm_remove), +}; +module_platform_driver (lpc32xx_motor_pwm_driver); + +MODULE_ALIAS ("platform:lpc32xx-motor-pwm" ); +MODULE_AUTHOR ("Alban Bedel <[email protected]>" ); +MODULE_DESCRIPTION ("LPC32XX Motor PWM Driver" ); +MODULE_LICENSE ("GPL v2" );
PATCH 1/1 pwm: lpc32xx - Add a driver for the motor PWM
Quoted 9 lines · Roland Stigge
Quoted 4 lines · Alban Bedel
Signed-off-by Alban Bedel <[email protected]>--- .../devicetree/bindings/pwm/lpc32xx-motor-pwm.txt | 24 ++ arch/arm/boot/dts/lpc32xx.dtsi | 7 +Is all this supposed to go via mach-lpc32xx -> arm-soc.git? Then, I can take this into the lpc32xx tree. Otherwise, you can split off the .dtsi file and I include it via lpc32xx.
I'd prefer a split between the arch/arm changes and the rest. I'll take the drivers/pwm and Documentation changes through the PWM tree.
Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20121107/61af1347/attachment.sig>
PATCH 1/1 pwm: lpc32xx - Add a driver for the motor PWM
Quoted 6 lines · Thierry Reding
Quoted 5 lines · Roland Stigge
Quoted 3 lines · Alban Bedel
Signed-off-by Alban Bedel <[email protected]> ---
.../devicetree/bindings/pwm/lpc32xx-motor-pwm.txt| 24 ++arch/arm/boot/dts/lpc32xx.dtsi| 7 +
Quoted 7 lines
Quoted 3 lines
Is all this supposed to go via mach-lpc32xx -> arm-soc.git? Then, I can take this into the lpc32xx tree. Otherwise, you can split off the .dtsi file and I include it via lpc32xx.
I'd prefer a split between the
arch/armchanges and the rest. I'll take thedrivers/pwmand Documentation changes through the PWM tree.
OK, I'll organize everything lpc32xx specific under arch/arm/
Thanks,
Roland
PATCH 1/1 pwm: lpc32xx - Add a driver for the motor PWM
Quoted 11 lines · Roland Stigge
Quoted 10 lines · Thierry Reding
Quoted 8 lines · Roland Stigge
Quoted 3 lines · Alban Bedel
Signed-off-by Alban Bedel <[email protected]> ---
.../devicetree/bindings/pwm/lpc32xx-motor-pwm.txt| 24 ++arch/arm/boot/dts/lpc32xx.dtsi| 7 +Is all this supposed to go via mach-lpc32xx -> arm-soc.git? Then, I can take this into the lpc32xx tree. Otherwise, you can split off the .dtsi file and I include it via lpc32xx.
Quoted 5 lines
Quoted 3 lines
I'd prefer a split between the
arch/armchanges and the rest. I'll take thedrivers/pwmand Documentation changes through the PWM tree.OK, I'll organize everything lpc32xx specific under
arch/arm/
Alban, I haven't finished reviewing yet, but once I'm done, can you resubmit a set of two patches split by arch/arm and the rest?
Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20121108/e75de120/attachment.sig>