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");
dts device tree 文件描述
i2c1: i2c@02203000 {
#addres