Skip to content

Commit a6575d7

Browse files
committed
PWM working on one channel, using one timer.
1 parent 754bc6d commit a6575d7

File tree

4 files changed

+146
-80
lines changed

4 files changed

+146
-80
lines changed

Makefile

+6-6
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,22 @@
88
include $(TOPDIR)/rules.mk
99
include $(INCLUDE_DIR)/kernel.mk
1010

11-
PKG_NAME:=gpio-meander
11+
PKG_NAME:=gpio-pwm-ar9331
1212
PKG_RELEASE:=1
1313

1414
include $(INCLUDE_DIR)/package.mk
1515

16-
define KernelPackage/gpio-sqwave
16+
define KernelPackage/gpio-pwm-ar9331
1717
SUBMENU:=Other modules
1818
DEPENDS:=@!LINUX_3_3
19-
TITLE:=Timer IRQ handler
20-
FILES:=$(PKG_BUILD_DIR)/gpio-sqwave.ko
19+
TITLE:=PWM on gpio for AR9331
20+
FILES:=$(PKG_BUILD_DIR)/gpio-pwm-ar9331.ko
2121
AUTOLOAD:=$(call AutoLoad,30,gpio-sqwave,1)
2222
KCONFIG:=
2323
endef
2424

2525
define KernelPackage/gpio-sqwave/description
26-
This is GPIO square wave generator for AR9331 devices.
26+
This is GPIO PWM generator for AR9331 devices.
2727
endef
2828

2929
MAKE_OPTS:= \
@@ -42,4 +42,4 @@ define Build/Compile
4242
modules
4343
endef
4444

45-
$(eval $(call KernelPackage,gpio-sqwave))
45+
$(eval $(call KernelPackage,gpio-pwm-ar9331))

README.md

+16-11
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,27 @@
1-
# gpio-sqwave
2-
Square wave generator using AR9331 hardware timer.
1+
# gpio-pwm-ar9331
2+
PWM generator using AR9331 hardware timer.
33

4-
gpio-sqwave is an OpenWRT kernel module which provides square wave output on any AR9331 SoC GPIO pin with up to 125 kHz frequency.
4+
gpio-pwm-ar9331 is an OpenWRT kernel module which provides PWM output on any AR9331 SoC GPIO pin with up to 125 kHz frequency.
55

6-
##Installation
76

8-
*insmod gpio-sqwave [timer=0|1|2|3]*<br />
7+
##Intallation
8+
1. Download binary package from [releases section](https://github.com/ASMfreaK/gpio-pwm-ar9331/releases) or build it using OpenWRT Buildroot.
9+
2. Upload package to device using your favorite method.
10+
3. Run `opkg install kmod-gpio-pwm-ar9331_<version>.ipk` where `<version>` is version of a package. If it fails, rerun command with `--force-depends` flag i.e. `opkg install --force-depends kmod-gpio-pwm-ar9331_<version>.ipk`
11+
12+
13+
##Initialisation
14+
`insmod gpio-sqwave [timer=0|1|2|3]`<br />
915
Default is timer 3
1016

1117
##Usage
1218

13-
**Start**: *echo "&lt;GPIO&gt; &lt;freq&gt;" > /sys/kernel/debug/sqwave*<br />
14-
"*GPIO*" is GPIO number, "*freq*" is square wave frequency in Hz. Maximum frequency with 200 MHz system bus (default clock) is 125 kHz; high settings may result in performance penalty or watchdog reset.
19+
**Start**: `echo "<GPIO> <freq> <pos>" > /sys/kernel/debug/pwm-ar9331`<br />
20+
`GPIO` is GPIO number, `freq` is square wave frequency in Hz, `pos` is a number between 0 and 65536 representing duty cycle. At different frequencies it can generate up to 16 bit PWM Maximum frequency with 200 MHz system bus (default clock) is 125 kHz; high settings may result in performance penalty or watchdog reset.
1521

16-
**Example**: to blink Black Swift's system LED with 1 Hz frequency: *echo "27 1" > /sys/kernel/debug/sqwave*
22+
**Example**: to blink Black Swift's system LED with 1 Hz frequency at around 1/2 duty cycle: `echo "27 1 3000" > /sys/kernel/debug/pwm-ar9331`
1723

18-
**Stop**: *echo - > /sys/kernel/debug/sqwave*
24+
**Stop**: `echo - > /sys/kernel/debug/pwm-ar9331`
1925

20-
**Status**: *echo ? > /sys/kernel/debug/sqwave*
26+
**Status**: `echo ? > /sys/kernel/debug/pwm-ar9331`
2127

22-
Check http://www.black-swift.com/wiki for more information.

src/Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
obj-m += gpio-sqwave.o
1+
obj-m += gpio-pwm-ar9331.o

src/gpio-sqwave.c renamed to src/gpio-pwm-ar9331.c

+123-62
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@
2929

3030
////////////////////////////////////////////////////////////////////////////////////////////
3131

32-
#define DRV_NAME "gpio-sqwave"
33-
#define FILE_NAME "sqwave"
32+
#define DRV_NAME "gpio-pwm-ar9331"
33+
#define FILE_NAME "pwm-ar9331"
3434

3535
////////////////////////////////////////////////////////////////////////////////////////////
3636

@@ -48,7 +48,7 @@ MODULE_PARM_DESC(timer, "system timer number (0-3)");
4848
#define debug(fmt,args...)
4949
#endif /* DEBUG_OUT */
5050

51-
static unsigned int _timer_frequency=100000000;
51+
static unsigned int _timer_frequency=200000000;
5252
static spinlock_t _lock;
5353
static unsigned int _gpio_prev=0;
5454

@@ -84,6 +84,8 @@ struct _timer_desc_struct
8484
#define GPIO_OFFS_SET 0x0C
8585
#define GPIO_OFFS_CLEAR 0x10
8686

87+
#define PWM_MAX 65536
88+
8789
////////////////////////////////////////////////////////////////////////////////////////////
8890

8991
void __iomem *ath79_timer_base=NULL;
@@ -97,11 +99,16 @@ void __iomem *gpio_cleardataout_addr=NULL;
9799

98100
typedef struct
99101
{
100-
int timer;
101-
int irq;
102-
int gpio;
102+
int timer;
103+
int irq;
104+
int gpio;
103105
unsigned int frequency;
104-
int value;
106+
unsigned int timeout_total;
107+
unsigned int timeout_front;
108+
unsigned int timeout_back;
109+
unsigned int new_pos;
110+
int update;
111+
int value;
105112
} _timer_handler;
106113

107114
static _timer_handler _handler;
@@ -110,6 +117,41 @@ static struct dentry* in_file;
110117

111118
////////////////////////////////////////////////////////////////////////////////////////////
112119

120+
inline void set_timer_reload(int timer, unsigned int freq)
121+
{
122+
__raw_writel(freq, ath79_timer_base+_timers[timer].reload_reg);
123+
}
124+
125+
////////////////////////////////////////////////////////////////////////////////////////////
126+
127+
inline void set_gpio_value(int gpio, int val)
128+
{
129+
if(val)
130+
{
131+
__raw_writel(1 << gpio, gpio_setdataout_addr);
132+
}
133+
else
134+
{
135+
__raw_writel(1 << gpio, gpio_cleardataout_addr);
136+
}
137+
}
138+
139+
////////////////////////////////////////////////////////////////////////////////////////////
140+
141+
void recalculate_timeouts(_timer_handler* handler){
142+
unsigned int flags = 0;
143+
spin_lock_irqsave(&_lock,flags);
144+
handler->timeout_total=_timer_frequency/handler->frequency;
145+
debug("New timeout: %u\n",handler->timeout_total);
146+
handler->timeout_front =(unsigned int)(((unsigned long long)handler->timeout_total * (unsigned long long)handler->new_pos) / PWM_MAX);
147+
debug("New front timeout: %u\n",handler->timeout_front);
148+
handler->timeout_back = handler->timeout_total - handler->timeout_front;
149+
debug("New back timeout: %u\n",handler->timeout_back);
150+
spin_unlock_irqrestore(&_lock,flags);
151+
}
152+
153+
////////////////////////////////////////////////////////////////////////////////////////////
154+
113155
static int is_space(char symbol)
114156
{
115157
return (symbol == ' ') || (symbol == '\t');
@@ -130,15 +172,21 @@ static irqreturn_t timer_interrupt(int irq, void* dev_id)
130172

131173
if(handler && (handler->irq == irq) && (handler->gpio >= 0))
132174
{
175+
if(handler->update == 1)
176+
{
177+
handler->update = 0;
178+
recalculate_timeouts(handler);
179+
}
133180
if(handler->value)
134181
{
135182
__raw_writel(1 << handler->gpio, gpio_setdataout_addr);
183+
set_timer_reload(handler->timer, handler->timeout_back);
136184
}
137185
else
138186
{
139187
__raw_writel(1 << handler->gpio, gpio_cleardataout_addr);
188+
set_timer_reload(handler->timer, handler->timeout_front);
140189
}
141-
142190
handler->value=!handler->value;
143191
}
144192

@@ -186,16 +234,7 @@ static void stop(void)
186234

187235
if(_handler.gpio >= 0)
188236
{
189-
// restore previous GPIO state
190-
if(_gpio_prev)
191-
{
192-
__raw_writel(1 << _handler.gpio,gpio_setdataout_addr);
193-
}
194-
else
195-
{
196-
__raw_writel(1 << _handler.gpio,gpio_cleardataout_addr);
197-
}
198-
237+
set_gpio_value(_handler.gpio, _gpio_prev);
199238
gpio_free(_handler.gpio);
200239
_handler.gpio=-1;
201240
}
@@ -211,17 +250,16 @@ static void stop(void)
211250

212251
////////////////////////////////////////////////////////////////////////////////////////////
213252

214-
static int start(int gpio,unsigned int frequency)
253+
static int start(int gpio,unsigned int frequency,unsigned int pos)
215254
{
216-
unsigned int timeout=0;
217255
int irq=-1;
218256
unsigned long flags=0;
219257

220258
stop();
221259

222260
spin_lock_irqsave(&_lock,flags);
223261
// need some time (10 ms) before first IRQ - even after "lock"?!
224-
__raw_writel(_timer_frequency/100, ath79_timer_base+_timers[timer].reload_reg);
262+
set_timer_reload(timer, _timer_frequency/100);
225263

226264
irq=add_irq(&_handler);
227265

@@ -238,10 +276,11 @@ static int start(int gpio,unsigned int frequency)
238276
// save current GPIO state
239277
_gpio_prev=__raw_readl(gpio_readdata_addr+GPIO_OFFS_READ) & (1 << gpio);
240278

241-
timeout=_timer_frequency/frequency/2;
242-
__raw_writel(timeout, ath79_timer_base+_timers[timer].reload_reg);
243279

244-
_handler.frequency=frequency;
280+
_handler.frequency = frequency;
281+
_handler.new_pos = pos;
282+
recalculate_timeouts(&_handler);
283+
set_timer_reload(timer, _handler.timeout_front);
245284

246285
debug("New frequency: %u.\n", frequency);
247286

@@ -270,6 +309,7 @@ static ssize_t run_command(struct file *file, const char __user *buf,
270309
char* in_pos=NULL;
271310
char* end=NULL;
272311
char* out_pos=NULL;
312+
unsigned int flags = 0;
273313

274314
if(count > 512)
275315
return -EINVAL; // file is too big
@@ -286,6 +326,7 @@ static ssize_t run_command(struct file *file, const char __user *buf,
286326
{
287327
unsigned int gpio=-1;
288328
unsigned int frequency=0;
329+
unsigned int pos=0;
289330

290331
while((in_pos < end) && is_space(*in_pos)) ++in_pos; // skip whitespace
291332
if(in_pos >= end) break;
@@ -295,7 +336,7 @@ static ssize_t run_command(struct file *file, const char __user *buf,
295336
stop();
296337
return count;
297338
}
298-
else if(*in_pos == '?')
339+
if(*in_pos == '?')
299340
{
300341
if(_handler.frequency)
301342
{
@@ -309,46 +350,66 @@ static ssize_t run_command(struct file *file, const char __user *buf,
309350

310351
break;
311352
}
353+
if(*in_pos == '+'){
354+
++in_pos;
355+
while((in_pos < end) && is_space(*in_pos)) ++in_pos; // skip whitespace
356+
if(in_pos >= end) break;
312357

313-
out_pos=line;
314-
while((in_pos < end) && is_digit(*in_pos)) *out_pos++=*in_pos++;
315-
*out_pos=0;
316-
317-
if(is_digit(line[0]))
318-
{
319-
sscanf(line, "%d", &gpio);
320-
}
321-
else
322-
{
323-
printk(KERN_INFO DRV_NAME " can't read GPIO number.\n");
324-
break;
325-
}
326-
327-
while((in_pos < end) && is_space(*in_pos)) ++in_pos; // skip whitespace
358+
out_pos=line;
359+
while((in_pos < end) && is_digit(*in_pos)) *out_pos++=*in_pos++;
360+
*out_pos=0;
328361

329-
out_pos=line;
330-
while((in_pos < end) && is_digit(*in_pos)) *out_pos++=*in_pos++;
331-
*out_pos=0;
362+
if(is_digit(line[0]))
363+
{
364+
sscanf(line, "%d", &gpio);
365+
}
366+
else
367+
{
368+
printk(KERN_INFO DRV_NAME " can't read GPIO number.\n");
369+
break;
370+
}
371+
372+
while((in_pos < end) && is_space(*in_pos)) ++in_pos; // skip whitespace
373+
374+
out_pos=line;
375+
while((in_pos < end) && is_digit(*in_pos)) *out_pos++=*in_pos++;
376+
*out_pos=0;
377+
378+
if(is_digit(line[0]))
379+
{
380+
sscanf(line, "%u", &frequency);
381+
}
382+
else
383+
{
384+
printk(KERN_INFO DRV_NAME " can't read frequency.\n");
385+
break;
386+
}
387+
388+
while((in_pos < end) && is_space(*in_pos)) ++in_pos; // skip whitespace
332389

333-
if(is_digit(line[0]))
334-
{
335-
sscanf(line, "%u", &frequency);
336-
}
337-
else
338-
{
339-
printk(KERN_INFO DRV_NAME " can't read frequency.\n");
340-
break;
341-
}
390+
out_pos=line;
391+
while((in_pos < end) && is_digit(*in_pos)) *out_pos++=*in_pos++;
392+
*out_pos=0;
342393

343-
if((gpio >= 0) && (frequency > 0))
344-
{
345-
if(start(gpio,frequency) >= 0)
394+
if(is_digit(line[0]))
395+
{
396+
sscanf(line, "%u", &pos);
397+
}
398+
else
346399
{
347-
debug("Started!\n");
400+
printk(KERN_INFO DRV_NAME " can't read pos.\n");
348401
break;
349402
}
350-
}
351403

404+
if((gpio >= 0) && (frequency > 0))
405+
{
406+
if(start(gpio,frequency,pos) >= 0)
407+
{
408+
debug("Started!\n");
409+
break;
410+
}
411+
}
412+
}
352413
printk(KERN_INFO DRV_NAME " can't start.\n");
353414
return 0;
354415
}
@@ -380,13 +441,13 @@ static int __init mymodule_init(void)
380441
_timer_frequency=ahb_clk->rate;
381442
}
382443

383-
ath79_timer_base=ioremap_nocache(AR71XX_RESET_BASE, AR71XX_RESET_SIZE);
444+
ath79_timer_base=ioremap_nocache(AR71XX_RESET_BASE, AR71XX_RESET_SIZE);
384445

385-
gpio_addr=ioremap_nocache(AR71XX_GPIO_BASE, AR71XX_GPIO_SIZE);
446+
gpio_addr=ioremap_nocache(AR71XX_GPIO_BASE, AR71XX_GPIO_SIZE);
386447

387-
gpio_readdata_addr = gpio_addr + GPIO_OFFS_READ;
388-
gpio_setdataout_addr = gpio_addr + GPIO_OFFS_SET;
389-
gpio_cleardataout_addr = gpio_addr + GPIO_OFFS_CLEAR;
448+
gpio_readdata_addr = gpio_addr + GPIO_OFFS_READ;
449+
gpio_setdataout_addr = gpio_addr + GPIO_OFFS_SET;
450+
gpio_cleardataout_addr = gpio_addr + GPIO_OFFS_CLEAR;
390451

391452
_handler.timer=-1;
392453
_handler.irq=-1;

0 commit comments

Comments
 (0)