找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3550|回复: 0
打印 上一主题 下一主题
收起左侧

基于android2.3.3的MCU驱动

[复制链接]
跳转到指定楼层
楼主
ID:75013 发表于 2015-3-21 19:17 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/moduleparam.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <asm/uaccess.h>
#include <linux/cdev.h>

#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/mach-types.h>
#include <linux/delay.h>
#if defined(CONFIG_ARCH_TCC88XX)
#include <mach/TCC88xx_Structures.h>
#include <mach/TCC88xx_Physical.h>
#endif
#include <linux/interrupt.h>
#include <mach/bsp.h>
#include<linux/51boardpcb.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/wait.h>
#include <linux/timer.h>
#include <linux/workqueue.h>

#define MCU_DEBUG    1

#if MCU_DEBUG
#define mcu_dbg(fmt, arg...)     printk(fmt, ##arg)
#else
#define mcu_dbg(arg...)
#endif

#define MCU_NAME"mcu"
#define MCU_I2C_CH1
#define START_REG         0x35

#define MCU_I2C_ADDRESS      0x31

#define MCU_READ0
#define MCU_SEND_CMD1

#define IIC_BLOCK_SIZE               512

#define ZAVE_IRQINT_EI1
#define ZIGBEE_IRQINT_EI0

static struct i2c_client *mcu_i2c_client;

static const struct i2c_device_id mcu_id[] = {
{ MCU_NAME, 0, },
    { }
};

struct mcu_chip {
struct i2c_client *client;
struct cdev  cdev;
struct mutexlock;
int   mcu_major;
unsigned char* buf;
int current_len;
int irq_flag;
wait_queue_head_t r_wait;
wait_queue_head_t w_wait;
struct timer_list mcu_timer;
struct work_struct mcu_work;
};

static struct mcu_chip* pmcu_chip;

static void mcu_send_cmd(unsigned char reg, unsigned char val)
{

unsigned char cmd[2];
int err;
mcu_dbg("%s():reg = 0x%x, val = 0x%x\n", __func__, reg, val);
cmd[0] = reg;
cmd[1] = val;
err = i2c_master_send(mcu_i2c_client, cmd, 2);
if(err < 0)
printk("mcu_send_cmd error!\n");
}


static unsigned char mcu_read_data(unsigned char reg)
{
unsigned char buf;
int err;
err = i2c_master_send(mcu_i2c_client, &reg, 1);
if(err < 0)
printk("mcu_send_cmd error!\n");
err = i2c_master_recv(mcu_i2c_client, &buf, 1);
if(err < 0)
printk("i2c_master_recv error!\n");
mcu_dbg("<------%s():buf = 0x%x\n", __func__, buf);
return buf;
}

static int mcu_read_datas(unsigned char reg, unsigned char *buf, unsigned char count)
{
int ret;
mcu_dbg("%s\n", __func__);
ret = i2c_smbus_read_i2c_block_data(mcu_i2c_client, reg, count, buf);
if (ret < 0) {
dev_err(&mcu_i2c_client->dev, "failed writings to 0x%02x\n", reg);
return ret;
}
return 0;
}

static int mcu_write_datas(unsigned char reg, unsigned char *buf, unsigned char count)
{
   int ret;
mcu_dbg("%s\n", __func__);
ret = i2c_smbus_write_i2c_block_data(mcu_i2c_client, reg, count, buf);
if (ret < 0) {
dev_err(&mcu_i2c_client->dev, "failed writings to 0x%02x\n", reg);
return ret;
}
return count;
}

static void init_mcu_irq(void)
{
mcu_dbg("%s()\n", __func__);
#if defined(CONFIG_ARCH_TCC88XX)
    volatile PGPIO pGPIO = (volatile PGPIO)tcc_p2v(HwGPIO_BASE);
    volatile PPIC pPIC = (volatile PPIC)tcc_p2v(HwPIC_BASE);
//gpioa[6] input zigbee irq ZIGBEE_IRQ INT_EI0
BITCSET(pGPIO->GPAFN0, Hw27-Hw24, 0);
BITCLR(pGPIO->GPAEN,  Hw6);
BITCLR(pGPIO->GPADAT, Hw6);
//select gpioa[6] irq
    BITCSET(pGPIO->EINTSEL0, Hw6-Hw0, 6);
//select INT_EIt0
BITSET(pPIC->INTMSK0, 1<<ZIGBEE_IRQ);//select INT_EI0
//BITSET(pPIC->POL0, 1<<ZIGBEE_IRQ);
BITCLR(pPIC->MODE0, 1<<ZIGBEE_IRQ);       //edge trigger
BITCLR(pPIC->MODEA0, 1<<ZIGBEE_IRQ);    //single triger

//gpiof[24] input zave irq ZAVE_IRQ  INT_EI1
BITCSET(pGPIO->GPFFN3, Hw3-Hw0, 0);
BITCLR(pGPIO->GPFEN,  Hw24);
BITCLR(pGPIO->GPFDAT, Hw24);
//select gpiof[24] irq
    BITCSET(pGPIO->EINTSEL0, Hw14-Hw8, 31 << 8);
//select INT_EIt0
BITSET(pPIC->INTMSK0, 1<<ZAVE_IRQ);//select INT_EI0
    //BITSET(pPIC->POL0, 1<<ZAVE_IRQ);
BITCLR(pPIC->MODE0, 1<<ZAVE_IRQ);       //edge trigger
BITCLR(pPIC->MODEA0, 1<<ZAVE_IRQ);    //single triger
#endif//TCC88xx
}

static void mcu_timer_handler(unsigned long data)
{
struct mcu_chip *chip = container_of((struct timer_list*)data, struct mcu_chip, mcu_timer);
if (schedule_work(&chip->mcu_work) == 0) {
mcu_dbg("cannot schedule work !!!\n");
}
}

static void mcu_timer_registertimer(struct timer_list* ptimer, unsigned int timeover )
{
init_timer(ptimer);
ptimer->expires = jiffies+msecs_to_jiffies(timeover);
ptimer->data = (unsigned long)ptimer;
ptimer->function = mcu_timer_handler;

add_timer(ptimer);
}

static void mcu_work(struct work_struct *work)
{
mcu_dbg("%s()", __func__);
struct mcu_chip *chip = i2c_get_clientdata(mcu_i2c_client);
mcu_timer_registertimer(&chip->mcu_timer, 50 );   // test
}


static irqreturn_t zigbee_irq_handler(int irq, void *data)
{
printk("Zigbee irq!\n");
return IRQ_HANDLED;
}

static irqreturn_t zave_irq_handler(int irq, void *data)
{
printk("Zave irq!\n");
return IRQ_HANDLED;
}


static int mcu_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
int ret;
mcu_dbg("<--------%s\n", __func__);
pmcu_chip->buf= kmalloc(IIC_BLOCK_SIZE, GFP_KERNEL);
if (!pmcu_chip->buf) {
printk("mcu malloc i2c buf error!\n");
return -ENOMEM;
}
pmcu_chip->client = client;
i2c_set_clientdata(client, pmcu_chip);
if (!pmcu_chip->irq_flag) {
enable_irq(ZIGBEE_IRQ);
enable_irq(ZAVE_IRQ);
pmcu_chip->irq_flag = 1;
}
return 0;
}

static int mcu_i2c_remove(struct i2c_client *client)
{
mcu_dbg("<--------%s\n", __func__);
kfree(pmcu_chip->buf);
return 0;
}


/* mma7660 i2c control layer */
static struct i2c_driver mcu_i2c_driver = {
.driver = {
.name= MCU_NAME,
       .owner  = THIS_MODULE,
},
.probe= mcu_i2c_probe,
.remove= mcu_i2c_remove,
.id_table= mcu_id,
};

static int mcu_i2c_register(void)
{
    struct i2c_board_info info;
    struct i2c_adapter *adapter;
    struct i2c_client *client;

mcu_dbg("<--------%s\n", __func__);

    memset(&info, 0, sizeof(struct i2c_board_info));
    info.addr = MCU_I2C_ADDRESS;
    strlcpy(info.type, MCU_NAME, I2C_NAME_SIZE);

    adapter = i2c_get_adapter(MCU_I2C_CH);

    if (!adapter)
    {
        mcu_dbg(KERN_ERR "can't get i2c adapter 0 for mcu\n");
        return -ENODEV;
    }

    client = i2c_new_device(adapter, &info);
    i2c_put_adapter(adapter);
    if (!client)
    {
        mcu_dbg(KERN_ERR "can't add i2c device at 0x%x\n", (unsigned int)info.addr);
        return -ENODEV;
    }

    mcu_i2c_client = client;
pmcu_chip->client = client;
    return 0;
}

static ssize_t mcu_write(struct file *file, const char __user *user, size_t size, loff_t *o)
{
mcu_dbg("%s\n", __func__);
int ret;
DECLARE_WAITQUEUE(wait, current);
struct mcu_chip *chip = i2c_get_clientdata(mcu_i2c_client);
unsigned char *buf = chip->buf;
unsigned char* debug_buf = chip->buf;
mutex_lock(&chip->lock);
add_wait_queue(&chip->w_wait, &wait);
while(chip->current_len == IIC_BLOCK_SIZE){
set_current_state(TASK_INTERRUPTIBLE);
mutex_unlock(&chip->lock);
schedule();
}
if(size > IIC_BLOCK_SIZE - chip->current_len)
size = IIC_BLOCK_SIZE - chip->current_len;
mutex_lock(&chip->lock);
if(copy_from_user( buf, (unsigned char*) user, size)){
printk("copy_from_user error!\n");
ret = -EFAULT;
goto err;
} else
wake_up_interruptible(&chip->r_wait);
mutex_unlock(&chip->lock);
mcu_dbg("\n%s\n", debug_buf);
mcu_dbg("size = %d\n", size);
ret = mcu_write_datas(buf[0], ++buf, size - 1);
err:
remove_wait_queue(&chip->w_wait, &wait);
set_current_state(TASK_RUNNING);
return ret;
}

static ssize_t mcu_read(struct file *file, char __user *user, size_t size, loff_t *o)
{
mcu_dbg("%s\n", __func__);
int ret;
DECLARE_WAITQUEUE(wait, current);
struct mcu_chip *chip = i2c_get_clientdata(mcu_i2c_client);
char *buf = chip->buf;
mutex_lock(&chip->lock);
add_wait_queue(&chip->r_wait, &wait);
while(chip->current_len == 0){
set_current_state(TASK_INTERRUPTIBLE);

mutex_unlock(&chip->lock);
schedule();
}
if(size > chip->current_len)
size = chip->current_len;

ret = mcu_read_datas(buf[0], buf, size);
mutex_lock(&chip->lock);
if(ret == 0){
if(copy_to_user(user, buf, size)){
printk("copy_to_user error!\n");
ret = -EFAULT;
goto err;
} else
wake_up_interruptible(&chip->w_wait);
ret = size;
}
chip->current_len -= size;
mutex_unlock(&chip->lock);
err:
remove_wait_queue(&chip->r_wait, &wait);
set_current_state(TASK_RUNNING);
return ret;
}

static int mcu_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, void *arg)
{
mcu_dbg("%s  (0x%x)  \n", __FUNCTION__, cmd);
unsigned char buf;
struct mcu_chip *chip = i2c_get_clientdata(mcu_i2c_client);
switch (cmd)
{
case MCU_READ:
mcu_dbg("cmd MCU_READ\n");
buf = mcu_read_data(START_REG);
mutex_lock(&chip->lock);
if(copy_to_user((unsigned char*) arg, &buf, sizeof(unsigned char))){
printk("copy_to_user error!\n");
return -EFAULT;
}
mutex_unlock(&chip->lock);
break;
case MCU_SEND_CMD:
mcu_dbg("cmd MCU_SEND_CMD\n");
mutex_lock(&chip->lock);
if(copy_from_user( &buf, (unsigned char*) arg, sizeof(unsigned char))){
printk("copy_from_user error!\n");
return -EFAULT;
}
mutex_unlock(&chip->lock);
mcu_send_cmd(START_REG, buf);
break;
default:
break;
}
return 0;
}

static int mcu_release(struct inode *inode, struct file *filp)
{
i2c_unregister_device(mcu_i2c_client);
i2c_del_driver(&mcu_i2c_driver);
    mcu_i2c_client = NULL;
return 0;
}

static int mcu_open(struct inode *inode, struct file *filp)
{
int ret;
mcu_dbg("<----------%s\n", __func__);
ret = i2c_add_driver(&mcu_i2c_driver);
if (ret < 0) {
mcu_dbg("%s() [Error] failed i2c_add_driver() = %d\n", __func__, ret);
return ret;
}
ret = mcu_i2c_register();
if (ret < 0) {
mcu_dbg("%s() [Error] Failed register i2c client driver for mcu,\n", __func__);
return ret;
}
return 0;
}

static struct file_operations mcu_fops =
{
.owner= THIS_MODULE,
.open= mcu_open,
.release= mcu_release,
.ioctl= mcu_ioctl,
.read      = mcu_read,
.write= mcu_write,
};

static struct class *mcu_class;

int __init mcu_init(void)
{
int ret;
dev_t devno;
mcu_dbg("<------ mcu init\n");
pmcu_chip = kmalloc(sizeof(struct mcu_chip), GFP_KERNEL);
if (!pmcu_chip) {
printk("mcu malloc error!\n");
return -ENOMEM;
}

devno = MKDEV(pmcu_chip->mcu_major, 0);
ret = alloc_chrdev_region(&devno, 0, 1, MCU_NAME);
pmcu_chip->mcu_major = MAJOR(devno);
if (ret < 0){
printk("alloc chardev error!\n");
kfree(pmcu_chip);
return ret;
}

memset(&pmcu_chip->cdev, 0, sizeof(struct cdev));
cdev_init(&pmcu_chip->cdev, &mcu_fops);
pmcu_chip->cdev.owner = THIS_MODULE;
ret = cdev_add(&pmcu_chip->cdev, MKDEV(pmcu_chip->mcu_major, 0), 1);
if(ret)
printk("Error adding mcu cdev\n");
mcu_class = class_create(THIS_MODULE, MCU_NAME);
device_create(mcu_class, NULL, MKDEV(pmcu_chip->mcu_major, 0), NULL, MCU_NAME);
mutex_init(&pmcu_chip->lock);
init_waitqueue_head(&pmcu_chip->r_wait);
init_waitqueue_head(&pmcu_chip->w_wait);
INIT_WORK(&pmcu_chip->mcu_work, mcu_work);
//init arch irq
pmcu_chip->irq_flag = 0;
init_mcu_irq();
ret = request_irq(ZIGBEE_IRQ, zigbee_irq_handler, IRQF_TRIGGER_FALLING, "zigbee", NULL);
  if (ret) {
  printk("<-----failed to request zigbee irq!\n");
kfree(pmcu_chip);
  return ret;
  }
ret = request_irq(ZAVE_IRQ, zave_irq_handler, IRQF_TRIGGER_FALLING, "zave", NULL);
  if (ret) {
  printk("<-----failed to request zave irq!\n");
kfree(pmcu_chip);
  return ret;
  }
disable_irq(ZIGBEE_IRQ);
disable_irq(ZAVE_IRQ);
//mcu_timer_registertimer(pmcu_chip->mcu_major, 50);
return 0;
}

void __exit mcu_exit(void)
{
mcu_dbg("%s()\n", __func__);
    device_destroy(mcu_class, MKDEV(pmcu_chip->mcu_major, 0));   
class_destroy(mcu_class);   
cdev_del(&pmcu_chip->cdev);   
unregister_chrdev_region(MKDEV(pmcu_chip->mcu_major, 0), 1);
kfree(pmcu_chip);
pmcu_chip = NULL;
free_irq(ZAVE_IRQ, NULL);
free_irq(ZIGBEE_IRQ, NULL);
}

module_init(mcu_init);
module_exit(mcu_exit);

MODULE_AUTHOR("jingfeng.shi@emdoor.com");
MODULE_DESCRIPTION("freescale mc9s08ac16");
MODULE_LICENSE("GPL");

平台:tcc8803  系统:android2.3.3    驱动模块:mc9s08ac16(飞思卡尔单片机)
通讯方式:I2C
功能:主控利用i2c与mcu通讯,mcu根据通讯协议利用uart与zigbee和zave通讯。zigbee,zave上报时,利用mcu产生irq。
            整个控制流程使用阻塞式驱动。




分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表