📄 w90p710_usi.c
字号:
/****************************************************************************
*
* Copyright (c) 2004 - 2006 Winbond Electronics Corp. All rights reserved.
*
****************************************************************************/
/****************************************************************************
*
* FILENAME
* w90p710_usi.c
*
* VERSION
* 1.0
*
* DESCRIPTION
* USI driver supported for W90n710.
*
* FUNCTIONS
* all functions, if they has return value, return 0 if they success, others failed.
*
* HISTORY
* 2006/01/10 Created by QFu
*
* REMARK
* None
*************************************************************************/
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/time.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <asm/arch/hardware.h>
#include <asm/arch/irqs.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/string.h>
#include <asm/atomic.h>
#include "w90p710_usi.h"
//#define USI_DEBUG
//#define USI_DEBUG_ENABLE_ENTER_LEAVE
//#define USI_DEBUG_ENABLE_MSG
//#define USI_DEBUG_ENABLE_MSG2
#ifdef USI_DEBUG
#define PDEBUG(fmt, arg...) printk(fmt, ##arg)
#else
#define PDEBUG(fmt, arg...)
#endif
#ifdef USI_DEBUG_ENABLE_ENTER_LEAVE
#define ENTER() PDEBUG("[%-20s] : Enter...\n", __FUNCTION__)
#define LEAVE() PDEBUG("[%-20s] : Leave...\n", __FUNCTION__)
#else
#define ENTER()
#define LEAVE()
#endif
#ifdef USI_DEBUG_ENABLE_MSG
#define MSG(msg) PDEBUG("[%-20s] : %s\n", __FUNCTION__, msg)
#else
#define MSG(msg)
#endif
#ifdef USI_DEBUG_ENABLE_MSG2
#define MSG2(fmt, arg...) PDEBUG("[%-20s] : "fmt, __FUNCTION__, ##arg)
#define PRNBUF(buf, count) {int i;MSG2("Data: ");for(i=0;i<count;i++)\
PDEBUG("%02x ", buf[i]);PDEBUG("\n");}
#else
#define MSG2(fmt, arg...)
#define PRNBUF(buf, count)
#endif
#define usi_inl(addr) (*((volatile u32 *)(addr)))
#define usi_outl(val, addr) (*((volatile u32 *)(addr))=(val))
static atomic_t usi_available = ATOMIC_INIT(1);
static struct usi_parameter global_parameter;
static wait_queue_head_t wq;
static volatile int trans_finish, slave_select;
void usi_deselect_slave(void)
{
usi_outl(usi_inl(USI_SSR)&0xc, USI_SSR);
slave_select = 0;
}
void usi_select_slave(int x)
{
usi_outl((global_parameter.active_level << 2)|(1 << x), USI_SSR);
slave_select = 1;
}
static void usi_interrupt(int irq, void * dev_id, struct pt_regs *regs)
{
u32 reg;
ENTER();
reg = usi_inl(USI_CNTRL);
if (!(reg & 0x10000)) /* it not me ? */
return;
reg |= 0x10000;
usi_outl(reg, USI_CNTRL); /* clear interrupt flag */
trans_finish = 1;
wake_up_interruptible(&wq);
LEAVE();
}
static int usi_transit(struct usi_data *data_ptr)
{
u32 reg,mask;
ENTER();
if (slave_select == 0)
return -ENODEV;
mask = (1 << data_ptr->bit_len) - 1;
MSG2("bit_len : %d, mask : %x\n", data_ptr->bit_len, mask);
usi_outl(data_ptr->write_data & mask , USI_TX0); /* write data to hardware buffer */
MSG2("-> %x\n", data_ptr->write_data & mask);
reg = (global_parameter.sleep << 12) |
(global_parameter.lsb << 10) |
(data_ptr->bit_len << 3) |
(global_parameter.tx_neg << 2) |
(global_parameter.rx_neg << 1) | 0x20001;
trans_finish = 0;
usi_outl(reg, USI_CNTRL); /* start */
wait_event_interruptible(wq, trans_finish != 0);
data_ptr->read_data = usi_inl(USI_RX0) & mask;
MSG2("<- %x\n", data_ptr->read_data & mask);
LEAVE();
return 0;
}
static int usi_ioctl(struct inode *inode, struct file *flip, unsigned int cmd, unsigned long arg)
{
int err = 0;
struct usi_parameter tmp_parameter;
struct usi_data tmp_data;
ENTER();
if(_IOC_TYPE(cmd) != USI_IOC_MAGIC) return -ENOTTY;
if(_IOC_NR(cmd) > USI_IOC_MAXNR) return -ENOTTY;
if(_IOC_DIR(cmd) & _IOC_READ)
err = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd));
else if(_IOC_DIR(cmd) & _IOC_WRITE)
err = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd));
if(err)
return -EFAULT;
switch(cmd) {
case USI_IOC_GETPARAMETER:
if (copy_to_user((void *)arg, &global_parameter,
sizeof(struct usi_parameter)))
return -EFAULT;
break;
case USI_IOC_SETPARAMETER:
if (copy_from_user(&tmp_parameter, (void *)arg,
sizeof(struct usi_parameter)))
return -EFAULT;
memcpy(&global_parameter, &tmp_parameter,
sizeof(struct usi_parameter));
usi_outl(global_parameter.divider, USI_DIVIDER); /* update clock */
break;
case USI_IOC_SELECTSLAVE:
if (arg < -1 && arg > 1)
return -EPERM;
if (arg == -1)
usi_deselect_slave();
else
usi_select_slave(arg);
break;
case USI_IOC_TRANSIT:
if (copy_from_user(&tmp_data, (void *)arg, sizeof(tmp_data)))
return -EFAULT;
err = usi_transit(&tmp_data);
if (err)
return err;
if (copy_to_user((void *)arg, &tmp_data, sizeof(tmp_data)))
return -EFAULT;
break;
default:
return -ENOTTY;
}
LEAVE();
return 0;
}
static int usi_open(struct inode *inode, struct file *filp)
{
u32 reg;
int retval = -EBUSY;
ENTER();
if (! atomic_dec_and_test (&usi_available))
goto failed;
global_parameter.active_level = 0;
global_parameter.lsb = 0;
global_parameter.rx_neg = 0;
global_parameter.tx_neg = 1;
global_parameter.divider = 0x1;
global_parameter.sleep = 0;
slave_select = 0;
reg = usi_inl(0xFFF83050) & 0xfff00fff;
reg |= 0xaa000;
usi_outl(reg, 0xFFF83050);
reg = usi_inl(USI_CNTRL);
reg |= 0x20000;
usi_outl(reg, USI_CNTRL);
MSG2("GPIO 5 : %x\n", usi_inl(0xFFF83050));
usi_outl(global_parameter.divider, USI_DIVIDER); /* set clock */
if ((retval = request_irq(INT_SPI, usi_interrupt, SA_INTERRUPT, "usi", NULL)) < 0) {
printk("usi : request irq error\n");
goto failed;
}
LEAVE();
return 0; /* success */
failed:
atomic_inc(&usi_available); /* release the device */
return retval;
}
static int usi_release(struct inode *inode, struct file *flip)
{
u32 reg;
ENTER();
reg = usi_inl(USI_CNTRL);
reg &= 0xffff;
usi_outl(reg, USI_CNTRL);
free_irq(INT_SPI, NULL);
usi_deselect_slave();
atomic_inc(&usi_available); /* release the device */
LEAVE();
return 0;
}
struct file_operations usi_fops =
{
owner: THIS_MODULE,
open: usi_open,
release: usi_release,
ioctl: usi_ioctl,
};
static int __init usi_init(void)
{
u32 reg;
int result;
init_waitqueue_head(&wq);
/* every things ok, now, we can register char device safely */
result = register_chrdev(USI_MAJOR, "usi", &usi_fops);
if( result < 0){
unregister_chrdev(USI_MAJOR, "usi");
printk("usi : can't get major %d\n", USI_MAJOR);
goto failed;
}
printk("USI driver has been installed successfully!\n");
failed:
return result;
}
static void __exit usi_exit(void)
{
unregister_chrdev(USI_MAJOR, "usi");
}
module_init(usi_init);
module_exit(usi_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -