Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Blackfin: pwm: implement linux/pwm.h API

For now, this only supports gptimers. Support for dedicated PWM devices
as found on newer parts to come.

Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
Signed-off-by: Mike Frysinger <vapier@gentoo.org>

+111
+10
arch/blackfin/Kconfig
··· 953 953 To compile this driver as a module, choose M here: the module 954 954 will be called gptimers. 955 955 956 + config HAVE_PWM 957 + tristate "Enable PWM API support" 958 + depends on BFIN_GPTIMERS 959 + help 960 + Enable support for the Pulse Width Modulation framework (as 961 + found in linux/pwm.h). 962 + 963 + To compile this driver as a module, choose M here: the module 964 + will be called pwm. 965 + 956 966 choice 957 967 prompt "Uncached DMA region" 958 968 default DMA_UNCACHED_1M
+1
arch/blackfin/kernel/Makefile
··· 21 21 obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o 22 22 CFLAGS_REMOVE_ftrace.o = -pg 23 23 24 + obj-$(CONFIG_HAVE_PWM) += pwm.o 24 25 obj-$(CONFIG_IPIPE) += ipipe.o 25 26 obj-$(CONFIG_BFIN_GPTIMERS) += gptimers.o 26 27 obj-$(CONFIG_CPLB_INFO) += cplbinfo.o
+100
arch/blackfin/kernel/pwm.c
··· 1 + /* 2 + * Blackfin Pulse Width Modulation (PWM) core 3 + * 4 + * Copyright (c) 2011 Analog Devices Inc. 5 + * 6 + * Licensed under the GPL-2 or later. 7 + */ 8 + 9 + #include <linux/module.h> 10 + #include <linux/pwm.h> 11 + #include <linux/slab.h> 12 + 13 + #include <asm/gptimers.h> 14 + #include <asm/portmux.h> 15 + 16 + struct pwm_device { 17 + unsigned id; 18 + unsigned short pin; 19 + }; 20 + 21 + static const unsigned short pwm_to_gptimer_per[] = { 22 + P_TMR0, P_TMR1, P_TMR2, P_TMR3, P_TMR4, P_TMR5, 23 + P_TMR6, P_TMR7, P_TMR8, P_TMR9, P_TMR10, P_TMR11, 24 + }; 25 + 26 + struct pwm_device *pwm_request(int pwm_id, const char *label) 27 + { 28 + struct pwm_device *pwm; 29 + int ret; 30 + 31 + /* XXX: pwm_id really should be unsigned */ 32 + if (pwm_id < 0) 33 + return NULL; 34 + 35 + pwm = kzalloc(sizeof(*pwm), GFP_KERNEL); 36 + if (!pwm) 37 + return pwm; 38 + 39 + pwm->id = pwm_id; 40 + if (pwm->id >= ARRAY_SIZE(pwm_to_gptimer_per)) 41 + goto err; 42 + 43 + pwm->pin = pwm_to_gptimer_per[pwm->id]; 44 + ret = peripheral_request(pwm->pin, label); 45 + if (ret) 46 + goto err; 47 + 48 + return pwm; 49 + err: 50 + kfree(pwm); 51 + return NULL; 52 + } 53 + EXPORT_SYMBOL(pwm_request); 54 + 55 + void pwm_free(struct pwm_device *pwm) 56 + { 57 + peripheral_free(pwm->pin); 58 + kfree(pwm); 59 + } 60 + EXPORT_SYMBOL(pwm_free); 61 + 62 + int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) 63 + { 64 + unsigned long period, duty; 65 + unsigned long long val; 66 + 67 + if (duty_ns < 0 || duty_ns > period_ns) 68 + return -EINVAL; 69 + 70 + val = (unsigned long long)get_sclk() * period_ns; 71 + do_div(val, NSEC_PER_SEC); 72 + period = val; 73 + 74 + val = (unsigned long long)period * duty_ns; 75 + do_div(val, period_ns); 76 + duty = period - val; 77 + 78 + if (duty >= period) 79 + duty = period - 1; 80 + 81 + set_gptimer_config(pwm->id, TIMER_MODE_PWM | TIMER_PERIOD_CNT); 82 + set_gptimer_pwidth(pwm->id, duty); 83 + set_gptimer_period(pwm->id, period); 84 + 85 + return 0; 86 + } 87 + EXPORT_SYMBOL(pwm_config); 88 + 89 + int pwm_enable(struct pwm_device *pwm) 90 + { 91 + enable_gptimer(pwm->id); 92 + return 0; 93 + } 94 + EXPORT_SYMBOL(pwm_enable); 95 + 96 + void pwm_disable(struct pwm_device *pwm) 97 + { 98 + disable_gptimer(pwm->id); 99 + } 100 + EXPORT_SYMBOL(pwm_disable);