diff --git a/arch/arm/boards/mioa701/board.c b/arch/arm/boards/mioa701/board.c index 6f93900fd..cdb86fc36 100644 --- a/arch/arm/boards/mioa701/board.c +++ b/arch/arm/boards/mioa701/board.c @@ -68,7 +68,7 @@ static void mioa701_lcd_power(int on) static void mioa701_lcd_backlight(int on) { - struct pwm_device *pwm0 = pwm_request("pxa_pwm0"); + struct pwm_device *pwm0 = pwm_request("pwm0"); /* * The backlight has a base frequency of 250kHz (<=> 4 ms). diff --git a/arch/arm/dts/imx6qdl.dtsi b/arch/arm/dts/imx6qdl.dtsi index 735569f8e..70424d2cb 100644 --- a/arch/arm/dts/imx6qdl.dtsi +++ b/arch/arm/dts/imx6qdl.dtsi @@ -30,6 +30,10 @@ mmc1 = &usdhc2; mmc2 = &usdhc3; mmc3 = &usdhc4; + pwm0 = &pwm1; + pwm1 = &pwm2; + pwm2 = &pwm3; + pwm3 = &pwm4; serial0 = &uart1; serial1 = &uart2; serial2 = &uart3; diff --git a/arch/arm/mach-imx/clk-imx6.c b/arch/arm/mach-imx/clk-imx6.c index ac86074b6..5560fff7c 100644 --- a/arch/arm/mach-imx/clk-imx6.c +++ b/arch/arm/mach-imx/clk-imx6.c @@ -305,6 +305,10 @@ static int imx6_ccm_probe(struct device_d *dev) clkdev_add_physbase(clks[usbphy1], MX6_USBPHY1_BASE_ADDR, NULL); clkdev_add_physbase(clks[usbphy2], MX6_USBPHY2_BASE_ADDR, NULL); clkdev_add_physbase(clks[enfc_podf], MX6_GPMI_BASE_ADDR, NULL); + clkdev_add_physbase(clks[ipg_per], MX6_PWM1_BASE_ADDR, "per"); + clkdev_add_physbase(clks[ipg_per], MX6_PWM2_BASE_ADDR, "per"); + clkdev_add_physbase(clks[ipg_per], MX6_PWM3_BASE_ADDR, "per"); + clkdev_add_physbase(clks[ipg_per], MX6_PWM4_BASE_ADDR, "per"); writel(0xffffffff, ccm_base + CCGR0); writel(0xf0ffffff, ccm_base + CCGR1); /* gate GPU3D, GPU2D */ diff --git a/drivers/led/Kconfig b/drivers/led/Kconfig index 3ead82e03..155a78a7d 100644 --- a/drivers/led/Kconfig +++ b/drivers/led/Kconfig @@ -7,6 +7,10 @@ config LED_GPIO bool "gpio LED support" depends on GENERIC_GPIO +config LED_PWM + bool "PWM LED support" + depends on PWM + config LED_GPIO_OF bool "support parsing gpio LEDs from device tree" depends on LED_GPIO && OFTREE diff --git a/drivers/led/Makefile b/drivers/led/Makefile index 6aafa6df0..619bbcf5c 100644 --- a/drivers/led/Makefile +++ b/drivers/led/Makefile @@ -1,3 +1,4 @@ obj-$(CONFIG_LED) += core.o obj-$(CONFIG_LED_GPIO) += led-gpio.o +obj-$(CONFIG_LED_PWM) += led-pwm.o obj-$(CONFIG_LED_TRIGGERS) += led-triggers.o diff --git a/drivers/led/core.c b/drivers/led/core.c index 8537aa15e..30b016bb3 100644 --- a/drivers/led/core.c +++ b/drivers/led/core.c @@ -153,3 +153,38 @@ void led_unregister(struct led *led) { list_del(&led->list); } + +struct led_trg { + const char *str; + enum led_trigger trg; +}; + +static struct led_trg triggers[] = { + { .str = "heartbeat", LED_TRIGGER_HEARTBEAT, }, + { .str = "panic", LED_TRIGGER_PANIC, }, + { .str = "net", LED_TRIGGER_NET_TXRX, }, + { .str = "default-on", LED_TRIGGER_DEFAULT_ON, }, +}; + +void led_of_parse_trigger(struct led *led, struct device_node *np) +{ + const char *trigger; + int i; + + trigger = of_get_property(np, "linux,default-trigger", NULL); + if (!trigger) + trigger = of_get_property(np, "barebox,default-trigger", NULL); + + if (!trigger) + return; + + for (i = 0; i < ARRAY_SIZE(triggers); i++) { + struct led_trg *trg = &triggers[i]; + if (!strcmp(trg->str, trigger)) { + /* disable LED before installing trigger */ + led_set(led, 0); + led_set_trigger(trg->trg, led); + return; + } + } +} diff --git a/drivers/led/led-gpio.c b/drivers/led/led-gpio.c index 7a5ef473e..7bb3b4995 100644 --- a/drivers/led/led-gpio.c +++ b/drivers/led/led-gpio.c @@ -198,41 +198,6 @@ void led_gpio_rgb_unregister(struct gpio_led *led) #endif /* CONFIG_LED_GPIO_RGB */ #ifdef CONFIG_LED_GPIO_OF - -struct led_trg { - const char *str; - enum led_trigger trg; -}; - -static struct led_trg triggers[] = { - { .str = "heartbeat", LED_TRIGGER_HEARTBEAT, }, - { .str = "panic", LED_TRIGGER_PANIC, }, - { .str = "net", LED_TRIGGER_NET_TXRX, }, -}; - -static void led_of_parse_trigger(struct led *led, struct device_node *np) -{ - const char *trigger; - int i; - - trigger = of_get_property(np, "linux,default-trigger", NULL); - if (!trigger) - trigger = of_get_property(np, "barebox,default-trigger", NULL); - - if (!trigger) - return; - - for (i = 0; i < ARRAY_SIZE(triggers); i++) { - struct led_trg *trg = &triggers[i]; - if (!strcmp(trg->str, trigger)) { - /* disable LED before installing trigger */ - led_set(led, 0); - led_set_trigger(trg->trg, led); - return; - } - } -} - static int led_gpio_of_probe(struct device_d *dev) { struct device_node *child; diff --git a/drivers/led/led-pwm.c b/drivers/led/led-pwm.c new file mode 100644 index 000000000..16d22b556 --- /dev/null +++ b/drivers/led/led-pwm.c @@ -0,0 +1,93 @@ +/* + * pwm LED support for barebox + * + * (C) Copyright 2010 Sascha Hauer, Pengutronix + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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; either version 2 of + * the License, or (at your option) any later version. + * + * 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. + * + */ +#include +#include +#include +#include +#include +#include +#include + +struct pwmled { + bool active_low; + struct led led; + struct pwm_device *pwm; + uint32_t period; +}; + +static void led_pwm_set(struct led *led, unsigned int brightness) +{ + struct pwmled *pwmled = container_of(led, struct pwmled, led); + unsigned long long duty = pwmled->period; + unsigned int max = pwmled->led.max_value; + + duty *= brightness; + do_div(duty, max); + + pwm_config(pwmled->pwm, duty, pwmled->period); +} + +static int led_pwm_of_probe(struct device_d *dev) +{ + struct device_node *child; + int ret; + + for_each_child_of_node(dev->device_node, child) { + struct pwmled *pwmled; + struct pwm_device *pwm; + + pwm = of_pwm_request(child, NULL); + if (pwm < 0) + continue; + + pwmled = xzalloc(sizeof(*pwmled)); + pwmled->led.name = xstrdup(child->name); + pwmled->pwm = pwm; + + of_property_read_u32(child, "max-brightness", &pwmled->led.max_value); + + pwmled->period = pwm_get_period(pwmled->pwm); + + pwmled->led.set = led_pwm_set; + + pwm_config(pwmled->pwm, 0, pwmled->period); + pwm_enable(pwmled->pwm); + + ret = led_register(&pwmled->led); + if (ret) + return ret; + + led_of_parse_trigger(&pwmled->led, child); + } + + return 0; +} + +static struct of_device_id led_pwm_of_ids[] = { + { .compatible = "pwm-leds", }, + { } +}; + +static struct driver_d led_pwm_of_driver = { + .name = "pwm-leds", + .probe = led_pwm_of_probe, + .of_compatible = DRV_OF_COMPAT(led_pwm_of_ids), +}; +device_platform_driver(led_pwm_of_driver); diff --git a/drivers/led/led-triggers.c b/drivers/led/led-triggers.c index 7555eee3a..5eaf73276 100644 --- a/drivers/led/led-triggers.c +++ b/drivers/led/led-triggers.c @@ -124,6 +124,9 @@ int led_set_trigger(enum led_trigger trigger, struct led *led) triggers[trigger].led = led; + if (trigger == LED_TRIGGER_DEFAULT_ON) + led_set(triggers[trigger].led, triggers[trigger].led->max_value); + return 0; } diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index fc0836319..8324d5ef1 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -16,4 +16,10 @@ config PWM_PXA This enables PWM support for Intel/Marvell PXA chips, such as the PXA25x, PXA27x. +config PWM_IMX + bool "i.MX PWM Support" + depends on ARCH_IMX + help + This enables PWM support for Freescale i.MX SoCs + endif diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index c886bd55b..dea9956c0 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -1,2 +1,3 @@ obj-$(CONFIG_PWM) += core.o -obj-$(CONFIG_PWM_PXA) += pxa_pwm.o \ No newline at end of file +obj-$(CONFIG_PWM_PXA) += pxa_pwm.o +obj-$(CONFIG_PWM_IMX) += pwm-imx.o diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index f769cfe9b..cc33dec36 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -26,7 +26,8 @@ struct pwm_device { #define FLAG_REQUESTED 0 #define FLAG_ENABLED 1 struct list_head node; - struct device_d *dev; + struct device_d *hwdev; + struct device_d dev; unsigned int duty_ns; unsigned int period_ns; @@ -79,27 +80,36 @@ int pwmchip_add(struct pwm_chip *chip, struct device_d *dev) { struct pwm_device *pwm; struct param_d *p; + int ret; if (_find_pwm(chip->devname)) return -EBUSY; pwm = xzalloc(sizeof(*pwm)); pwm->chip = chip; - pwm->dev = dev; + pwm->hwdev = dev; + + strcpy(pwm->dev.name, chip->devname); + pwm->dev.id = DEVICE_ID_SINGLE; + pwm->dev.parent = dev; + + ret = register_device(&pwm->dev); + if (ret) + return ret; list_add_tail(&pwm->node, &pwm_list); - p = dev_add_param_int(dev, "duty_ns", set_duty_period_ns, + p = dev_add_param_int(&pwm->dev, "duty_ns", set_duty_period_ns, NULL, &pwm->chip->duty_ns, "%u", pwm); if (IS_ERR(p)) return PTR_ERR(p); - p = dev_add_param_int(dev, "period_ns", set_duty_period_ns, + p = dev_add_param_int(&pwm->dev, "period_ns", set_duty_period_ns, NULL, &pwm->chip->period_ns, "%u", pwm); if (IS_ERR(p)) return PTR_ERR(p); - p = dev_add_param_bool(dev, "enable", set_enable, + p = dev_add_param_bool(&pwm->dev, "enable", set_enable, NULL, &pwm->p_enable, pwm); if (IS_ERR(p)) return PTR_ERR(p); @@ -133,6 +143,24 @@ int pwmchip_remove(struct pwm_chip *chip) } EXPORT_SYMBOL_GPL(pwmchip_remove); +static int __pwm_request(struct pwm_device *pwm) +{ + int ret; + + if (test_bit(FLAG_REQUESTED, &pwm->flags)) + return -EBUSY; + + if (pwm->chip->ops->request) { + ret = pwm->chip->ops->request(pwm->chip); + if (ret) + return ret; + } + + set_bit(FLAG_REQUESTED, &pwm->flags); + + return 0; +} + /* * pwm_request - request a PWM device */ @@ -145,21 +173,60 @@ struct pwm_device *pwm_request(const char *devname) if (!pwm) return NULL; - if (test_bit(FLAG_REQUESTED, &pwm->flags)) + ret = __pwm_request(pwm); + if (ret) return NULL; - if (pwm->chip->ops->request) { - ret = pwm->chip->ops->request(pwm->chip); - if (ret) - return NULL; - } - - set_bit(FLAG_REQUESTED, &pwm->flags); - return pwm; } EXPORT_SYMBOL_GPL(pwm_request); +static struct pwm_device *of_node_to_pwm_device(struct device_node *np) +{ + struct pwm_device *pwm; + + list_for_each_entry(pwm, &pwm_list, node) { + if (pwm->hwdev && pwm->hwdev->device_node == np) + return pwm; + } + + return ERR_PTR(-ENODEV); +} + +struct pwm_device *of_pwm_request(struct device_node *np, const char *con_id) +{ + struct of_phandle_args args; + int index = 0; + struct pwm_device *pwm; + int ret; + + if (con_id) + return ERR_PTR(-EINVAL); + + ret = of_parse_phandle_with_args(np, "pwms", "#pwm-cells", index, + &args); + if (ret) { + pr_debug("%s(): can't parse \"pwms\" property\n", __func__); + return ERR_PTR(ret); + } + + pwm = of_node_to_pwm_device(args.np); + if (IS_ERR(pwm)) { + pr_debug("%s(): PWM chip not found\n", __func__); + return pwm; + } + + if (args.args_count > 1) + pwm_set_period(pwm, args.args[1]); + + ret = __pwm_request(pwm); + if (ret) + return ERR_PTR(-ret); + + return pwm; +} +EXPORT_SYMBOL_GPL(of_pwm_request); + /* * pwm_free - free a PWM device */ @@ -188,6 +255,26 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) } EXPORT_SYMBOL_GPL(pwm_config); +void pwm_set_period(struct pwm_device *pwm, unsigned int period_ns) +{ + pwm->period_ns = period_ns; +} + +unsigned int pwm_get_period(struct pwm_device *pwm) +{ + return pwm->period_ns; +} + +void pwm_set_duty_cycle(struct pwm_device *pwm, unsigned int duty_ns) +{ + pwm->duty_ns = duty_ns; +} + +unsigned int pwm_get_duty_cycle(struct pwm_device *pwm) +{ + return pwm->duty_ns; +} + /* * pwm_enable - start a PWM output toggling */ diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c new file mode 100644 index 000000000..e29341f8e --- /dev/null +++ b/drivers/pwm/pwm-imx.c @@ -0,0 +1,262 @@ +/* + * simple driver for PWM (Pulse Width Modulator) controller + * + * 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. + * + * Derived from pxa PWM driver by eric miao + */ + +#include +#include +#include +#include +#include +#include +#include + +/* i.MX1 and i.MX21 share the same PWM function block: */ + +#define MX1_PWMC 0x00 /* PWM Control Register */ +#define MX1_PWMS 0x04 /* PWM Sample Register */ +#define MX1_PWMP 0x08 /* PWM Period Register */ + +#define MX1_PWMC_EN (1 << 4) + +/* i.MX27, i.MX31, i.MX35 share the same PWM function block: */ + +#define MX3_PWMCR 0x00 /* PWM Control Register */ +#define MX3_PWMSAR 0x0C /* PWM Sample Register */ +#define MX3_PWMPR 0x10 /* PWM Period Register */ +#define MX3_PWMCR_PRESCALER(x) (((x - 1) & 0xFFF) << 4) +#define MX3_PWMCR_DOZEEN (1 << 24) +#define MX3_PWMCR_WAITEN (1 << 23) +#define MX3_PWMCR_DBGEN (1 << 22) +#define MX3_PWMCR_CLKSRC_IPG_HIGH (2 << 16) +#define MX3_PWMCR_CLKSRC_IPG (1 << 16) +#define MX3_PWMCR_EN (1 << 0) + +struct imx_chip { + struct clk *clk_per; + + void __iomem *mmio_base; + + struct pwm_chip chip; + + int (*config)(struct pwm_chip *chip, + int duty_ns, int period_ns); + void (*set_enable)(struct pwm_chip *chip, bool enable); +}; + +#define to_imx_chip(chip) container_of(chip, struct imx_chip, chip) + +static int imx_pwm_config_v1(struct pwm_chip *chip, + int duty_ns, int period_ns) +{ + struct imx_chip *imx = to_imx_chip(chip); + + /* + * The PWM subsystem allows for exact frequencies. However, + * I cannot connect a scope on my device to the PWM line and + * thus cannot provide the program the PWM controller + * exactly. Instead, I'm relying on the fact that the + * Bootloader (u-boot or WinCE+haret) has programmed the PWM + * function group already. So I'll just modify the PWM sample + * register to follow the ratio of duty_ns vs. period_ns + * accordingly. + * + * This is good enough for programming the brightness of + * the LCD backlight. + * + * The real implementation would divide PERCLK[0] first by + * both the prescaler (/1 .. /128) and then by CLKSEL + * (/2 .. /16). + */ + u32 max = readl(imx->mmio_base + MX1_PWMP); + u32 p = max * duty_ns / period_ns; + writel(max - p, imx->mmio_base + MX1_PWMS); + + return 0; +} + +static void imx_pwm_set_enable_v1(struct pwm_chip *chip, bool enable) +{ + struct imx_chip *imx = to_imx_chip(chip); + u32 val; + + val = readl(imx->mmio_base + MX1_PWMC); + + if (enable) + val |= MX1_PWMC_EN; + else + val &= ~MX1_PWMC_EN; + + writel(val, imx->mmio_base + MX1_PWMC); +} + +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; + u32 cr; + + c = clk_get_rate(imx->clk_per); + c = c * period_ns; + do_div(c, 1000000000); + period_cycles = c; + + prescale = period_cycles / 0x10000 + 1; + + period_cycles /= prescale; + c = (unsigned long long)period_cycles * duty_ns; + do_div(c, period_ns); + duty_cycles = c; + + /* + * according to imx pwm RM, the real period value should be + * PERIOD value in PWMPR plus 2. + */ + if (period_cycles > 2) + period_cycles -= 2; + else + period_cycles = 0; + + writel(duty_cycles, imx->mmio_base + MX3_PWMSAR); + writel(period_cycles, imx->mmio_base + MX3_PWMPR); + + cr = MX3_PWMCR_PRESCALER(prescale) | + MX3_PWMCR_DOZEEN | MX3_PWMCR_WAITEN | + MX3_PWMCR_DBGEN | MX3_PWMCR_CLKSRC_IPG_HIGH; + + if (readl(imx->mmio_base + MX3_PWMCR) & MX3_PWMCR_EN) + cr |= MX3_PWMCR_EN; + + writel(cr, imx->mmio_base + MX3_PWMCR); + + return 0; +} + +static void imx_pwm_set_enable_v2(struct pwm_chip *chip, bool enable) +{ + struct imx_chip *imx = to_imx_chip(chip); + u32 val; + + val = readl(imx->mmio_base + MX3_PWMCR); + + if (enable) + val |= MX3_PWMCR_EN; + else + val &= ~MX3_PWMCR_EN; + + writel(val, imx->mmio_base + MX3_PWMCR); +} + +static int imx_pwm_config(struct pwm_chip *chip, + int duty_ns, int period_ns) +{ + struct imx_chip *imx = to_imx_chip(chip); + int ret; + + ret = imx->config(chip, duty_ns, period_ns); + + return ret; +} + +static int imx_pwm_enable(struct pwm_chip *chip) +{ + struct imx_chip *imx = to_imx_chip(chip); + + imx->set_enable(chip, true); + + return 0; +} + +static void imx_pwm_disable(struct pwm_chip *chip) +{ + struct imx_chip *imx = to_imx_chip(chip); + + imx->set_enable(chip, false); +} + +static struct pwm_ops imx_pwm_ops = { + .enable = imx_pwm_enable, + .disable = imx_pwm_disable, + .config = imx_pwm_config, +}; + +struct imx_pwm_data { + int (*config)(struct pwm_chip *chip, + int duty_ns, int period_ns); + void (*set_enable)(struct pwm_chip *chip, bool enable); +}; + +static struct imx_pwm_data imx_pwm_data_v1 = { + .config = imx_pwm_config_v1, + .set_enable = imx_pwm_set_enable_v1, +}; + +static struct imx_pwm_data imx_pwm_data_v2 = { + .config = imx_pwm_config_v2, + .set_enable = imx_pwm_set_enable_v2, +}; + +static struct of_device_id imx_pwm_dt_ids[] = { + { .compatible = "fsl,imx1-pwm", .data = (unsigned long)&imx_pwm_data_v1, }, + { .compatible = "fsl,imx27-pwm", .data = (unsigned long)&imx_pwm_data_v2, }, + { /* sentinel */ } +}; + +static int imx_pwm_probe(struct device_d *dev) +{ + const struct imx_pwm_data *data; + struct imx_chip *imx; + int ret = 0; + + ret = dev_get_drvdata(dev, (unsigned long *)&data); + if (ret) + return ret; + + imx = xzalloc(sizeof(*imx)); + + imx->clk_per = clk_get(dev, "per"); + if (IS_ERR(imx->clk_per)) + return PTR_ERR(imx->clk_per); + + imx->chip.ops = &imx_pwm_ops; + if (dev->device_node) { + imx->chip.devname = of_alias_get(dev->device_node); + if (!imx->chip.devname) { + dev_err(dev, "no alias for pwm\n"); + return -EINVAL; + } + } else { + imx->chip.devname = asprintf("pwm%d", dev->id); + } + + imx->mmio_base = dev_request_mem_region(dev, 0); + if (!imx->mmio_base) + return -EBUSY; + + imx->config = data->config; + imx->set_enable = data->set_enable; + + ret = pwmchip_add(&imx->chip, dev); + if (ret < 0) + return ret; + + return 0; +} + +static struct driver_d imx_pwm_driver = { + .name = "imx-pwm", + .of_compatible = imx_pwm_dt_ids, + .probe = imx_pwm_probe, +}; + +coredevice_platform_driver(imx_pwm_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Sascha Hauer "); diff --git a/drivers/pwm/pxa_pwm.c b/drivers/pwm/pxa_pwm.c index 8e22d4988..8b2ebe4f6 100644 --- a/drivers/pwm/pxa_pwm.c +++ b/drivers/pwm/pxa_pwm.c @@ -133,7 +133,7 @@ static int pxa_pwm_probe(struct device_d *dev) struct pxa_pwm_chip *chip; chip = xzalloc(sizeof(*chip)); - chip->chip.devname = asprintf("%s", dev_name(dev)); + chip->chip.devname = asprintf("pwm%d", dev->id); chip->chip.ops = &pxa_pwm_ops; chip->iobase = dev_request_mem_region(dev, 0); chip->id = dev->id; diff --git a/include/led.h b/include/led.h index dd551fe16..f17621e16 100644 --- a/include/led.h +++ b/include/led.h @@ -33,6 +33,7 @@ enum led_trigger { LED_TRIGGER_NET_RX, LED_TRIGGER_NET_TX, LED_TRIGGER_NET_TXRX, + LED_TRIGGER_DEFAULT_ON, LED_TRIGGER_MAX, }; @@ -58,6 +59,8 @@ static inline void led_trigger(enum led_trigger trigger, enum trigger_type type) int led_get_trigger(enum led_trigger trigger); +void led_of_parse_trigger(struct led *led, struct device_node *np); + /* gpio LED support */ struct gpio_led { int gpio; diff --git a/include/pwm.h b/include/pwm.h index bdc2fdd85..59d86d497 100644 --- a/include/pwm.h +++ b/include/pwm.h @@ -9,6 +9,8 @@ struct device_d; */ struct pwm_device *pwm_request(const char *pwmname); +struct pwm_device *of_pwm_request(struct device_node *np, const char *con_id); + /* * pwm_free - free a PWM device */ @@ -29,6 +31,11 @@ int pwm_enable(struct pwm_device *pwm); */ void pwm_disable(struct pwm_device *pwm); +void pwm_set_period(struct pwm_device *pwm, unsigned int period); +unsigned int pwm_get_period(struct pwm_device *pwm); +void pwm_set_duty_cycle(struct pwm_device *pwm, unsigned int duty); +unsigned int pwm_get_duty_cycle(struct pwm_device *pwm); + struct pwm_chip; /**