Commit ab15f874 authored by Federico Vaga's avatar Federico Vaga Committed by Adam Wujek

kernel:at91_softpwm: not use anymore

On modern switches the fan are driver by a dedicated FPGA core
that does the PWM. This module is not necessary anymore and not even
the kernel patches to make this module work.
Signed-off-by: Federico Vaga's avatarFederico Vaga <federico.vaga@cern.ch>
parent 08e250b8
DIRS = wr_vic wr_nic wr_rtu at91_softpwm wr_pstats wr_clocksource
DIRS = wr_vic wr_nic wr_rtu wr_pstats wr_clocksource
# We may "LINUX ?= /usr/src/linux-wrswitch", but it's better to leave it empty
......
obj-m = at91_softpwm.o
at91_softpwm-objs := fiq-asm.o fiq-at91sam92.o fiq-module.o softpwm_core.o
export ARCH ?= arm
export CROSS_COMPILE ?= $(CROSS_COMPILE_ARM)
all modules:
$(MAKE) CONFIG_DEBUG_SECTION_MISMATCH=y \
-C $(LINUX) SUBDIRS=$(shell /bin/pwd) modules
# We might "$(MAKE) -C $(LINUX)" but "make clean" with no LINUX defined
# is sometimes useful to have
clean:
rm -f *.mod.c *.o *.ko .*cmd Module.symvers modules.order
rm -rf .tmp_versions
#ifndef __AT91_SOFTPWM_H
#define __AT91_SOFTPWM_H
#define __AT91_SOFTPWM_IOC_MAGIC '5'
#define AT91_SOFTPWM_ENABLE _IO(__AT91_SOFTPWM_IOC_MAGIC, 4)
#define AT91_SOFTPWM_DISABLE _IO(__AT91_SOFTPWM_IOC_MAGIC, 5)
#define AT91_SOFTPWM_SETPOINT _IO(__AT91_SOFTPWM_IOC_MAGIC, 6)
#endif /*__AT91_SOFTPWM_H*/
/*
* Alessandro Rubini, 2007, GPL 2 or later
*
* This file implements entry/exit from the fiq handler.
* It must save r0..r8 (since R8 is used to preserve LR in the few lines
* I added in kernel code, before calling this with "bl").
*/
.globl fiq_entry
.type fiq_entry, #function
/* here, we can use r10..r13 to our pleasure */
fiq_entry:
ldr r11, fiq_handler
movs r11, r11
moveq pc, lr /* nobody registered, return */
/* count the fiq: it doesn't cost too much cpu time */
ldr r10, fiqcount
add r10, r10, #1
str r10, fiqcount
/* save all registers, build sp and branch to C */
adr r9, regpool
stmia r9, {r0 - r8, lr}
adr sp, fiq_sp
ldr sp, [sp]
mov lr, pc
mov pc, r11
adr r9, regpool
ldmia r9, {r0 - r8, pc}
/* data words*/
.globl fiqcount
fiqcount: .long 0
fiq_sp: .long fiq_stack+1020
/* The pointer */
.globl fiq_handler
fiq_handler:
.long 0
regpool:
.space 40 /* 10 registers */
.pool
.align 5
fiq_stack:
.space 1024
/* cpu-specific code for Atmel 92xx timers (actually, only 9263 as it is) */
#include <linux/module.h>
#include <linux/interrupt.h>
#include <asm/io.h>
#include <mach/hardware.h>
#include <mach/at91_aic.h>
#include <mach/at91_pmc.h>
#include <mach/at91_tc.h>
#include "fiq-engine.h"
#include "fiq-at91sam92.h"
static int fiq_irqnr;
/* The following are called from the cpu-independent source file */
int __fiq_register(void (*handler)(void), int irq)
{
int ret;
if (irq < FIQ_IRQ_MIN || irq > FIQ_IRQ_MAX) {
printk(KERN_WARNING "at91-fiq: irq %i not in valid range (%i-%i)\n",
irq, FIQ_IRQ_MIN, FIQ_IRQ_MAX);
return -EINVAL;
}
fiq_irqnr = irq; /* save it for ack and so on */
/* clock the peripheral */
at91_sys_write(AT91_PMC_PCER, 1 << fiq_irqnr);
fiq_handler = handler; /* used both from fiq and non-fiq */
/* request the irq in any case, only turn it to fiq as needed */
ret = request_irq(irq, fake_fiq_handler, IRQF_DISABLED,
"fake-fiq", &fiq_handler);
if (ret) {
printk(KERN_WARNING "at91-fiq: can't request irq %i\n", irq);
return ret;
}
if (fiq_use_fiq) {
at91_sys_write(AT91_AIC_FFER, 1 << fiq_irqnr);
}
return 0;
}
void __fiq_unregister(void (*handler)(void), int irq)
{
if (fiq_use_fiq) {
at91_sys_write(AT91_AIC_FFDR, 1 << fiq_irqnr);
}
free_irq(irq, &fiq_handler);
fiq_handler = NULL;
}
#ifndef __FIQ_AT91SAM92_H__
#define __FIQ_AT91SAM92_H__
/* defines for atmel 926x */
#include <mach/gpio.h>
#include <mach/at91_tc.h>
/*
* We have different setups for each of the three processors.
* This is mainly because of different names, but also because the 9263 differs
*/
#ifdef CONFIG_ARCH_AT91SAM9G45 /* one interrupt for tc block; use TC0 */
/* Limits we support */
# define FIQ_IRQ_MIN AT91SAM9G45_ID_TCB
# define FIQ_IRQ_MAX AT91SAM9G45_ID_TCB
/* Choices we make */
# define FIQ_IRQNR AT91SAM9G45_ID_TCB
# define FIQ_BASE AT91SAM9G45_BASE_TC0
#endif
#ifdef CONFIG_ARCH_AT91SAM9263 /* one interrupt for tc block; use TC0 */
/* Limits we support */
# define FIQ_IRQ_MIN AT91SAM9263_ID_TCB
# define FIQ_IRQ_MAX AT91SAM9263_ID_TCB
/* Choices we make */
# define FIQ_IRQNR AT91SAM9263_ID_TCB
# define FIQ_BASE AT91SAM9263_BASE_TC0
# define FIQ_BITNR AT91_PIN_PB20
#endif
#ifdef CONFIG_ARCH_AT91SAM9260 /* Use TC0 but any of TC0-TC2 can work */
/* Limits we support */
# define FIQ_IRQ_MIN AT91SAM9260_ID_TC0
# define FIQ_IRQ_MAX AT91SAM9260_ID_TC2
/* Choices we make */
# define FIQ_IRQNR AT91SAM9260_ID_TC0
# define FIQ_BASE AT91SAM9260_BASE_TC0
# define FIQ_BITNR AT91_PIN_PB20
#endif
#ifdef CONFIG_ARCH_AT91SAM9261 /* Use TC0 but any of TC0-TC2 can work */
/* Limits we support */
# define FIQ_IRQ_MIN AT91SAM9261_ID_TC0
# define FIQ_IRQ_MAX AT91SAM9261_ID_TC2
/* Choices we make */
# define FIQ_IRQNR AT91SAM9261_ID_TC0
# define FIQ_BASE AT91SAM9261_BASE_TC0
# define FIQ_BITNR AT91_PIN_PA20 /* very few pins are available */
#endif
#define FIQ_MHZ 3 /* timer clock runs at 99.328MHz/32 = 3.104MHz */
#define FIQ_TASK_CONVERT 1000, 3104 /* sysctl-stamp, used in fiq-task.c */
extern void *__fiq_timer_base; /* for register access to the timer */
/* how to get a time stamp (counts, not usec). This cpu counts up */
#define __GETSTAMP() __raw_readl(__fiq_timer_base + AT91_TC_CV)
static inline void __fiq_ack(void)
{
/* read status register */
static int foo;
foo = __raw_readl( __fiq_timer_base + AT91_TC_SR);
}
static inline void __fiq_sched_next_irq(int usec)
{
__raw_writel(usec * FIQ_MHZ, __fiq_timer_base + AT91_TC_RC);
}
/* This is not needed for the fiq engine, but our example task wants it */
#define __fiq_set_gpio_value(a,b) at91_set_gpio_value(a, b);
#endif /* __FIQ_AT91SAM92_H__ */
#ifndef __FIQ_ENGINE_H__
#define __FIQ_ENGINE_H__
#include <linux/irqreturn.h>
/* include cpu-specific defines to customize use */
#if defined(CONFIG_ARCH_AT91)
# include "fiq-at91sam92.h"
#elif defined(CONFIG_ARCH_PXA)
# include "fiq-pxa.h"
#elif defined(CONFIG_ARCH_OMAP3)
# include "fiq-omap3.h"
#else
# error "This package has no support for your architecture"
#endif
/* exported by the kernel (our patch) */
extern void (*fiq_userptr)(void);
/* declared in fiq-asm.S */
extern void fiq_entry(void);
extern unsigned long fiqcount;
extern void (*fiq_handler)(void);
/* declared in fiq-module.c */
extern irqreturn_t fake_fiq_handler(int irq, void *dev);
extern int fiq_verbose;
extern int fiq_use_fiq; /* false by default */
extern int fiq_register(void (*handler)(void), int irq);
extern int fiq_unregister(void (*handler)(void), int irq);
/* declared in the cpu-specific source file */
extern int __fiq_register(void (*handler)(void), int irq);
extern void __fiq_unregister(void (*handler)(void), int irq);
#endif /* __FIQ_ENGINE_H__ */
/*
* Fast-interrupt infrastructure for a real-time task.
* Alessandro Rubini, 2007,2008 GPL 2 or later.
* This code is generic, you must supplement it with cpu-specific code
* in another source file.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/timer.h>
#include <linux/interrupt.h>
#include <asm/io.h>
#include "fiq-engine.h"
int fiq_use_fiq;
EXPORT_SYMBOL(fiq_use_fiq);
int fiq_verbose;
/*
* High-level interface (cpu-independent)
*/
/* An irq handler, faking fiq, to test with fiq=0 */
irqreturn_t fake_fiq_handler(int irq, void *dev)
{
(*fiq_handler)();
return IRQ_HANDLED;
}
/* Software PWM emulation for AT91SAM9xxx MCUs. Relies on Alessandro's fiq-engine.
Licensed under GPL v2 (c) T.W. 2012
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/ioctl.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <mach/gpio.h>
#include <mach/at91_tc.h>
#include <mach/at91sam9g45.h>
#include "fiq-engine.h"
#include "at91_softpwm.h"
struct at91_softpwm_dev {
int in_use;
int pin;
int setpoint;
int state;
void *timer_base;
};
#define PERIOD 3000
static struct at91_softpwm_dev dev;
static void at91_softpwm_fiq_handler(void)
{
static int status;
status = __raw_readl(dev.timer_base + AT91_TC_SR);
if(!dev.in_use)
return;
if(dev.state)
{
__raw_writel(dev.setpoint, dev.timer_base + AT91_TC_RC); /* FIQ Rate = 1 kHz */
at91_set_gpio_value(dev.pin, 0);
dev.state = 0;
} else {
__raw_writel(PERIOD-dev.setpoint, dev.timer_base + AT91_TC_RC); /* FIQ Rate = 1 kHz */
at91_set_gpio_value(dev.pin, 1);
dev.state = 1;
}
}
static long at91_softpwm_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
{
/* Check cmd type */
if (_IOC_TYPE(cmd) != __AT91_SOFTPWM_IOC_MAGIC)
return -ENOIOCTLCMD;
switch(cmd) {
case AT91_SOFTPWM_ENABLE:
dev.pin = arg;
dev.in_use = 1;
dev.state = 0;
return 0;
case AT91_SOFTPWM_DISABLE:
dev.in_use = 0;
dev.state = 0;
return 0;
case AT91_SOFTPWM_SETPOINT:
dev.setpoint = PERIOD - (arg * PERIOD / 1000);
return 0;
default:
return -ENOIOCTLCMD;
}
}
static struct file_operations at91_softpwm_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = at91_softpwm_ioctl
};
// TODO check available minor numbers
static struct miscdevice at91_softpwm_misc = {
.minor = 78,
.name = "at91_softpwm",
.fops = &at91_softpwm_fops
};
int __init at91_softpwm_init(void)
{
int err;
printk("at91_softpwm: initializing\n");
// register misc device
err = misc_register(&at91_softpwm_misc);
if (err < 0) {
printk(KERN_ERR "%s: Can't register misc device\n",
KBUILD_MODNAME);
return err;
}
dev.in_use = 0;
dev.setpoint = 0;
dev.timer_base = ioremap_nocache(AT91SAM9G45_BASE_TC2, 0x40);
__fiq_register(at91_softpwm_fiq_handler, AT91SAM9G45_ID_TCB);
__raw_writel(AT91_TC_TIMER_CLOCK3
| AT91_TC_WAVE
| AT91_TC_WAVESEL_UP_AUTO,
dev.timer_base + AT91_TC_CMR); /* Clock = 3 MHz */
__raw_writel(PERIOD, dev.timer_base + AT91_TC_RC); /* FIQ Rate = 1 kHz */
__raw_writel((1<<4) /* rc/rb compare */, dev.timer_base + AT91_TC_IER);
__raw_writel(AT91_TC_CLKEN | AT91_TC_SWTRG, dev.timer_base + AT91_TC_CCR);
return 0;
}
void __exit at91_softpwm_exit(void)
{
__fiq_unregister(at91_softpwm_fiq_handler, AT91SAM9G45_ID_TCB);
__raw_writel((1<<4)/* rc compare */, dev.timer_base + AT91_TC_IDR);
__raw_writel(AT91_TC_CLKDIS, dev.timer_base + AT91_TC_CCR);
if(dev.in_use)
at91_set_gpio_value(dev.pin, 0);
dev.in_use = 0;
misc_deregister(&at91_softpwm_misc);
iounmap(dev.timer_base);
}
module_init(at91_softpwm_init);
module_exit(at91_softpwm_exit);
MODULE_DESCRIPTION("Atmel AT91SAM9G45 software PWM");
MODULE_VERSION("0.1");
MODULE_LICENSE("GPL");
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment