Linux I2C 设备驱动

dts device tree 文件描述

i2c1: i2c@02203000 {
            #address-cells = <1>;
            #size-cells = <0>;
            compatible = "snps,designware-i2c";
            reg = <0x02203000 0x1000>;
            clocks = <&apb0>;
            interrupts = <2>;
            status = "okay";

            //新添加的设备描述
            apt: apt32f101xx@5a {
                compatible = "apt,apt32f101xx"; 驱动文件of_match
                #address-cells = <1>;
                #size-cells = <0>;
                reg = <0x5a>; // 设备I2C地址7bit   (8bit addr /2) 右移1位 ,
                //reg = <0x3c>; // 0x78(8bit), 0x78 / 2 = 0x3c(7bit) 
            };
        };

系统启动后会创建/sys/devices/platform/soc/2203000.i2c/i2c-1/1-005a
如果没成功创建设备节点,加载驱动时probe不会调用
/**************************************************************************************************************************************
 * 
 * File Name    : apt32f101.c
 * Date         : 2018-06-25  
 * Author       : [email protected]
 * 
 * function     : APT32F101 MCU driver.
 * 
 **************************************************************************************************************************************/

#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/types.h>
#include <linux/types.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/input-polldev.h>
#include <linux/delay.h>
#include <linux/wait.h>
#include <linux/poll.h>
#include <linux/slab.h>
#include <linux/freezer.h>
#include <linux/uaccess.h>
#include <linux/miscdevice.h>
#include <linux/pm_runtime.h>
#include <linux/atomic.h>
#include <linux/of_device.h>
#include <linux/device.h>
#include <linux/sysfs.h>
#include <linux/string.h>
#include <linux/dmi.h>
#include <linux/idr.h>
#include <linux/mutex.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio/driver.h>
#include <linux/kdev_t.h>
#include <linux/devcoredump.h>
#include <linux/list.h>
#include <linux/fs.h>
#include <linux/workqueue.h>
#include <linux/timer.h>
#include <linux/kthread.h>

#include "apt32f101.h"

#define SYSTEM_STATUS_CHECK_TIME (3 * 100) // n秒


#define D_SUPPORT_CLASS_SYSFS 0
#define D_SUPPORT_KTHREAD
#define D_SUUPORT_DELAYED_TASKLET
#define D_SUPPORT_KEY_IRQ

#define dprintk printk


// 高字节命令码,低字节指令码

// 系统命令码定义
#define D_SYSCMD_CODE_MOTOR     0x11 // 马达电机
#define D_SYSCMD_CODE_EYELED    0x12 // 眼灯控制
#define D_SYSCMD_CODE_EARLED    0x13 // 耳灯控制
#define D_SYSCMD_CODE_STATUS    0x14 // 系统状态    电池电量,充电检查


// 马达运动命令
#define D_MOTOR_ACTION_WHEEL_STOP               (D_SYSCMD_CODE_MOTOR << 8 | 0x00)
#define D_MOTOR_ACTION_WHEEL_BREAK              (D_SYSCMD_CODE_MOTOR << 8 | 0x01)   
#define D_MOTOR_ACTION_WHEEL_FORWARD            (D_SYSCMD_CODE_MOTOR << 8 | 0x02)
#define D_MOTOR_ACTION_WHEEL_BACKWARD           (D_SYSCMD_CODE_MOTOR << 8 | 0x03)
#define D_MOTOR_ACTION_WHEEL_ROTATION_LEFT      (D_SYSCMD_CODE_MOTOR << 8 | 0x04)
#define D_MOTOR_ACTION_WHEEL_ROTATION_RIGHT     (D_SYSCMD_CODE_MOTOR << 8 | 0x05)
#define D_MOTOR_ACTION_WHEEL_LEFT_STOP          (D_SYSCMD_CODE_MOTOR << 8 | 0x06)
#define D_MOTOR_ACTION_WHEEL_LEFT_BREAK         (D_SYSCMD_CODE_MOTOR << 8 | 0x07)
#define D_MOTOR_ACTION_WHEEL_LEFT_FORWARD       (D_SYSCMD_CODE_MOTOR << 8 | 0x08)
#define D_MOTOR_ACTION_WHEEL_LEFT_BACKWARD      (D_SYSCMD_CODE_MOTOR << 8 | 0x09)
#define D_MOTOR_ACTION_WHEEL_RIGHT_STOP         (D_SYSCMD_CODE_MOTOR << 8 | 0x0a)
#define D_MOTOR_ACTION_WHEEL_RIGHT_BREAK        (D_SYSCMD_CODE_MOTOR << 8 | 0x0b)
#define D_MOTOR_ACTION_WHEEL_RIGHT_FORWARD      (D_SYSCMD_CODE_MOTOR << 8 | 0x0c)
#define D_MOTOR_ACTION_WHEEL_RIGHT_BACKWARD     (D_SYSCMD_CODE_MOTOR << 8 | 0x0d)
#define D_MOTOR_ACTION_HEAD_STOP                (D_SYSCMD_CODE_MOTOR << 8 | 0x10)
#define D_MOTOR_ACTION_HEAD_BREAK               (D_SYSCMD_CODE_MOTOR << 8 | 0x11)
#define D_MOTOR_ACTION_HEAD_LEFT                (D_SYSCMD_CODE_MOTOR << 8 | 0x12)
#define D_MOTOR_ACTION_HEAD_RIGHT               (D_SYSCMD_CODE_MOTOR << 8 | 0x13)

// 系统状态控制命令
#define D_SYSSTATUS_GET_BAT         (D_SYSCMD_CODE_STATUS << 8 | 0x01)  // 获取电池电量
#define D_SYSSTATUS_GET_CHARGE      (D_SYSCMD_CODE_STATUS << 8 | 0x02)  // 获取充电状态



static const keymap_t keymap[] = 
{
    {KEYCODE_POWER, KEY_POWER},
    {KEYCODE_VOLUME_DOWN,KEY_VOLUMEDOWN},
    {KEYCODE_VOLUME_UP, KEY_VOLUMEUP},
    {KEYCODE_MUTE, KEY_MUTE},
    {KEYCODE_HOME, KEY_HOME},
    {KEYCODE_WIFI, KEY_W},
    {KEYCODE_PREVIOUS, KEY_PREVIOUS},
}; 


#ifdef D_SUPPORT_KEY_IRQ
static struct gpio_desc *gpio_irq_key;
#endif

struct apt32f101_priv *priv_p;
struct apt32f101_priv *priv;

struct apt32f101_priv {
    int irq;
    const struct apt32f101_chipdef *cdef;
    struct i2c_client *client;
    struct input_dev *input_dev;
#ifdef D_SUPPORT_KTHREAD    
    struct task_struct  *pthread;
#endif  
#ifdef D_SUUPORT_DELAYED_TASKLET
    struct delayed_work apt_work;
    struct workqueue_struct *apt_workqueue;
#endif  
};

struct apt32f101_chipdef {
    u8  key_reg; // 按键值寄读取存器
    u8  battery_reg; // 电池电量值读取寄存器
    u8  motor_cmd_reg;  // 马达命令写入寄存器
    u8  sys_status_reg; // 系统状态读取寄存器
};

static const struct apt32f101_chipdef apt32f101_cdef = {
    .key_reg = 0x00,  // 按键值寄读取存器
    .battery_reg = 0x01, // 电池电量值读取寄存器
    .motor_cmd_reg = 0x02, // 马达命令写入寄存器
    .sys_status_reg = 0x03, // 系统状态读取寄存器
};

struct timer_list systimer;

//i2c_smbus_read_byte() 从设备读取一个字节(不定义位置偏移,使用以前发起的命令的偏移)

//i2c_smbus_write_byte() 从设备写入一个字节(使用以前发起的命令的偏移)

//i2c_smbus_write_quick() 向设备发送一个比特 ( 取代清单 8.1 中的 Rd/Wr 位 ).

//i2c_smbus_read_byte_data() 从设备指定偏移处读取一个字节

//i2c_smbus_write_byte_data() 向设备指定偏移处写入一个字节

//i2c_smbus_read_word_data() 从设备指定偏移处读取二个字节

//i2c_smbus_write_word_data() 向设备指定偏移处写入二个字节

//i2c_smbus_read_block_data() 从设备指定偏移处读取一块数据 .

//i2c_smbus_write_block_data()  //向设备指定偏移处写入一块数据 . (<= 32 字

/* I2C bus functions */

static int write_d8(void *client, u8 val)
{
    return i2c_smbus_write_byte(client, val);
}

static int write_r8d8(void *client, u8 reg, u8 val)
{
    return i2c_smbus_write_byte_data(client, reg, val);
}

static int write_r8d16(void *client, u8 reg, u16 val)
{
    return i2c_smbus_write_word_data(client, reg, val);
}

static int read_d8(void *client)
{
    return i2c_smbus_read_byte(client);
}

static int read_r8d8(void *client, u8 reg)
{
    return i2c_smbus_read_byte_data(client, reg);
}

static int read_r8d16(void *client, u8 reg)
{
    return i2c_smbus_read_word_data(client, reg);
}

static int device_i2c_rxdata( struct i2c_client *client, unsigned char *rxData, int length)
{
    struct i2c_msg msgs[] = 
    {
        {
                .addr   = client->addr, 
                .flags  = 0, 
                .len    = 1, 
                .buf    = rxData,
        }, 
        {
                .addr   = client->addr,
                .flags  = I2C_M_RD, 
                .len    = length, 
                .buf    = rxData,
        },
    };

    if (i2c_transfer(client->adapter, msgs, 2) < 0) {
        dev_err(&client->dev, "%s: transfer failed.", __func__);
        return -EIO;
    }

    return 0;
}

static int device_i2c_txdata( struct i2c_client *client, unsigned char *txData, int length)
{
    struct i2c_msg msg[] = 
    {
        {
                .addr   = client->addr,
                .flags  = 0, 
                .len    = length, 
                .buf    = txData,
        }, 
    };

    if (i2c_transfer(client->adapter, msg, 1) < 0) {
        dev_err(&client->dev, "%s: transfer failed.", __func__);
        return -EIO;
    }

    return 0;
}

#define LM8323_MAX_DATA 8

/*
 * To write, we just access the chip's address in write mode, and dump the
 * command and data out on the bus.  The command byte and data are taken as
 * sequential u8s out of varargs, to a maximum of LM8323_MAX_DATA.
 */
static int I2C_write(struct apt32f101_priv *priv, int len, ...)
{
    int ret, i;
    //va_list ap;
    u8 data[LM8323_MAX_DATA];

    //va_start(ap, len);

    if (unlikely(len > LM8323_MAX_DATA)) {
        dev_err(&priv->client->dev, "tried to send %d bytes\n", len);
        //va_end(ap);
        return 0;
    }

    //for (i = 0; i < len; i++)
    //  data[i] = va_arg(ap, int);

    //va_end(ap);

    /*
     * If the host is asleep while we send the data, we can get a NACK
     * back while it wakes up, so try again, once.
     */
    ret = i2c_master_send(priv->client, data, len);
    if (unlikely(ret == -EREMOTEIO))
        ret = i2c_master_send(priv->client, data, len);
    if (unlikely(ret != len))
        dev_err(&priv->client->dev, "sent %d bytes of %d total\n",
            len, ret);

    return ret;
}

/*
 * To read, we first send the command byte to the chip and end the transaction,
 * then access the chip in read mode, at which point it will send the data.
 */
static int I2C_read(struct apt32f101_priv *priv, u8 cmd, u8 *buf, int len)
{
    int ret;

    /*
     * If the host is asleep while we send the byte, we can get a NACK
     * back while it wakes up, so try again, once.
     */
    ret = i2c_master_send(priv->client, &cmd, 1);
    if (unlikely(ret == -EREMOTEIO))
        ret = i2c_master_send(priv->client, &cmd, 1);
    if (unlikely(ret != 1)) {
        dev_err(&priv->client->dev, "sending read cmd 0x%02x failed\n",
            cmd);
        return 0;
    }

    ret = i2c_master_recv(priv->client, buf, len);
    if (unlikely(ret != len))
        dev_err(&priv->client->dev, "wanted %d bytes, got %d\n",
            len, ret);

    return ret;
}


static int apt32f101_smbus_read(struct apt32f101_priv *priv, u8 reg)
{
    int ret;

    dev_dbg(&priv->client->dev, "read register 0x%02X=", reg);

    ret =  i2c_smbus_read_byte_data(priv->client, reg);
    if (ret) {
        dev_err(&priv->client->dev,
            "register read to 0x%02X failed (error %d)",
            reg, ret);
    }
    return ret;
}


static int apt32f101_smbus_write(struct apt32f101_priv *priv, u8 reg, u8 val)
{
    int ret;

    dev_dbg(&priv->client->dev, "writing register 0x%02X=0x%02X", reg, val);

    ret =  i2c_smbus_write_byte_data(priv->client, reg, val);
    if (ret) {
        dev_err(&priv->client->dev,
            "register write to 0x%02X failed (error %d)",
            reg, ret);
    }
    return ret;
}


#if D_SUPPORT_CLASS_SYSFS
static ssize_t action_show(struct class *clazz, struct class_attribute *attr, char *buf)
{
    dprintk("%s:%d\n", __FUNCTION__, __LINE__);
    return 0;
}

static ssize_t action_store(struct class *clazz, struct class_attribute *attr, const char *buf, ssize_t size)
{
    dprintk("%s:%d\n", __FUNCTION__, __LINE__);
    return 0;
}

static class_attribute motor_class_attrs[] = {
    __ATTR(action, S_IRUGO | S_IWUSR, action_show, action_store),
    __ATTR_NULL,
}; 

static struct class motor_class = {
    .name = "apt32f101",
    .owner = THIS_MODULE,
    .class_attrs = motor_class_attrs,
};
#endif


static long apt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    u8 cmd_buf[8] = {0};

    dprintk("%s:%d,  cmd:0x%04x\n",__FUNCTION__, __LINE__, cmd);

    cmd_buf[0] = (char)((cmd >> 8) & 0xFF); 
    cmd_buf[1] = (char)(cmd & 0xFF);

    dprintk("ioctl cmd = 0x%02x, data = 0x%02x\n", cmd_buf[0], cmd_buf[1]);


    switch(cmd_buf[0]) {
        case D_SYSCMD_CODE_STATUS:
        {
            if (cmd_buf[1] == D_SYSSTATUS_GET_BAT) {
                return read_r8d8(priv_p->client, SYSREG_BAT);
            }

            if (cmd_buf[1] == D_SYSSTATUS_GET_CHARGE) {
                return read_r8d8(priv_p->client, SYSREG_ACIN);
            }
        }
            break;

        case D_SYSCMD_CODE_MOTOR:
        {
            write_r8d8(priv_p->client, SYSREG_CMD_CODE, cmd_buf[0]);
            write_r8d8(priv_p->client, SYSREG_CMD_DATA, cmd_buf[1]);
        }
            break;

        default:
            printk("APTF32101 IOCTL UNKNOW CMD\n");
            break;
    }




    #if 0
    int i=0;
    for(i = 0; i<10; i++)
    {
            dprintk("keycode:0x%2x\n", read_r8d8(priv_p->client, 0x00));
    }

    #endif

    #if 0  //read adc val
    int i = 0; 
    int val = 0;
    val = 0;
    for (i=0; i<21; i++)
    {
        u16 adc=0;
        adc = (read_r8d8(priv_p->client, 0x19) << 8) & 0xf00;
        adc |= read_r8d8(priv_p->client, 0x20);
        val += adc;
        dprintk("i = %d, key adc:%d\n",i, adc);
        //dprintk("key adc: 0x%2x%2x\n", read_r8d8(priv_p->client, 0x00), read_r8d8(priv_p->client, 0x01));
    }
    //dprintk(" i = %d  ,key adc :%d\n",i,  val/i);
    #endif

    #if 0
    u8 buffer[10];

    /* get xyz high/low bytes, 0x12 */  
    buffer[0] = 0x01;
    /* Read acceleration data */    
    if (device_i2c_rxdata(priv_p->client, buffer, 4)!= 0)       
    {
        dprintk("**************************\n");
    } else {
        dprintk("==========================\n");
    }
    //I2C_write(priv_p, 3, 0x00, send_buf[0], send_buf[1]);
    //I2C_write(priv_p, 3, 0x01, send_buf[1]);
    //I2C_read(priv_p, 0x01, buf, 8);
    #endif



    return 0;   
}   


int apt_read(struct file *filp, char __user *buf, size_t count, loff_t *offset)
{
    int ret = 0;
    //motor_dev_t *pdev = filp->private_data;
    //ret = copy_to_user(buf, pdev->obsavo_status, count);


    return ret; 
}

int apt_write(struct file *filp, const char __user *buf, size_t count, loff_t *offset)  
{
    int ret = 0;
    //motor_dev_t *pdev = filp->private_data;
    //ret = copy_from_user(pdev->obsavo_status, buf, count);
    return ret;
}

static int apt_open(struct inode *inode, struct file *file)
{
    int ret;
    dprintk("%s:%d\n", __FUNCTION__, __LINE__);

    ret = nonseekable_open(inode, file);
    if( ret < 0 )
        return ret;

    file->private_data = NULL;
    return 0;
}

static int apt_release(struct inode *inode, struct file *file)
{
    dprintk("%s:%d\n", __FUNCTION__, __LINE__);
    return 0;
}


static struct file_operations apt_fops = {
    .owner = THIS_MODULE,
    .open = apt_open,
    .read = apt_read,
    .write = apt_write,
    .release = apt_release,
    .unlocked_ioctl = apt_ioctl,
};

static struct miscdevice apt_device = {
    .minor = MISC_DYNAMIC_MINOR,
    .name = "apt32f101xx",
    .fops = &apt_fops,
};



unsigned int get_keycode_keymap(unsigned char key)
{
    int i=0;
    for(i=0; i < sizeof(keymap)/sizeof(keymap_t); i++)
    {
        if(keymap[i].key_val == key)
            return keymap[i].key_code;
    }
}

static void apt_timer_func(unsigned long arg)
{
    //dprintk("Timer do func  \n");

#if 0
    input_report_key(priv_p->input_dev, KEY_MUTE, 1);
    input_sync(priv_p->input_dev);

    //msleep(1000);
    input_report_key(priv_p->input_dev, KEY_MUTE, 0);
    input_sync(priv_p->input_dev);

#endif

    systimer.expires = jiffies + SYSTEM_STATUS_CHECK_TIME;// msecs_to_jiffies(10); // SYSTEM_STATUS_CHECK_TIME;
    add_timer(&systimer);
}

#ifdef D_SUUPORT_DELAYED_TASKLET
static void apt_work_func(struct work_struct *work)
{
    u8 event, code, change, pressed;

    code = read_r8d8(priv_p->client, SYSREG_KEY_CODE);
    event = read_r8d8(priv_p->client, SYSREG_KEY_EVENT);
    //dprintk("keyevent:0x%02x,   keycode:0x%02x\n", event, code);
    //dprintk("keycode:0x%2x\n", read_r8d8(priv_p->client, 0x00));
    if(code != KEYCODE_DUMP) {
        // key pressed
        pressed = 1;
        change = code;
        input_report_key(priv_p->input_dev, get_keycode_keymap(change), 1); 
        input_sync(priv_p->input_dev);

    } else if (pressed) {
        // key release
        pressed = 0;
        input_report_key(priv_p->input_dev, get_keycode_keymap(change), 0);
        input_sync(priv_p->input_dev);

    } else {
        // no event
    }

    //dprintk("keyevent:0x%02x,   keycode:0x%02x\n", event, code);
    queue_delayed_work(priv_p->apt_workqueue, &priv_p->apt_work, 20);
}
#endif


#ifdef D_SUPPORT_KEY_IRQ
static irqreturn_t apt_key_isr(int irq, void *dev_id)
{
    //struct apt32f101_priv *priv = (struct apt32f101_priv*)dev_id;
      //printk("%s enter, %s: gpio:%d, irq: %d\n", __func__, data->name, data->gpio, data->irq);
    dprintk("==========key irq==========\n");
    queue_delayed_work(priv_p->apt_workqueue, &priv_p->apt_work, 20);

    return IRQ_HANDLED;
}
#endif

#ifdef D_SUPPORT_KTHREAD
int apt_thread_func(void *data) 
{
    u8 event, code, pressed, change = 0;

    do{

        #if 0
        //dprintk("==============\n");  
        code = read_r8d8(priv_p->client, SYSREG_KEY_CODE);
        event = read_r8d8(priv_p->client, SYSREG_KEY_EVENT);
        //dprintk("keyevent:0x%02x,   keycode:0x%02x\n", event, code);
        //dprintk("keycode:0x%2x\n", read_r8d8(priv_p->client, 0x00));
        if(code != KEYCODE_DUMP) {
            // key pressed
            pressed = 1;
            change = code;
            input_report_key(priv_p->input_dev, get_keycode_keymap(change), 1); 
            input_sync(priv_p->input_dev);

        } else if (pressed) {
            // key release
            pressed = 0;
            input_report_key(priv_p->input_dev, get_keycode_keymap(change), 0);
            input_sync(priv_p->input_dev);

        } else {
            // no event
        }
        #endif
        msleep(100);

        //dprintk("usb-in :0x%2x,  battery :%d\n", read_r8d8(priv_p->client, SYSREG_ACIN) , read_r8d8(priv_p->client, SYSREG_BAT));
        //ssleep(1);

    } while(!kthread_should_stop());

}
#endif

static int apt32f101_parse_dt(struct device *dev, struct apt32f101_priv *priv)
{
    struct device_node *child;
    int ret = 0;

    return ret;
}


static const struct of_device_id of_apt32f101_match[] = {
    {.compatible = "apt,apt32f101" , 0}, //.data = &apt32f101_cdef
    { }
};

MODULE_DEVICE_TABLE(of, of_apt32f101_match);

static int aptf32101_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
    const struct apt32f101_chipdef *cdef;
    const struct of_device_id *of_dev_id;
    struct device *dev = &client->dev;

    struct input_dev *input_dev;
    int count;
    int ret = 0;
    int key_irq_gpio;

    dprintk(&client->dev, "I2C Address: 0x%02x\n", client->addr);

    if (!client->dev.of_node)
    {
        dprintk("apt32f101 device tree node not found.\n");
        return -ENODEV;
    }

    if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
    {
        return -ENXIO;
    }

    of_dev_id = of_match_device(of_apt32f101_match, dev);
    if (!of_dev_id)
        return -EINVAL;

    //cdef = of_dev_id->data;
    #if 0
    cdef = dev_get_platdata(&client->dev);
    if (cdef == NULL) {
        dev_err(&client->dev, "platform data required error\n");
        return -ENODEV;
    }
    #endif

    priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
    if (!priv)
        return -ENOMEM;

    priv->client = client;
    priv->cdef = cdef;
    i2c_set_clientdata(client, priv); //设置client data


    //ret = apt32f101_parse_dt(dev, priv);
    //if (ret)
    //  return ret;

    input_dev = devm_input_allocate_device(&client->dev);
    if (!input_dev) {
        dprintk(&client->dev, "failed to allocate the input device\n");
        return -ENOMEM;
    }

    __set_bit(EV_KEY, input_dev->evbit);

    /* Enable auto repeat feature of Linux input subsystem */
    if (of_property_read_bool(client->dev.of_node, "autorepeat"))
        __set_bit(EV_REP, input_dev->evbit);

    input_dev->name = "apt32f101-key";
    //input_dev->phys = "keypad/input3";
    input_dev->dev.parent = &client->dev;

    input_dev->id.bustype = BUS_I2C; //BUS_HOST;
    input_dev->id.vendor = 0x0001;
    input_dev->id.product = 0x0001;
    input_dev->id.version = 0x0002;
    input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);

    //input_set_drvdata(input_dev, priv);

    //input_set_capability(input_dev, EV_KEY, KEY_HOME);
    //input_set_capability(input_dev, EV_KEY, KEY_MUTE);
    int i=0;
    for(i=0; i < sizeof(keymap)/sizeof(keymap_t); i++)
    {
        input_set_capability(input_dev, EV_KEY, keymap[i].key_code);
    }


    priv->input_dev = input_dev;
    priv_p = priv;
    ret = input_register_device(input_dev);
    if (ret) {
        dprintk(&client->dev, "failed to register input device\n");
        return ret;
    }



    #if D_SUPPORT_CLASS_SYSFS
    if (class_register(&motor_class) < 0)
    {
        dprintk("register class error.\n");
    }
    #endif  


    // miscdevie init
    ret = misc_register(&apt_device);
    if(ret)
    {
        dprintk("miscdevice register error.\n");
        return -1;
    }

    // timer init 
    init_timer(&systimer);
    systimer.function = &apt_timer_func;
    systimer.data = (unsigned long)&apt_device;;
    systimer.expires = jiffies + SYSTEM_STATUS_CHECK_TIME;
    add_timer(&systimer);

#ifdef D_SUPPORT_KTHREAD
    priv_p->pthread =  kthread_run(apt_thread_func, NULL, "apt32_thread-%d", 1);
    if (IS_ERR(priv_p->pthread)) {
        priv_p->pthread = NULL;
    }
#endif

#ifdef D_SUUPORT_DELAYED_TASKLET
    INIT_DELAYED_WORK(&priv_p->apt_work, apt_work_func);
    priv_p->apt_workqueue = create_workqueue("apg_workqueue");

    queue_delayed_work(priv_p->apt_workqueue, &priv_p->apt_work, 20);
    // cancel_delayed_work_sync(&priv_p->apt_work);
#endif

#ifdef D_SUPPORT_KEY_IRQ
    dprintk("=========get key irq==========\n");
    gpio_irq_key = devm_gpiod_get(dev, "key_irq", GPIOD_IN);
    if (IS_ERR(gpio_irq_key)){
        ret = PTR_ERR(gpio_irq_key);
        dev_err(&dev, "Failed to gpio get irq\n");
        return ret; 
    }

    dprintk("=========key irq==========\n");

    key_irq_gpio = gpiod_to_irq(gpio_irq_key);
    if (key_irq_gpio < 0){
        printk("%s get key_irq_gpio error\n", client->name);
    }

    dprintk("========request irq==========\n");
    // IRQ_TYPE_EDGE_FALLING IRQF_SHARED
    ret = devm_request_irq(dev, key_irq_gpio, apt_key_isr, IRQ_TYPE_LEVEL_HIGH, "key-isr", priv_p);
    if(ret){
        printk("fail to request_irq err:%d\n", ret);
    }
#endif  

    // 发送LINUX启动完成 TO MCU
    write_r8d8(priv_p->client, SYSREG_LINUX_STARTED, D_ARM_LINUX_OS_STARTED_MAGIC);

    return 0;
}

static int aptf32101_remove(struct i2c_client *client)
{

    printk("aptf32101_remove\n");
    //struct apt32f101_priv *priv = i2c_getclientdata(client);
#ifdef D_SUPPORT_KEY_IRQ    
    devm_gpiod_put(&priv_p->client->dev, gpio_irq_key);
#endif

#ifdef D_SUPPORT_KTHREAD    
    if (!IS_ERR(priv_p->pthread)) {
        kthread_stop(priv_p->pthread);
    }
#endif

#ifdef D_SUUPORT_DELAYED_TASKLET
    cancel_delayed_work(&priv_p->apt_work);  
    flush_workqueue(priv_p->apt_workqueue);   
    destroy_workqueue(priv_p->apt_workqueue);
#endif
    #if D_SUPPORT_CLASS_SYSFS
    class_unregister(&motor_class);
    #endif

    input_unregister_device(priv_p->input_dev);
    misc_deregister(&apt_device);
    del_timer(&systimer);


}


 /*
 * i2c-core (and modalias) requires that id_table be properly filled,
 * even though it is not used for DeviceTree based instantiation.
 */
static const struct i2c_device_id aptf32101_id[] = {
    { "apt32f101"},
    { }
};

MODULE_DEVICE_TABLE(i2c, aptf32101_id);

static struct i2c_driver apt32f101_driver = {
    .driver = {
        .name   = "apt32f101xx",
        .of_match_table = of_match_ptr(of_apt32f101_match),
    },
    .probe      = aptf32101_probe,
    .remove     = aptf32101_remove,
    .id_table   = aptf32101_id,
};

#if 1
module_i2c_driver(apt32f101_driver);

#else
static int __init apt32f101_init(void)
{
    int ret;
    printk("===apt32f101_init==\n");
    //return i2c_register_driver(THIS_MODULE, &apt32f101_driver);
    ret = i2c_add_driver(&apt32f101_driver);

    printk("i2c_add_driver: %d\n", ret);
    return ret;
}

static void __exit apt32f101_exit(void)
{
    return i2c_del_driver(&apt32f101_driver);
}

module_init(apt32f101_init);
module_exit(apt32f101_exit);
#endif



MODULE_AUTHOR("www.globalpat.com <[email protected]>");
MODULE_DESCRIPTION("Driver APT32F101. MCU I2C devices");
/* a few non-GPL license types are also allowed */
MODULE_LICENSE("GPL v2");

猜你喜欢

转载自blog.csdn.net/u013420428/article/details/80811917