Re: [PATCH 1/1] pwm: atmel: add Timer Counter Block PWM driver

2012-12-13 Thread Jean-Christophe PLAGNIOL-VILLARD
On 17:45 Thu 06 Dec , Boris BREZILLON wrote:
> Add TCB PWM driver.
> Add device tree binding.
> 
> Signed-off-by: Boris BREZILLON 
> --
>  create mode 100644 Documentation/devicetree/bindings/pwm/atmel-tcb-pwm.txt
>  create mode 100644 drivers/pwm/pwm-atmel-tcb.c
> 
> diff --git a/Documentation/devicetree/bindings/pwm/atmel-tcb-pwm.txt 
> b/Documentation/devicetree/bindings/pwm/atmel-tcb-pwm.txt
> new file mode 100644
> index 000..7644889
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/pwm/atmel-tcb-pwm.txt
> @@ -0,0 +1,15 @@
> +Atmel TCB PWM controller
> +
> +Required properties:
> +- compatible: should be "atmel,tcb-pwm"
> +- #pwm-cells: should be 2.  The first cell specifies the per-chip index
> +  of the PWM to use and the second cell is the period in nanoseconds.
> +- atmel,tc-block: the Timer Counter block to use as a PWM chip.
> +
> +Example:
> +
> +pwm: pwm@80064000 {
> + compatible = "fsl,imx28-pwm", "fsl,imx23-pwm";
are you sure?
> + #pwm-cells = <2>;
> + atmel,tc-block = <1>;
> +};
> diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
> index e513cd9..bda52f7 100644
> --- a/drivers/pwm/Kconfig
> +++ b/drivers/pwm/Kconfig
> @@ -37,6 +37,14 @@ config PWM_AB8500
> To compile this driver as a module, choose M here: the module
> will be called pwm-ab8500.
>  
> +config PWM_ATMEL_TCB
> + bool "TC Block PWM"
> + depends on ATMEL_TCLIB
> + select HAVE_PWM
> + default y
not default y
> + help
> +   Select this to get 6 PWM devices.
> +
>  config PWM_BFIN
>   tristate "Blackfin PWM support"
>   depends on BFIN_GPTIMERS
> diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
> index 62a2963..94ba21e 100644
> --- a/drivers/pwm/Makefile
> +++ b/drivers/pwm/Makefile
> @@ -1,5 +1,6 @@
>  obj-$(CONFIG_PWM)+= core.o
>  obj-$(CONFIG_PWM_AB8500) += pwm-ab8500.o
> +obj-$(CONFIG_PWM_ATMEL_TCB)  += pwm-atmel-tcb.o
>  obj-$(CONFIG_PWM_BFIN)   += pwm-bfin.o
>  obj-$(CONFIG_PWM_IMX)+= pwm-imx.o
>  obj-$(CONFIG_PWM_JZ4740) += pwm-jz4740.o
> diff --git a/drivers/pwm/pwm-atmel-tcb.c b/drivers/pwm/pwm-atmel-tcb.c
> new file mode 100644
> index 000..d5a87cc
> --- /dev/null
> +++ b/drivers/pwm/pwm-atmel-tcb.c
> @@ -0,0 +1,335 @@
> +/*
> + * Copyright (C) Overkiz SAS 2012
> + *
> + * Author: Boris BREZILLON 
> + * License terms: GNU General Public License (GPL) version 2
> + */
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +
> +#define NPWM 6
> +
> +struct atmel_tcb_pwm_device {
> + u8 polarity : 1;
> + u8 clk : 3;
no need to optimise that much
> + u32 duty;
> + u32 period;
> +};
> +
> +struct atmel_tcb_pwm_chip {
> + struct pwm_chip chip;
> + spinlock_t lock;
> + struct atmel_tc *tc;
> + struct atmel_tcb_pwm_device pwms[NPWM];
need to be aloocated
> +};
> +
> +static inline struct atmel_tcb_pwm_chip *to_atmel_tcb_pwm_chip(struct 
> pwm_chip *chip)
> +{
> + return container_of(chip, struct atmel_tcb_pwm_chip, chip);
> +}
> +
> +static int atmel_tcb_pwm_set_polarity (struct pwm_chip *chip, struct 
> pwm_device *pwm,
> +   enum pwm_polarity polarity)
> +{
> + struct atmel_tcb_pwm_device *tcbpwm =
> + (struct atmel_tcb_pwm_device *)pwm_get_chip_data(pwm);
> +
> + tcbpwm->polarity = polarity;
> +
> + return 0;
> +}
> +
> +static int atmel_tcb_pwm_request (struct pwm_chip *chip, struct pwm_device 
> *pwm)
> +{
> + struct atmel_tcb_pwm_chip *tcbpwmc = to_atmel_tcb_pwm_chip(chip);
> + struct atmel_tcb_pwm_device *tcbpwm = &(tcbpwmc->pwms[pwm->hwpwm]);
> + struct atmel_tc *tc = tcbpwmc->tc;
> + void __iomem *regs = tc->regs;
> + u32 reg;
> +
> + pwm_set_chip_data(pwm, tcbpwm);
> + tcbpwm->polarity = PWM_POLARITY_NORMAL;
> + tcbpwm->duty = 0;
> + tcbpwm->period = 0;
> + tcbpwm->clk = 0;
> + spin_lock(>lock);
> + reg = __raw_readl (regs + ATMEL_TC_REG(pwm->hwpwm / 2, CMR));
no space before (
> + if (reg & ATMEL_TC_WAVE) {
> + tcbpwm->duty = __raw_readl (regs + ((pwm->hwpwm % 2) ?
> + ATMEL_TC_REG(pwm->hwpwm / 2, RB) :
> + ATMEL_TC_REG(pwm->hwpwm / 2, RA)));
> +
> +
> + tcbpwm->clk = reg & ATMEL_TC_TCCLKS;
> + tcbpwm->period = __raw_readl (regs + ATMEL_TC_REG(pwm->hwpwm / 
> 2, RC));
> + reg &= (ATMEL_TC_TCCLKS |
> + ATMEL_TC_ACPA | ATMEL_TC_ACPC | ATMEL_TC_AEEVT 
> | ATMEL_TC_ASWTRG |
> + ATMEL_TC_BCPB | ATMEL_TC_BCPC | ATMEL_TC_BEEVT 
> | ATMEL_TC_BSWTRG);
> + }
> + else
> + reg = 0;
> + reg |= ATMEL_TC_WAVE | ATMEL_TC_WAVESEL_UP_AUTO | ATMEL_TC_EEVT_XC0;
> + __raw_writel (reg, regs + ATMEL_TC_REG(pwm->hwpwm / 

Re: [PATCH 1/1] pwm: atmel: add Timer Counter Block PWM driver

2012-12-13 Thread Jean-Christophe PLAGNIOL-VILLARD
On 17:45 Thu 06 Dec , Boris BREZILLON wrote:
 Add TCB PWM driver.
 Add device tree binding.
 
 Signed-off-by: Boris BREZILLON linux-...@overkiz.com
 --
  create mode 100644 Documentation/devicetree/bindings/pwm/atmel-tcb-pwm.txt
  create mode 100644 drivers/pwm/pwm-atmel-tcb.c
 
 diff --git a/Documentation/devicetree/bindings/pwm/atmel-tcb-pwm.txt 
 b/Documentation/devicetree/bindings/pwm/atmel-tcb-pwm.txt
 new file mode 100644
 index 000..7644889
 --- /dev/null
 +++ b/Documentation/devicetree/bindings/pwm/atmel-tcb-pwm.txt
 @@ -0,0 +1,15 @@
 +Atmel TCB PWM controller
 +
 +Required properties:
 +- compatible: should be atmel,tcb-pwm
 +- #pwm-cells: should be 2.  The first cell specifies the per-chip index
 +  of the PWM to use and the second cell is the period in nanoseconds.
 +- atmel,tc-block: the Timer Counter block to use as a PWM chip.
 +
 +Example:
 +
 +pwm: pwm@80064000 {
 + compatible = fsl,imx28-pwm, fsl,imx23-pwm;
are you sure?
 + #pwm-cells = 2;
 + atmel,tc-block = 1;
 +};
 diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
 index e513cd9..bda52f7 100644
 --- a/drivers/pwm/Kconfig
 +++ b/drivers/pwm/Kconfig
 @@ -37,6 +37,14 @@ config PWM_AB8500
 To compile this driver as a module, choose M here: the module
 will be called pwm-ab8500.
  
 +config PWM_ATMEL_TCB
 + bool TC Block PWM
 + depends on ATMEL_TCLIB
 + select HAVE_PWM
 + default y
not default y
 + help
 +   Select this to get 6 PWM devices.
 +
  config PWM_BFIN
   tristate Blackfin PWM support
   depends on BFIN_GPTIMERS
 diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
 index 62a2963..94ba21e 100644
 --- a/drivers/pwm/Makefile
 +++ b/drivers/pwm/Makefile
 @@ -1,5 +1,6 @@
  obj-$(CONFIG_PWM)+= core.o
  obj-$(CONFIG_PWM_AB8500) += pwm-ab8500.o
 +obj-$(CONFIG_PWM_ATMEL_TCB)  += pwm-atmel-tcb.o
  obj-$(CONFIG_PWM_BFIN)   += pwm-bfin.o
  obj-$(CONFIG_PWM_IMX)+= pwm-imx.o
  obj-$(CONFIG_PWM_JZ4740) += pwm-jz4740.o
 diff --git a/drivers/pwm/pwm-atmel-tcb.c b/drivers/pwm/pwm-atmel-tcb.c
 new file mode 100644
 index 000..d5a87cc
 --- /dev/null
 +++ b/drivers/pwm/pwm-atmel-tcb.c
 @@ -0,0 +1,335 @@
 +/*
 + * Copyright (C) Overkiz SAS 2012
 + *
 + * Author: Boris BREZILLON b.brezil...@overkiz.com
 + * License terms: GNU General Public License (GPL) version 2
 + */
 +#include linux/module.h
 +#include linux/init.h
 +#include linux/clocksource.h
 +#include linux/clockchips.h
 +#include linux/interrupt.h
 +#include linux/irq.h
 +
 +#include linux/clk.h
 +#include linux/err.h
 +#include linux/ioport.h
 +#include linux/io.h
 +#include linux/platform_device.h
 +#include linux/atmel_tc.h
 +#include linux/pwm.h
 +#include linux/of_device.h
 +#include linux/slab.h
 +
 +#define NPWM 6
 +
 +struct atmel_tcb_pwm_device {
 + u8 polarity : 1;
 + u8 clk : 3;
no need to optimise that much
 + u32 duty;
 + u32 period;
 +};
 +
 +struct atmel_tcb_pwm_chip {
 + struct pwm_chip chip;
 + spinlock_t lock;
 + struct atmel_tc *tc;
 + struct atmel_tcb_pwm_device pwms[NPWM];
need to be aloocated
 +};
 +
 +static inline struct atmel_tcb_pwm_chip *to_atmel_tcb_pwm_chip(struct 
 pwm_chip *chip)
 +{
 + return container_of(chip, struct atmel_tcb_pwm_chip, chip);
 +}
 +
 +static int atmel_tcb_pwm_set_polarity (struct pwm_chip *chip, struct 
 pwm_device *pwm,
 +   enum pwm_polarity polarity)
 +{
 + struct atmel_tcb_pwm_device *tcbpwm =
 + (struct atmel_tcb_pwm_device *)pwm_get_chip_data(pwm);
 +
 + tcbpwm-polarity = polarity;
 +
 + return 0;
 +}
 +
 +static int atmel_tcb_pwm_request (struct pwm_chip *chip, struct pwm_device 
 *pwm)
 +{
 + struct atmel_tcb_pwm_chip *tcbpwmc = to_atmel_tcb_pwm_chip(chip);
 + struct atmel_tcb_pwm_device *tcbpwm = (tcbpwmc-pwms[pwm-hwpwm]);
 + struct atmel_tc *tc = tcbpwmc-tc;
 + void __iomem *regs = tc-regs;
 + u32 reg;
 +
 + pwm_set_chip_data(pwm, tcbpwm);
 + tcbpwm-polarity = PWM_POLARITY_NORMAL;
 + tcbpwm-duty = 0;
 + tcbpwm-period = 0;
 + tcbpwm-clk = 0;
 + spin_lock(tcbpwmc-lock);
 + reg = __raw_readl (regs + ATMEL_TC_REG(pwm-hwpwm / 2, CMR));
no space before (
 + if (reg  ATMEL_TC_WAVE) {
 + tcbpwm-duty = __raw_readl (regs + ((pwm-hwpwm % 2) ?
 + ATMEL_TC_REG(pwm-hwpwm / 2, RB) :
 + ATMEL_TC_REG(pwm-hwpwm / 2, RA)));
 +
 +
 + tcbpwm-clk = reg  ATMEL_TC_TCCLKS;
 + tcbpwm-period = __raw_readl (regs + ATMEL_TC_REG(pwm-hwpwm / 
 2, RC));
 + reg = (ATMEL_TC_TCCLKS |
 + ATMEL_TC_ACPA | ATMEL_TC_ACPC | ATMEL_TC_AEEVT 
 | ATMEL_TC_ASWTRG |
 + ATMEL_TC_BCPB | ATMEL_TC_BCPC | ATMEL_TC_BEEVT 
 | ATMEL_TC_BSWTRG);
 + }
 + else
 + reg = 0;
 + reg |= ATMEL_TC_WAVE | ATMEL_TC_WAVESEL_UP_AUTO | 

[PATCH 1/1] pwm: atmel: add Timer Counter Block PWM driver

2012-12-06 Thread Boris BREZILLON
Add TCB PWM driver.
Add device tree binding.

Signed-off-by: Boris BREZILLON 
--
 create mode 100644 Documentation/devicetree/bindings/pwm/atmel-tcb-pwm.txt
 create mode 100644 drivers/pwm/pwm-atmel-tcb.c

diff --git a/Documentation/devicetree/bindings/pwm/atmel-tcb-pwm.txt 
b/Documentation/devicetree/bindings/pwm/atmel-tcb-pwm.txt
new file mode 100644
index 000..7644889
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/atmel-tcb-pwm.txt
@@ -0,0 +1,15 @@
+Atmel TCB PWM controller
+
+Required properties:
+- compatible: should be "atmel,tcb-pwm"
+- #pwm-cells: should be 2.  The first cell specifies the per-chip index
+  of the PWM to use and the second cell is the period in nanoseconds.
+- atmel,tc-block: the Timer Counter block to use as a PWM chip.
+
+Example:
+
+pwm: pwm@80064000 {
+   compatible = "fsl,imx28-pwm", "fsl,imx23-pwm";
+   #pwm-cells = <2>;
+   atmel,tc-block = <1>;
+};
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index e513cd9..bda52f7 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -37,6 +37,14 @@ config PWM_AB8500
  To compile this driver as a module, choose M here: the module
  will be called pwm-ab8500.
 
+config PWM_ATMEL_TCB
+   bool "TC Block PWM"
+   depends on ATMEL_TCLIB
+   select HAVE_PWM
+   default y
+   help
+ Select this to get 6 PWM devices.
+
 config PWM_BFIN
tristate "Blackfin PWM support"
depends on BFIN_GPTIMERS
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 62a2963..94ba21e 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -1,5 +1,6 @@
 obj-$(CONFIG_PWM)  += core.o
 obj-$(CONFIG_PWM_AB8500)   += pwm-ab8500.o
+obj-$(CONFIG_PWM_ATMEL_TCB)+= pwm-atmel-tcb.o
 obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o
 obj-$(CONFIG_PWM_IMX)  += pwm-imx.o
 obj-$(CONFIG_PWM_JZ4740)   += pwm-jz4740.o
diff --git a/drivers/pwm/pwm-atmel-tcb.c b/drivers/pwm/pwm-atmel-tcb.c
new file mode 100644
index 000..d5a87cc
--- /dev/null
+++ b/drivers/pwm/pwm-atmel-tcb.c
@@ -0,0 +1,335 @@
+/*
+ * Copyright (C) Overkiz SAS 2012
+ *
+ * Author: Boris BREZILLON 
+ * License terms: GNU General Public License (GPL) version 2
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define NPWM   6
+
+struct atmel_tcb_pwm_device {
+   u8 polarity : 1;
+   u8 clk : 3;
+   u32 duty;
+   u32 period;
+};
+
+struct atmel_tcb_pwm_chip {
+   struct pwm_chip chip;
+   spinlock_t lock;
+   struct atmel_tc *tc;
+   struct atmel_tcb_pwm_device pwms[NPWM];
+};
+
+static inline struct atmel_tcb_pwm_chip *to_atmel_tcb_pwm_chip(struct pwm_chip 
*chip)
+{
+   return container_of(chip, struct atmel_tcb_pwm_chip, chip);
+}
+
+static int atmel_tcb_pwm_set_polarity (struct pwm_chip *chip, struct 
pwm_device *pwm,
+ enum pwm_polarity polarity)
+{
+   struct atmel_tcb_pwm_device *tcbpwm =
+   (struct atmel_tcb_pwm_device *)pwm_get_chip_data(pwm);
+
+   tcbpwm->polarity = polarity;
+
+   return 0;
+}
+
+static int atmel_tcb_pwm_request (struct pwm_chip *chip, struct pwm_device 
*pwm)
+{
+   struct atmel_tcb_pwm_chip *tcbpwmc = to_atmel_tcb_pwm_chip(chip);
+   struct atmel_tcb_pwm_device *tcbpwm = &(tcbpwmc->pwms[pwm->hwpwm]);
+   struct atmel_tc *tc = tcbpwmc->tc;
+   void __iomem *regs = tc->regs;
+   u32 reg;
+
+   pwm_set_chip_data(pwm, tcbpwm);
+   tcbpwm->polarity = PWM_POLARITY_NORMAL;
+   tcbpwm->duty = 0;
+   tcbpwm->period = 0;
+   tcbpwm->clk = 0;
+   spin_lock(>lock);
+   reg = __raw_readl (regs + ATMEL_TC_REG(pwm->hwpwm / 2, CMR));
+   if (reg & ATMEL_TC_WAVE) {
+   tcbpwm->duty = __raw_readl (regs + ((pwm->hwpwm % 2) ?
+   ATMEL_TC_REG(pwm->hwpwm / 2, RB) :
+   ATMEL_TC_REG(pwm->hwpwm / 2, RA)));
+
+
+   tcbpwm->clk = reg & ATMEL_TC_TCCLKS;
+   tcbpwm->period = __raw_readl (regs + ATMEL_TC_REG(pwm->hwpwm / 
2, RC));
+   reg &= (ATMEL_TC_TCCLKS |
+   ATMEL_TC_ACPA | ATMEL_TC_ACPC | ATMEL_TC_AEEVT 
| ATMEL_TC_ASWTRG |
+   ATMEL_TC_BCPB | ATMEL_TC_BCPC | ATMEL_TC_BEEVT 
| ATMEL_TC_BSWTRG);
+   }
+   else
+   reg = 0;
+   reg |= ATMEL_TC_WAVE | ATMEL_TC_WAVESEL_UP_AUTO | ATMEL_TC_EEVT_XC0;
+   __raw_writel (reg, regs + ATMEL_TC_REG(pwm->hwpwm / 2, CMR));
+   spin_unlock(>lock);
+
+   clk_enable (tc->clk[pwm->hwpwm / 2]);
+
+   return 0;
+}
+
+static void atmel_tcb_pwm_free (struct pwm_chip *chip, struct pwm_device *pwm)
+{
+   struct atmel_tcb_pwm_chip *tcbpwmc = to_atmel_tcb_pwm_chip(chip);
+   struct atmel_tc *tc = tcbpwmc->tc;
+
+   clk_disable (tc->clk[pwm->hwpwm / 2]);

[PATCH 1/1] pwm: atmel: add Timer Counter Block PWM driver

2012-12-06 Thread Boris BREZILLON
Add TCB PWM driver.
Add device tree binding.

Signed-off-by: Boris BREZILLON linux-...@overkiz.com
--
 create mode 100644 Documentation/devicetree/bindings/pwm/atmel-tcb-pwm.txt
 create mode 100644 drivers/pwm/pwm-atmel-tcb.c

diff --git a/Documentation/devicetree/bindings/pwm/atmel-tcb-pwm.txt 
b/Documentation/devicetree/bindings/pwm/atmel-tcb-pwm.txt
new file mode 100644
index 000..7644889
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/atmel-tcb-pwm.txt
@@ -0,0 +1,15 @@
+Atmel TCB PWM controller
+
+Required properties:
+- compatible: should be atmel,tcb-pwm
+- #pwm-cells: should be 2.  The first cell specifies the per-chip index
+  of the PWM to use and the second cell is the period in nanoseconds.
+- atmel,tc-block: the Timer Counter block to use as a PWM chip.
+
+Example:
+
+pwm: pwm@80064000 {
+   compatible = fsl,imx28-pwm, fsl,imx23-pwm;
+   #pwm-cells = 2;
+   atmel,tc-block = 1;
+};
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index e513cd9..bda52f7 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -37,6 +37,14 @@ config PWM_AB8500
  To compile this driver as a module, choose M here: the module
  will be called pwm-ab8500.
 
+config PWM_ATMEL_TCB
+   bool TC Block PWM
+   depends on ATMEL_TCLIB
+   select HAVE_PWM
+   default y
+   help
+ Select this to get 6 PWM devices.
+
 config PWM_BFIN
tristate Blackfin PWM support
depends on BFIN_GPTIMERS
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 62a2963..94ba21e 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -1,5 +1,6 @@
 obj-$(CONFIG_PWM)  += core.o
 obj-$(CONFIG_PWM_AB8500)   += pwm-ab8500.o
+obj-$(CONFIG_PWM_ATMEL_TCB)+= pwm-atmel-tcb.o
 obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o
 obj-$(CONFIG_PWM_IMX)  += pwm-imx.o
 obj-$(CONFIG_PWM_JZ4740)   += pwm-jz4740.o
diff --git a/drivers/pwm/pwm-atmel-tcb.c b/drivers/pwm/pwm-atmel-tcb.c
new file mode 100644
index 000..d5a87cc
--- /dev/null
+++ b/drivers/pwm/pwm-atmel-tcb.c
@@ -0,0 +1,335 @@
+/*
+ * Copyright (C) Overkiz SAS 2012
+ *
+ * Author: Boris BREZILLON b.brezil...@overkiz.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+#include linux/module.h
+#include linux/init.h
+#include linux/clocksource.h
+#include linux/clockchips.h
+#include linux/interrupt.h
+#include linux/irq.h
+
+#include linux/clk.h
+#include linux/err.h
+#include linux/ioport.h
+#include linux/io.h
+#include linux/platform_device.h
+#include linux/atmel_tc.h
+#include linux/pwm.h
+#include linux/of_device.h
+#include linux/slab.h
+
+#define NPWM   6
+
+struct atmel_tcb_pwm_device {
+   u8 polarity : 1;
+   u8 clk : 3;
+   u32 duty;
+   u32 period;
+};
+
+struct atmel_tcb_pwm_chip {
+   struct pwm_chip chip;
+   spinlock_t lock;
+   struct atmel_tc *tc;
+   struct atmel_tcb_pwm_device pwms[NPWM];
+};
+
+static inline struct atmel_tcb_pwm_chip *to_atmel_tcb_pwm_chip(struct pwm_chip 
*chip)
+{
+   return container_of(chip, struct atmel_tcb_pwm_chip, chip);
+}
+
+static int atmel_tcb_pwm_set_polarity (struct pwm_chip *chip, struct 
pwm_device *pwm,
+ enum pwm_polarity polarity)
+{
+   struct atmel_tcb_pwm_device *tcbpwm =
+   (struct atmel_tcb_pwm_device *)pwm_get_chip_data(pwm);
+
+   tcbpwm-polarity = polarity;
+
+   return 0;
+}
+
+static int atmel_tcb_pwm_request (struct pwm_chip *chip, struct pwm_device 
*pwm)
+{
+   struct atmel_tcb_pwm_chip *tcbpwmc = to_atmel_tcb_pwm_chip(chip);
+   struct atmel_tcb_pwm_device *tcbpwm = (tcbpwmc-pwms[pwm-hwpwm]);
+   struct atmel_tc *tc = tcbpwmc-tc;
+   void __iomem *regs = tc-regs;
+   u32 reg;
+
+   pwm_set_chip_data(pwm, tcbpwm);
+   tcbpwm-polarity = PWM_POLARITY_NORMAL;
+   tcbpwm-duty = 0;
+   tcbpwm-period = 0;
+   tcbpwm-clk = 0;
+   spin_lock(tcbpwmc-lock);
+   reg = __raw_readl (regs + ATMEL_TC_REG(pwm-hwpwm / 2, CMR));
+   if (reg  ATMEL_TC_WAVE) {
+   tcbpwm-duty = __raw_readl (regs + ((pwm-hwpwm % 2) ?
+   ATMEL_TC_REG(pwm-hwpwm / 2, RB) :
+   ATMEL_TC_REG(pwm-hwpwm / 2, RA)));
+
+
+   tcbpwm-clk = reg  ATMEL_TC_TCCLKS;
+   tcbpwm-period = __raw_readl (regs + ATMEL_TC_REG(pwm-hwpwm / 
2, RC));
+   reg = (ATMEL_TC_TCCLKS |
+   ATMEL_TC_ACPA | ATMEL_TC_ACPC | ATMEL_TC_AEEVT 
| ATMEL_TC_ASWTRG |
+   ATMEL_TC_BCPB | ATMEL_TC_BCPC | ATMEL_TC_BEEVT 
| ATMEL_TC_BSWTRG);
+   }
+   else
+   reg = 0;
+   reg |= ATMEL_TC_WAVE | ATMEL_TC_WAVESEL_UP_AUTO | ATMEL_TC_EEVT_XC0;
+   __raw_writel (reg, regs + ATMEL_TC_REG(pwm-hwpwm / 2, CMR));
+   spin_unlock(tcbpwmc-lock);
+
+   clk_enable (tc-clk[pwm-hwpwm / 2]);
+
+   return 0;
+}
+
+static void