SmartAudio/lichee/linux-4.9/drivers/misc/xunfei/cpld/i2c_operator.c

314 lines
9.4 KiB
C
Raw Normal View History

2018-08-01 07:15:23 +00:00
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/gpio.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/timer.h>
#include <linux/workqueue.h>
#define GP_CLASS_NAME "i2c_operator"
#define GP_CHR_DEV_NAME "i2c_operator"
#define GP_I2C_DEV_NAME "i2c_operator_device"
struct i2c_ioctl_msg {
int i2c_index;
int reg_addr;
int reg_val;
};
#define MAGIC_NUM 'A'
#define CMD_I2C_SET _IOW(MAGIC_NUM, 0, struct i2c_ioctl_msg)
#define CMD_I2C_GET _IOR(MAGIC_NUM, 1, struct i2c_ioctl_msg)
#define CMD_MAX (1)
static unsigned int map_io_base;
#define D_IO_BASE map_io_base
#define D_IO_BASE_PHY (0x01c20800)
#define D_IO_LEN (0x400)
#define D_IO_B (1)
#define D_IO_C (2)
#define D_IO_D (3)
#define D_IO_E (4)
#define D_IO_F (5)
#define D_IO_G (6)
#define D_IO_H (7)
#define D_IO_CFG0(x) (D_IO_BASE + (x * 0x24) + 0x00)
#define D_IO_CFG1(x) (D_IO_BASE + (x * 0x24) + 0x04)
#define D_IO_CFG2(x) (D_IO_BASE + (x * 0x24) + 0x08)
#define D_IO_CFG3(x) (D_IO_BASE + (x * 0x24) + 0x0c)
#define D_IO_DAT(x) (D_IO_BASE + (x * 0x24) + 0x10)
#define D_IO_DRV0(x) (D_IO_BASE + (x * 0x24) + 0x14)
#define D_IO_DRV1(x) (D_IO_BASE + (x * 0x24) + 0x18)
#define D_IO_PUL0(x) (D_IO_BASE + (x * 0x24) + 0x1c)
#define D_IO_PUL1(x) (D_IO_BASE + (x * 0x24) + 0x20)
static struct class *p_gp_class;
static struct device *p_class_i2c;
static int major_num;
static unsigned char *i2c_msg;
int send_to_device(char *data, int count);
int receive_from_device(char *data, int count);
int cx20810_set_mode(int mode, int index);
// int led_array_set_mode(unsigned char * param, int length);
int led_array_set_enable(int enable);
int cx20810_write_reg(int index, int addr, int regval);
int cx20810_read_reg(int index, int cmd, int *regval);
enum {
I2C_DEVICE_FPGA = 0,
I2C_DEVICE_CX20810,
I2C_DEVICE_CX20810_0,
I2C_DEVICE_CX20810_1,
I2C_DEVICE_CX20810_2,
I2C_DEVICE_LED_ARRAY,
};
static void gp_hw_init(void) {
printk("i2c_operator.c->gp_hw_init()\n");
if (!D_IO_BASE) {
// printk("Timothy:D_IO_BASE is not initial yet, initial it now\n");
D_IO_BASE = (unsigned int)ioremap(D_IO_BASE_PHY, D_IO_LEN);
if (!D_IO_BASE) {
printk("led array hardware init io error\n");
return -1;
}
}
// set pe6 output and set it high to open mute led
// writel(readl(D_IO_CFG0(D_IO_E)) & (~(0x7<<24)) | (0x1<<24),
// D_IO_CFG0(D_IO_E)); writel(readl(D_IO_DAT(D_IO_E)) | 0x1<<6,
// D_IO_DAT(D_IO_E));
}
// add by Timothy
// time:2015-02-09
// start==========
// i2c设备write处理
static ssize_t gp_i2c_write_dispatch(int len) {
// //printk("Timothy:i2c_operator.c->gp_i2c_write_dispatch(), len = %d\n",
//len);
int ret = 0;
int i;
int device_index = (int)i2c_msg[0];
int length = len - sizeof(char);
// //printk("Timothy:device_index = %d\n", device_index);
// all 3 cx20810
if (I2C_DEVICE_CX20810 == device_index) {
// //printk("Timothy:operate device:cx20810\n");
for (i = 0; i < 3; i++) {
cx20810_set_mode((int)i2c_msg[1], i);
}
return 0;
}
else if (I2C_DEVICE_CX20810_0 == device_index) {
// //printk("Timothy:operate device:cx20810_0\n");
return cx20810_set_mode((int)i2c_msg[1], 0);
} else if (I2C_DEVICE_CX20810_1 == device_index) {
// //printk("Timothy:operate device:cx20810_1\n");
return cx20810_set_mode((int)i2c_msg[1], 1);
} else if (I2C_DEVICE_CX20810_2 == device_index) {
// //printk("Timothy:operate device:cx20810_2\n");
return cx20810_set_mode((int)i2c_msg[1], 2);
}
// LED
// else if(I2C_DEVICE_LED_ARRAY == device_index)
// {
// //printk("Timothy:operate device:led_array\n");
// return led_array_set_mode(&i2c_msg[1], length);
// }
// FPGA
else if (I2C_DEVICE_FPGA == device_index) {
// //printk("Timothy:operate device:FPGA, data lendth is
//%d\n", length);
ret = send_to_device((char *)&i2c_msg[1], length);
return ret;
}
return -1;
}
static int gp_i2c_read_dispatch(int len) {
// //printk("Timothy:i2c_operator.c->gp_i2c_read_dispatch()\n");
int ret = 0;
int device_index = (int)i2c_msg[0];
int length = len - sizeof(char);
// //printk("Timothy:device_index = %d\n", device_index);
if (I2C_DEVICE_FPGA == device_index) // FPGA
{
// //printk("Timothy:operate device:FPGA, data lendth is
//%d\n", length);
ret = receive_from_device((char *)&i2c_msg[1], length);
return ret;
}
return -1;
}
// end==========
static int gp_open(struct inode *pnode, struct file *pfile) {
// printk("Timothy:i2c_operator.c->gp_open()\n");
int major = MAJOR(pnode->i_rdev);
int minor = MINOR(pnode->i_rdev);
if (minor == 0) {
pfile->private_data = (void *)p_class_i2c;
// printk("Timothy:gp_open_i2c\n");
} else {
pfile->private_data = (void *)NULL;
// printk("Timothy:gp_open:unknow device\n");
}
return 0;
}
static int gp_close(struct inode *pnode, struct file *pfile) {
pfile->private_data = (void *)NULL;
printk("gp_close\n");
return 0;
}
static ssize_t gp_read(struct file *pfile, char __user *puser, size_t len,
loff_t *poff) {
int nread = 0;
int i;
// //printk("Timothy:i2c_operator.c->gp_read()\n");
if (pfile->private_data == p_class_i2c) {
// //printk("Timothy:gp_read():i2c device\n");
i2c_msg =
(unsigned char *)kzalloc(len * sizeof(unsigned char), GFP_KERNEL);
copy_from_user((void *)i2c_msg, puser, len);
nread = gp_i2c_read_dispatch(len);
// //printk("Timothy:the data will send to user is:%d\n",
//i2c_msg[1]);
copy_to_user(puser, (void *)i2c_msg, len);
kfree(i2c_msg);
}
// //printk("Timothy:return value is %d\n", nread);
return nread;
}
static ssize_t gp_write(struct file *pfile, const char __user *puser,
size_t len, loff_t *poff) {
// //printk("Timothy:i2c_operator.c->gp_write()\n");
int ret = 0;
int i;
if (pfile->private_data == p_class_i2c) {
// //printk("Timothy:gp_write():i2c device\n");
i2c_msg =
(unsigned char *)kzalloc(len * sizeof(unsigned char), GFP_KERNEL);
copy_from_user((void *)i2c_msg, puser, len);
// //printk("Timothy:the data is ");
// for(i = 0; i < len; i++)
// {
// printk("%x ", i2c_msg[i]);
// }
// printk("\n");
ret = gp_i2c_write_dispatch(len);
kfree(i2c_msg);
} else {
// //printk("Timothy:gp_write_null\n");
}
// //printk("Timothy:return value is %d\n", ret);
return ret;
}
// file operations
static long gp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) {
u8 i;
int ret = 0;
struct i2c_ioctl_msg i2carg = {0};
printk("ioctl start cmd: %d arg: %lX\n", cmd, arg);
if (_IOC_TYPE(cmd) != MAGIC_NUM)
return -EINVAL;
if (_IOC_NR(cmd) > CMD_MAX)
return -EINVAL;
printk("ioctl start\n");
switch (cmd) {
case CMD_I2C_SET:
ret = copy_from_user(&i2carg, (struct i2c_ioctl_msg *)arg,
sizeof(i2carg));
if (0 == ret) {
printk("Will set i2c:%d reg:0x%x val:0x%x\n", i2carg.i2c_index,
i2carg.reg_addr, i2carg.reg_val);
} else {
printk("get user arg fail!\n");
}
cx20810_write_reg(i2carg.i2c_index, i2carg.reg_addr, i2carg.reg_val);
break;
case CMD_I2C_GET:
i2carg.reg_val = 0;
ret = copy_from_user(&i2carg, (struct i2c_ioctl_msg *)arg,
sizeof(i2carg));
cx20810_read_reg(i2carg.i2c_index, i2carg.reg_addr, &(i2carg.reg_val));
printk("Get i2c:%d reg:0x%x val:0x%x\n", i2carg.i2c_index,
i2carg.reg_addr, i2carg.reg_val);
ret = copy_to_user((void *)arg, &i2carg, sizeof(i2carg));
break;
default:
break;
}
printk("ioctl end\n");
return ret;
}
static struct file_operations gp_fops = {
.owner = THIS_MODULE,
.open = gp_open,
.release = gp_close,
.read = gp_read,
.write = gp_write,
.unlocked_ioctl = gp_ioctl,
};
static int __init i2c_operator_init(void) {
gp_hw_init();
major_num = register_chrdev(0, GP_CHR_DEV_NAME, &gp_fops);
if (major_num < 0) {
// printk("Timothy:gen_prov_reg_chr_err\n");
return 1;
}
p_gp_class = class_create(THIS_MODULE, GP_CLASS_NAME);
if (p_gp_class == NULL) {
// printk("Timothy:gen_prov:class create err\n");
}
p_class_i2c = device_create(p_gp_class, NULL, MKDEV(major_num, 0), NULL,
GP_I2C_DEV_NAME);
if (p_class_i2c == NULL) {
// printk("Timothy:gen_prov:device_create err:i2c\n");
return 1;
}
}
static void __exit i2c_operator_exit(void) {}
module_init(i2c_operator_init);
module_exit(i2c_operator_exit);
MODULE_AUTHOR("Timothy");
MODULE_DESCRIPTION("i2c operator driver");
MODULE_LICENSE("GPL");