diff options
-rw-r--r-- | package/pwm-gpio-custom/Makefile | 54 | ||||
-rw-r--r-- | package/pwm-gpio-custom/src/Kconfig | 4 | ||||
-rw-r--r-- | package/pwm-gpio-custom/src/Makefile | 1 | ||||
-rw-r--r-- | package/pwm-gpio-custom/src/pwm-gpio-custom.c | 218 | ||||
-rw-r--r-- | target/linux/at91/modules.mk | 7 | ||||
-rw-r--r-- | target/linux/generic/files/drivers/pwm/Kconfig | 11 | ||||
-rw-r--r-- | target/linux/generic/files/drivers/pwm/Makefile | 1 | ||||
-rw-r--r-- | target/linux/generic/files/drivers/pwm/atmel-pwm.c | 592 | ||||
-rw-r--r-- | target/linux/generic/patches-3.3/865-gpiopwm.patch | 25 |
9 files changed, 28 insertions, 885 deletions
diff --git a/package/pwm-gpio-custom/Makefile b/package/pwm-gpio-custom/Makefile deleted file mode 100644 index 24cf096eb2..0000000000 --- a/package/pwm-gpio-custom/Makefile +++ /dev/null @@ -1,54 +0,0 @@ -# -# Copyright (C) 2010 OpenWrt.org -# -# This is free software, licensed under the GNU General Public License v2. -# See /LICENSE for more information. -# - -include $(TOPDIR)/rules.mk -include $(INCLUDE_DIR)/kernel.mk - -PKG_NAME:=pwm-gpio-custom -PKG_RELEASE:=1 - -include $(INCLUDE_DIR)/package.mk - -define KernelPackage/pwm-gpio-custom - SUBMENU:=Other modules - TITLE:=Custom GPIO-based PWM device - DEPENDS:=+kmod-pwm-gpio - FILES:=$(PKG_BUILD_DIR)/pwm-gpio-custom.ko - KCONFIG:= -endef - -define KernelPackage/pwm-gpio-custom/description - Kernel module to register a custom pwm-gpio platform device. -endef - -EXTRA_KCONFIG:= \ - CONFIG_PWM_GPIO_CUSTOM=m - -EXTRA_CFLAGS:= \ - $(patsubst CONFIG_%, -DCONFIG_%=1, $(patsubst %=m,%,$(filter %=m,$(EXTRA_KCONFIG)))) \ - $(patsubst CONFIG_%, -DCONFIG_%=1, $(patsubst %=y,%,$(filter %=y,$(EXTRA_KCONFIG)))) - -MAKE_OPTS:= \ - ARCH="$(LINUX_KARCH)" \ - CROSS_COMPILE="$(TARGET_CROSS)" \ - SUBDIRS="$(PKG_BUILD_DIR)" \ - EXTRA_CFLAGS="$(EXTRA_CFLAGS)" \ - $(EXTRA_KCONFIG) - -define Build/Prepare - mkdir -p $(PKG_BUILD_DIR) - $(CP) ./src/* $(PKG_BUILD_DIR)/ -endef - -define Build/Compile - $(MAKE) -C "$(LINUX_DIR)" \ - $(MAKE_OPTS) \ - modules -endef - -$(eval $(call KernelPackage,pwm-gpio-custom)) - diff --git a/package/pwm-gpio-custom/src/Kconfig b/package/pwm-gpio-custom/src/Kconfig deleted file mode 100644 index be417ba3c0..0000000000 --- a/package/pwm-gpio-custom/src/Kconfig +++ /dev/null @@ -1,4 +0,0 @@ -config PWM_MASTER_GPIO_CUSTOM - tristate "Custom GPIO-based PWM driver" - depends on GENERIC_GPIO - select PWM_GENERIC_GPIO diff --git a/package/pwm-gpio-custom/src/Makefile b/package/pwm-gpio-custom/src/Makefile deleted file mode 100644 index cc84e8ec4f..0000000000 --- a/package/pwm-gpio-custom/src/Makefile +++ /dev/null @@ -1 +0,0 @@ -obj-${CONFIG_PWM_GPIO_CUSTOM} += pwm-gpio-custom.o diff --git a/package/pwm-gpio-custom/src/pwm-gpio-custom.c b/package/pwm-gpio-custom/src/pwm-gpio-custom.c deleted file mode 100644 index 3a4d5b754a..0000000000 --- a/package/pwm-gpio-custom/src/pwm-gpio-custom.c +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Custom GPIO-based PWM driver - * - * Based on w1-gpio-custom by Copyright (C) 2007 Gabor Juhos <juhosg at openwrt.org> - * Copyright (C) 2010 Claudio Mignanti <c.mignanti@gmail.com > - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * --------------------------------------------------------------------------- - * - * The behaviour of this driver can be altered by setting some parameters - * from the insmod command line. - * - * The following parameters are adjustable: - * - * bus0 These four arguments must be arrays - * bus1 - * ..... - * bus10 <id>,<pin>,<od> - * - * where: - * - * <id> ID to used as device_id for the corresponding bus (required) - * <pin> GPIO pin ID for PWM channel (required) - * * - * If this driver is built into the kernel, you can use the following kernel - * command line parameters, with the same values as the corresponding module - * parameters listed above: - * - * pwm-gpio-custom.bus0 - * pwm-gpio-custom.bus1 - * pwm-gpio-custom.bunN - * pwm-gpio-custom.bus10 - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/platform_device.h> -#include <linux/workqueue.h> - -#include <linux/pwm/pwm.h> - -#define DRV_NAME "pwm-gpio-custom" -#define DRV_DESC "Custom GPIO-based pwm driver" -#define DRV_VERSION "0.1.0" - -#define PFX DRV_NAME ": " - -#define BUS_PARAM_ID 0 -#define BUS_PARAM_PIN 1 - -#define BUS_PARAM_REQUIRED 2 -#define BUS_PARAM_COUNT 2 -#define BUS_COUNT_MAX 10 - -static unsigned int bus0[BUS_PARAM_COUNT] __initdata; -static unsigned int bus1[BUS_PARAM_COUNT] __initdata; -static unsigned int bus2[BUS_PARAM_COUNT] __initdata; -static unsigned int bus3[BUS_PARAM_COUNT] __initdata; -static unsigned int bus4[BUS_PARAM_COUNT] __initdata; -static unsigned int bus5[BUS_PARAM_COUNT] __initdata; -static unsigned int bus6[BUS_PARAM_COUNT] __initdata; -static unsigned int bus7[BUS_PARAM_COUNT] __initdata; -static unsigned int bus8[BUS_PARAM_COUNT] __initdata; -static unsigned int bus9[BUS_PARAM_COUNT] __initdata; - -static unsigned int bus_nump[BUS_COUNT_MAX] __initdata; - -#define BUS_PARM_DESC " config -> id,pin" - -module_param_array(bus0, uint, &bus_nump[0], 0); -MODULE_PARM_DESC(bus0, "bus0" BUS_PARM_DESC); -module_param_array(bus1, uint, &bus_nump[1], 0); -MODULE_PARM_DESC(bus1, "bus1" BUS_PARM_DESC); -module_param_array(bus2, uint, &bus_nump[2], 0); -MODULE_PARM_DESC(bus2, "bus2" BUS_PARM_DESC); -module_param_array(bus3, uint, &bus_nump[3], 0); -MODULE_PARM_DESC(bus3, "bus3" BUS_PARM_DESC); -module_param_array(bus4, uint, &bus_nump[4], 0); -MODULE_PARM_DESC(bus4, "bus4" BUS_PARM_DESC); -module_param_array(bus5, uint, &bus_nump[5], 0); -MODULE_PARM_DESC(bus5, "bus5" BUS_PARM_DESC); -module_param_array(bus6, uint, &bus_nump[6], 0); -MODULE_PARM_DESC(bus6, "bus6" BUS_PARM_DESC); -module_param_array(bus7, uint, &bus_nump[7], 0); -MODULE_PARM_DESC(bus7, "bus7" BUS_PARM_DESC); -module_param_array(bus8, uint, &bus_nump[8], 0); -MODULE_PARM_DESC(bus8, "bus8" BUS_PARM_DESC); -module_param_array(bus9, uint, &bus_nump[9], 0); -MODULE_PARM_DESC(bus9, "bus9" BUS_PARM_DESC); - -static struct platform_device *devices[BUS_COUNT_MAX]; -static unsigned int nr_devices; - -static void pwm_gpio_custom_cleanup(void) -{ - int i; - - for (i = 0; i < nr_devices; i++) - if (devices[i]) - platform_device_put(devices[i]); -} - -static int __init pwm_gpio_custom_add_one(unsigned int id, unsigned int *params) -{ - struct platform_device *pdev; - struct gpio_pwm_platform_data pdata; - int err; - - if (!bus_nump[id]) - return 0; - - if (bus_nump[id] < BUS_PARAM_REQUIRED) { - printk(KERN_ERR PFX "not enough parameters for bus%d\n", id); - err = -EINVAL; - goto err; - } - - pdev = platform_device_alloc("gpio_pwm", params[BUS_PARAM_ID]); - if (!pdev) { - err = -ENOMEM; - goto err; - } - - pdata.gpio = params[BUS_PARAM_PIN]; - - err = platform_device_add_data(pdev, &pdata, sizeof(pdata)); - if (err) - goto err_put; - - err = platform_device_add(pdev); - if (err) - goto err_put; - - devices[nr_devices++] = pdev; - return 0; - - err_put: - platform_device_put(pdev); - err: - return err; -} - -static int __init pwm_gpio_custom_probe(void) -{ - int err; - - nr_devices = 0; - printk(KERN_INFO DRV_DESC " version " DRV_VERSION "\n"); - - err = pwm_gpio_custom_add_one(0, bus0); - if (err) goto err; - - err = pwm_gpio_custom_add_one(1, bus1); - if (err) goto err; - - err = pwm_gpio_custom_add_one(2, bus2); - if (err) goto err; - - err = pwm_gpio_custom_add_one(3, bus3); - if (err) goto err; - - err = pwm_gpio_custom_add_one(4, bus4); - if (err) goto err; - - err = pwm_gpio_custom_add_one(5, bus5); - if (err) goto err; - - err = pwm_gpio_custom_add_one(6, bus6); - if (err) goto err; - - err = pwm_gpio_custom_add_one(7, bus7); - if (err) goto err; - - err = pwm_gpio_custom_add_one(8, bus8); - if (err) goto err; - - err = pwm_gpio_custom_add_one(9, bus9); - if (err) goto err; - - if (!nr_devices) { - printk(KERN_ERR PFX "no bus parameter(s) specified\n"); - err = -ENODEV; - goto err; - } - - return 0; - -err: - pwm_gpio_custom_cleanup(); - return err; -} - -#ifdef MODULE -static int __init pwm_gpio_custom_init(void) -{ - return pwm_gpio_custom_probe(); -} -module_init(pwm_gpio_custom_init); - -static void __exit pwm_gpio_custom_exit(void) -{ - pwm_gpio_custom_cleanup(); -} -module_exit(pwm_gpio_custom_exit); -#else -subsys_initcall(pwm_gpio_custom_probe); -#endif /* MODULE*/ - -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("Bifferos <bifferos at yahoo.co.uk >"); -MODULE_AUTHOR("Claudio Mignanti <c.mignanti@gmail.com >"); -MODULE_DESCRIPTION(DRV_DESC); -MODULE_VERSION(DRV_VERSION); - diff --git a/target/linux/at91/modules.mk b/target/linux/at91/modules.mk index 0c6c03ab59..9c8ef3d5a8 100644 --- a/target/linux/at91/modules.mk +++ b/target/linux/at91/modules.mk @@ -24,10 +24,9 @@ define KernelPackage/pwm-atmel SUBMENU:=$(OTHER_MENU) TITLE:=PWM on atmel SoC DEPENDS:=@TARGET_at91 - KCONFIG:=CONFIG_GENERIC_PWM \ - CONFIG_ATMEL_PWM - FILES:=$(LINUX_DIR)/drivers/pwm/atmel-pwm.ko - AUTOLOAD:=$(call AutoLoad,51,atmel-pwm) + KCONFIG:=CONFIG_ATMEL_PWM + FILES:=$(LINUX_DIR)/drivers/misc/atmel_pwm.ko + AUTOLOAD:=$(call AutoLoad,51,atmel_pwm) endef define KernelPackage/pwm-atmel/description diff --git a/target/linux/generic/files/drivers/pwm/Kconfig b/target/linux/generic/files/drivers/pwm/Kconfig index 1c24e11077..70f4442eab 100644 --- a/target/linux/generic/files/drivers/pwm/Kconfig +++ b/target/linux/generic/files/drivers/pwm/Kconfig @@ -11,17 +11,6 @@ menuconfig GENERIC_PWM if GENERIC_PWM -config ATMEL_PWM - tristate "Atmel AT32/AT91 PWM support" - depends on AVR32 || ARCH_AT91 - help - This option enables device driver support for the PWMC - peripheral channels found on certain Atmel processors. - Pulse Width Modulation is used many for purposes, including - software controlled power-efficient backlights on LCD - displays, motor control, and waveform generation. If - unsure, say N. - config GPIO_PWM tristate "PWM emulation using GPIO" help diff --git a/target/linux/generic/files/drivers/pwm/Makefile b/target/linux/generic/files/drivers/pwm/Makefile index af22041bf2..3a0e996744 100644 --- a/target/linux/generic/files/drivers/pwm/Makefile +++ b/target/linux/generic/files/drivers/pwm/Makefile @@ -2,5 +2,4 @@ # Makefile for pwm devices # obj-$(CONFIG_GENERIC_PWM) := pwm.o -obj-$(CONFIG_ATMEL_PWM) += atmel-pwm.o obj-$(CONFIG_GPIO_PWM) += gpio-pwm.o diff --git a/target/linux/generic/files/drivers/pwm/atmel-pwm.c b/target/linux/generic/files/drivers/pwm/atmel-pwm.c deleted file mode 100644 index 158bb922c1..0000000000 --- a/target/linux/generic/files/drivers/pwm/atmel-pwm.c +++ /dev/null @@ -1,592 +0,0 @@ -/* - * drivers/pwm/atmel-pwm.c - * - * Copyright (C) 2010 Bill Gatliff <bgat@billgatliff.com> - * Copyright (C) 2007 David Brownell - * - * This program is free software; you may redistribute and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA - */ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/clk.h> -#include <linux/err.h> -#include <linux/io.h> -#include <linux/interrupt.h> -#include <linux/platform_device.h> -#include <linux/slab.h> -#include <linux/pwm/pwm.h> - -enum { - /* registers common to the PWMC peripheral */ - PWMC_MR = 0, - PWMC_ENA = 4, - PWMC_DIS = 8, - PWMC_SR = 0xc, - PWMC_IER = 0x10, - PWMC_IDR = 0x14, - PWMC_IMR = 0x18, - PWMC_ISR = 0x1c, - - /* registers per each PWMC channel */ - PWMC_CMR = 0, - PWMC_CDTY = 4, - PWMC_CPRD = 8, - PWMC_CCNT = 0xc, - PWMC_CUPD = 0x10, - - /* how to find each channel */ - PWMC_CHAN_BASE = 0x200, - PWMC_CHAN_STRIDE = 0x20, - - /* CMR bits of interest */ - PWMC_CMR_CPD = 10, - PWMC_CMR_CPOL = 9, - PWMC_CMR_CALG = 8, - PWMC_CMR_CPRE_MASK = 0xf, -}; - -struct atmel_pwm { - struct pwm_device pwm; - spinlock_t lock; - void __iomem *iobase; - struct clk *clk; - u32 *sync_mask; - int irq; - u32 ccnt_mask; -}; - -static inline struct atmel_pwm *to_atmel_pwm(const struct pwm_channel *p) -{ - return container_of(p->pwm, struct atmel_pwm, pwm); -} - -static inline void -pwmc_writel(const struct atmel_pwm *p, - unsigned offset, u32 val) -{ - __raw_writel(val, p->iobase + offset); -} - -static inline u32 -pwmc_readl(const struct atmel_pwm *p, - unsigned offset) -{ - return __raw_readl(p->iobase + offset); -} - -static inline void -pwmc_chan_writel(const struct pwm_channel *p, - u32 offset, u32 val) -{ - const struct atmel_pwm *ap = to_atmel_pwm(p); - - if (PWMC_CMR == offset) - val &= ((1 << PWMC_CMR_CPD) - | (1 << PWMC_CMR_CPOL) - | (1 << PWMC_CMR_CALG) - | (PWMC_CMR_CPRE_MASK)); - else - val &= ap->ccnt_mask; - - pwmc_writel(ap, offset + PWMC_CHAN_BASE - + (p->chan * PWMC_CHAN_STRIDE), val); -} - -static inline u32 -pwmc_chan_readl(const struct pwm_channel *p, - u32 offset) -{ - const struct atmel_pwm *ap = to_atmel_pwm(p); - - return pwmc_readl(ap, offset + PWMC_CHAN_BASE - + (p->chan * PWMC_CHAN_STRIDE)); -} - -static inline int -__atmel_pwm_is_on(struct pwm_channel *p) -{ - struct atmel_pwm *ap = to_atmel_pwm(p); - return (pwmc_readl(ap, PWMC_SR) & (1 << p->chan)) ? 1 : 0; -} - -static inline void -__atmel_pwm_unsynchronize(struct pwm_channel *p, - struct pwm_channel *to_p) -{ - const struct atmel_pwm *ap = to_atmel_pwm(p); - int wchan; - - if (to_p) { - ap->sync_mask[p->chan] &= ~(1 << to_p->chan); - ap->sync_mask[to_p->chan] &= ~(1 << p->chan); - goto done; - } - - ap->sync_mask[p->chan] = 0; - for (wchan = 0; wchan < ap->pwm.nchan; wchan++) - ap->sync_mask[wchan] &= ~(1 << p->chan); -done: - dev_dbg(p->pwm->dev, "sync_mask %x\n", ap->sync_mask[p->chan]); -} - -static inline void -__atmel_pwm_synchronize(struct pwm_channel *p, - struct pwm_channel *to_p) -{ - const struct atmel_pwm *ap = to_atmel_pwm(p); - - if (!to_p) - return; - - ap->sync_mask[p->chan] |= (1 << to_p->chan); - ap->sync_mask[to_p->chan] |= (1 << p->chan); - - dev_dbg(p->pwm->dev, "sync_mask %x\n", ap->sync_mask[p->chan]); -} - -static inline void -__atmel_pwm_stop(struct pwm_channel *p) -{ - struct atmel_pwm *ap = to_atmel_pwm(p); - u32 chid = 1 << p->chan; - - pwmc_writel(ap, PWMC_DIS, ap->sync_mask[p->chan] | chid); -} - -static inline void -__atmel_pwm_start(struct pwm_channel *p) -{ - struct atmel_pwm *ap = to_atmel_pwm(p); - u32 chid = 1 << p->chan; - - pwmc_writel(ap, PWMC_ENA, ap->sync_mask[p->chan] | chid); -} - -static int -atmel_pwm_synchronize(struct pwm_channel *p, - struct pwm_channel *to_p) -{ - unsigned long flags; - spin_lock_irqsave(&p->lock, flags); - __atmel_pwm_synchronize(p, to_p); - spin_unlock_irqrestore(&p->lock, flags); - return 0; -} - -static int -atmel_pwm_unsynchronize(struct pwm_channel *p, - struct pwm_channel *from_p) -{ - unsigned long flags; - spin_lock_irqsave(&p->lock, flags); - __atmel_pwm_unsynchronize(p, from_p); - spin_unlock_irqrestore(&p->lock, flags); - return 0; -} - -static inline int -__atmel_pwm_config_polarity(struct pwm_channel *p, - struct pwm_channel_config *c) -{ - u32 cmr = pwmc_chan_readl(p, PWMC_CMR); - - if (c->polarity) - cmr &= ~BIT(PWMC_CMR_CPOL); - else - cmr |= BIT(PWMC_CMR_CPOL); - pwmc_chan_writel(p, PWMC_CMR, cmr); - p->active_high = c->polarity ? 1 : 0; - - dev_dbg(p->pwm->dev, "polarity %d\n", c->polarity); - return 0; -} - -static inline int -__atmel_pwm_config_duty_ticks(struct pwm_channel *p, - struct pwm_channel_config *c) -{ - u32 cmr, cprd, cpre, cdty; - - cmr = pwmc_chan_readl(p, PWMC_CMR); - cprd = pwmc_chan_readl(p, PWMC_CPRD); - - cpre = cmr & PWMC_CMR_CPRE_MASK; - cmr &= ~BIT(PWMC_CMR_CPD); - - cdty = cprd - (c->duty_ticks >> cpre); - - p->duty_ticks = c->duty_ticks; - - if (__atmel_pwm_is_on(p)) { - pwmc_chan_writel(p, PWMC_CMR, cmr); - pwmc_chan_writel(p, PWMC_CUPD, cdty); - } else - pwmc_chan_writel(p, PWMC_CDTY, cdty); - - dev_dbg(p->pwm->dev, "duty_ticks = %lu cprd = %x" - " cdty = %x cpre = %x\n", p->duty_ticks, - cprd, cdty, cpre); - - return 0; -} - -static inline int -__atmel_pwm_config_period_ticks(struct pwm_channel *p, - struct pwm_channel_config *c) -{ - u32 cmr, cprd, cpre; - - cpre = fls(c->period_ticks); - if (cpre < 16) - cpre = 0; - else { - cpre -= 15; - if (cpre > 10) - return -EINVAL; - } - - cmr = pwmc_chan_readl(p, PWMC_CMR); - cmr &= ~PWMC_CMR_CPRE_MASK; - cmr |= cpre; - - cprd = c->period_ticks >> cpre; - - pwmc_chan_writel(p, PWMC_CMR, cmr); - pwmc_chan_writel(p, PWMC_CPRD, cprd); - p->period_ticks = c->period_ticks; - - dev_dbg(p->pwm->dev, "period_ticks = %lu cprd = %x cpre = %x\n", - p->period_ticks, cprd, cpre); - - return 0; -} - -static int -atmel_pwm_config_nosleep(struct pwm_channel *p, - struct pwm_channel_config *c) -{ - int ret = 0; - unsigned long flags; - - spin_lock_irqsave(&p->lock, flags); - - switch (c->config_mask) { - - case PWM_CONFIG_DUTY_TICKS: - __atmel_pwm_config_duty_ticks(p, c); - break; - - case PWM_CONFIG_STOP: - __atmel_pwm_stop(p); - break; - - case PWM_CONFIG_START: - __atmel_pwm_start(p); - break; - - case PWM_CONFIG_POLARITY: - __atmel_pwm_config_polarity(p, c); - break; - - default: - ret = -EINVAL; - break; - } - - spin_unlock_irqrestore(&p->lock, flags); - return ret; -} - -static int -atmel_pwm_stop_sync(struct pwm_channel *p) -{ - struct atmel_pwm *ap = container_of(p->pwm, struct atmel_pwm, pwm); - int ret; - int was_on = __atmel_pwm_is_on(p); - - if (was_on) { - do { - init_completion(&p->complete); - set_bit(FLAG_STOP, &p->flags); - pwmc_writel(ap, PWMC_IER, 1 << p->chan); - - dev_dbg(p->pwm->dev, "waiting on stop_sync completion...\n"); - - ret = wait_for_completion_interruptible(&p->complete); - - dev_dbg(p->pwm->dev, "stop_sync complete (%d)\n", ret); - - if (ret) - return ret; - } while (p->flags & BIT(FLAG_STOP)); - } - - return was_on; -} - -static int -atmel_pwm_config(struct pwm_channel *p, - struct pwm_channel_config *c) -{ - int was_on = 0; - - if (p->pwm->config_nosleep) { - if (!p->pwm->config_nosleep(p, c)) - return 0; - } - - might_sleep(); - - dev_dbg(p->pwm->dev, "config_mask %x\n", c->config_mask); - - was_on = atmel_pwm_stop_sync(p); - if (was_on < 0) - return was_on; - - if (c->config_mask & PWM_CONFIG_PERIOD_TICKS) { - __atmel_pwm_config_period_ticks(p, c); - if (!(c->config_mask & PWM_CONFIG_DUTY_TICKS)) { - struct pwm_channel_config d = { - .config_mask = PWM_CONFIG_DUTY_TICKS, - .duty_ticks = p->duty_ticks, - }; - __atmel_pwm_config_duty_ticks(p, &d); - } - } - - if (c->config_mask & PWM_CONFIG_DUTY_TICKS) - __atmel_pwm_config_duty_ticks(p, c); - - if (c->config_mask & PWM_CONFIG_POLARITY) - __atmel_pwm_config_polarity(p, c); - - if ((c->config_mask & PWM_CONFIG_START) - || (was_on && !(c->config_mask & PWM_CONFIG_STOP))) - __atmel_pwm_start(p); - - return 0; -} - -static void -__atmel_pwm_set_callback(struct pwm_channel *p, - pwm_callback_t callback) -{ - struct atmel_pwm *ap = container_of(p->pwm, struct atmel_pwm, pwm); - - p->callback = callback; - pwmc_writel(ap, p->callback ? PWMC_IER : PWMC_IDR, 1 << p->chan); -} - -static int -atmel_pwm_set_callback(struct pwm_channel *p, - pwm_callback_t callback) -{ - struct atmel_pwm *ap = to_atmel_pwm(p); - unsigned long flags; - - spin_lock_irqsave(&ap->lock, flags); - __atmel_pwm_set_callback(p, callback); - spin_unlock_irqrestore(&ap->lock, flags); - - return 0; -} - -static int -atmel_pwm_request(struct pwm_channel *p) -{ - struct atmel_pwm *ap = to_atmel_pwm(p); - unsigned long flags; - - spin_lock_irqsave(&p->lock, flags); - clk_enable(ap->clk); - p->tick_hz = clk_get_rate(ap->clk); - __atmel_pwm_unsynchronize(p, NULL); - __atmel_pwm_stop(p); - spin_unlock_irqrestore(&p->lock, flags); - - return 0; -} - -static void -atmel_pwm_free(struct pwm_channel *p) -{ - struct atmel_pwm *ap = to_atmel_pwm(p); - clk_disable(ap->clk); -} - -static irqreturn_t -atmel_pwmc_irq(int irq, void *data) -{ - struct atmel_pwm *ap = data; - struct pwm_channel *p; - u32 isr; - int chid; - unsigned long flags; - - spin_lock_irqsave(&ap->lock, flags); - - isr = pwmc_readl(ap, PWMC_ISR); - for (chid = 0; isr; chid++, isr >>= 1) { - p = &ap->pwm.channels[chid]; - if (isr & 1) { - if (p->callback) - p->callback(p); - if (p->flags & BIT(FLAG_STOP)) { - __atmel_pwm_stop(p); - clear_bit(FLAG_STOP, &p->flags); - } - complete_all(&p->complete); - } - } - - spin_unlock_irqrestore(&ap->lock, flags); - - return IRQ_HANDLED; -} - -static int __devinit -atmel_pwmc_probe(struct platform_device *pdev) -{ - struct atmel_pwm *ap; - struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - int ret = 0; - - ap = kzalloc(sizeof(*ap), GFP_KERNEL); - if (!ap) { - ret = -ENOMEM; - goto err_atmel_pwm_alloc; - } - - spin_lock_init(&ap->lock); - platform_set_drvdata(pdev, ap); - - ap->pwm.dev = &pdev->dev; - ap->pwm.bus_id = dev_name(&pdev->dev); - - ap->pwm.nchan = 4; /* TODO: true only for SAM9263 and AP7000 */ - ap->ccnt_mask = 0xffffUL; /* TODO: true only for SAM9263 */ - - ap->sync_mask = kzalloc(ap->pwm.nchan * sizeof(u32), GFP_KERNEL); - if (!ap->sync_mask) { - ret = -ENOMEM; - goto err_alloc_sync_masks; - } - - ap->pwm.owner = THIS_MODULE; - ap->pwm.request = atmel_pwm_request; - ap->pwm.free = atmel_pwm_free; - ap->pwm.config_nosleep = atmel_pwm_config_nosleep; - ap->pwm.config = atmel_pwm_config; - ap->pwm.synchronize = atmel_pwm_synchronize; - ap->pwm.unsynchronize = atmel_pwm_unsynchronize; - ap->pwm.set_callback = atmel_pwm_set_callback; - - ap->clk = clk_get(&pdev->dev, "pwm_clk"); - if (PTR_ERR(ap->clk)) { - ret = -ENODEV; - goto err_clk_get; - } - - ap->iobase = ioremap_nocache(r->start, r->end - r->start + 1); - if (!ap->iobase) { - ret = -ENODEV; - goto err_ioremap; - } - - clk_enable(ap->clk); - pwmc_writel(ap, PWMC_DIS, -1); - pwmc_writel(ap, PWMC_IDR, -1); - clk_disable(ap->clk); - - ap->irq = platform_get_irq(pdev, 0); - if (ap->irq != -ENXIO) { - ret = request_irq(ap->irq, atmel_pwmc_irq, 0, - ap->pwm.bus_id, ap); - if (ret) - goto err_request_irq; - } - - ret = pwm_register(&ap->pwm); - if (ret) - goto err_pwm_register; - - return 0; - -err_pwm_register: - if (ap->irq != -ENXIO) - free_irq(ap->irq, ap); -err_request_irq: - iounmap(ap->iobase); -err_ioremap: - clk_put(ap->clk); -err_clk_get: - platform_set_drvdata(pdev, NULL); -err_alloc_sync_masks: - kfree(ap); -err_atmel_pwm_alloc: - return ret; -} - -static int __devexit -atmel_pwmc_remove(struct platform_device *pdev) -{ - struct atmel_pwm *ap = platform_get_drvdata(pdev); - int ret; - - /* TODO: what can we do if this fails? */ - ret = pwm_unregister(&ap->pwm); - - clk_enable(ap->clk); - pwmc_writel(ap, PWMC_IDR, -1); - pwmc_writel(ap, PWMC_DIS, -1); - clk_disable(ap->clk); - - if (ap->irq != -ENXIO) - free_irq(ap->irq, ap); - - clk_put(ap->clk); - iounmap(ap->iobase); - - kfree(ap); - - return 0; -} - -static struct platform_driver atmel_pwm_driver = { - .driver = { - .name = "atmel_pwmc", - .owner = THIS_MODULE, - }, - .probe = atmel_pwmc_probe, - .remove = __devexit_p(atmel_pwmc_remove), -}; - -static int __init atmel_pwm_init(void) -{ - return platform_driver_register(&atmel_pwm_driver); -} -module_init(atmel_pwm_init); - -static void __exit atmel_pwm_exit(void) -{ - platform_driver_unregister(&atmel_pwm_driver); -} -module_exit(atmel_pwm_exit); - -MODULE_AUTHOR("Bill Gatliff <bgat@billgatliff.com>"); -MODULE_DESCRIPTION("Driver for Atmel PWMC peripheral"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:atmel_pwmc"); diff --git a/target/linux/generic/patches-3.3/865-gpiopwm.patch b/target/linux/generic/patches-3.3/865-gpiopwm.patch new file mode 100644 index 0000000000..219de16257 --- /dev/null +++ b/target/linux/generic/patches-3.3/865-gpiopwm.patch @@ -0,0 +1,25 @@ +Index: linux-3.3.8/drivers/Kconfig +=================================================================== +--- linux-3.3.8.orig/drivers/Kconfig 2012-06-01 09:16:13.000000000 +0200 ++++ linux-3.3.8/drivers/Kconfig 2012-07-28 22:16:32.894397322 +0200 +@@ -60,6 +60,8 @@ + + source "drivers/gpio/Kconfig" + ++source "drivers/pwm/Kconfig" ++ + source "drivers/w1/Kconfig" + + source "drivers/power/Kconfig" +Index: linux-3.3.8/drivers/Makefile +=================================================================== +--- linux-3.3.8.orig/drivers/Makefile 2012-06-01 09:16:13.000000000 +0200 ++++ linux-3.3.8/drivers/Makefile 2012-07-28 22:16:17.990396684 +0200 +@@ -8,6 +8,7 @@ + # GPIO must come after pinctrl as gpios may need to mux pins etc + obj-y += pinctrl/ + obj-y += gpio/ ++obj-$(CONFIG_GENERIC_PWM) += pwm/ + obj-$(CONFIG_PCI) += pci/ + obj-$(CONFIG_PARISC) += parisc/ + obj-$(CONFIG_RAPIDIO) += rapidio/ |