Makefile
KERNEL_DIR=/home/xxx/workspace/RK3399/soap/new_pro/P88/kernel
CURDIR=`pwd`
ARCH=arm64
CROSS_COMPILE=/home/xxx/workspace/RK3399/soap/new_pro/P88/prebuilts/gcc/linux-x86/aarch64/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-
export ARCH CROSS_COMPILE
obj-m := husb_ala.o
all:
make -C $(KERNEL_DIR) M=$(CURDIR) modules
.PHONE:clean cp
clean:
$(MAKE) -C $(KERNEL_DIR) M=$(CURDIR) clean
cp:
sudo cp *.ko /home/nfs -rf
创建
husb_ala.c
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/of_gpio.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#define I2C_RETRY_NUMBER 1
struct husb311_ctrl
{
int gpio;
int irq;
struct i2c_client * client;
};
static struct husb311_ctrl * g_husb311_ctrl = NULL;
static DEFINE_MUTEX(i2c_rw_access);
/**/
int husb311_i2c_read(struct i2c_client *client, char *writebuf, int writelen, char *readbuf, int readlen)
{
int ret = 0;
int i = 0;
mutex_lock(&i2c_rw_access);
if (readlen > 0) {
if (writelen > 0) {
struct i2c_msg msgs[] = {
{
.addr = client->addr,
.flags = 0,
.len = writelen,
.buf = writebuf,
},
{
.addr = client->addr,
.flags = I2C_M_RD,
.len = readlen,
.buf = readbuf,
},
};
for (i = 0; i < I2C_RETRY_NUMBER; i++) {
ret = i2c_transfer(client->adapter, msgs, 2);
if (ret < 0) {
printk(KERN_ERR "[IIC]: i2c_transfer(write) error, ret=%d ,client->addr=0x%x!!", ret,client->addr);
} else
break;
}
} else {
struct i2c_msg msgs[] = {
{
.addr = client->addr,
.flags = I2C_M_RD,
.len = readlen,
.buf = readbuf,
},
};
for (i = 0; i < I2C_RETRY_NUMBER; i++) {
ret = i2c_transfer(client->adapter, msgs, 1);
if (ret < 0) {
printk(KERN_ERR "[IIC]: i2c_transfer(read) error, ret=%d!!", ret);
} else
break;
}
}
}
mutex_unlock(&i2c_rw_access);
return ret;
}
int husb311_i2c_write(struct i2c_client *client, char *writebuf, int writelen)
{
int ret = 0;
int i = 0;
mutex_lock(&i2c_rw_access);
if (writelen > 0) {
struct i2c_msg msgs[] = {
{
.addr = client->addr,
.flags = 0,
.len = writelen,
.buf = writebuf,
},
};
for (i = 0; i < I2C_RETRY_NUMBER; i++) {
ret = i2c_transfer(client->adapter, msgs, 1);
if (ret < 0) {
printk(KERN_ERR "%s: i2c_transfer(write) error, ret=%d", __func__, ret);
} else
break;
}
}
mutex_unlock(&i2c_rw_access);
return ret;
}
int husb311_i2c_write_reg(struct i2c_client *client, unsigned char regaddr, unsigned char regvalue)
{
unsigned char buf[2] = {0};
buf[0] = regaddr;
buf[1] = regvalue;
return husb311_i2c_write(client, buf, sizeof(buf));
}
int husb311_i2c_read_reg(struct i2c_client *client, unsigned char regaddr, unsigned char *regvalue)
{
return husb311_i2c_read(client, ®addr, 1, regvalue, 1);
}
/**/
static int husb311_i2c_read_regs(struct i2c_client *client, unsigned char cmd, unsigned char *data, unsigned char data_len)
{
struct i2c_msg msgs[2];
int ret = -1;
unsigned char * buffer = NULL;
buffer = kzalloc(data_len, GFP_KERNEL);
if (!buffer)
return -ENOMEM;
msgs[0].addr = client->addr;
msgs[0].flags = client->flags;
msgs[0].len = 1;
msgs[0].buf = &cmd;
msgs[1].addr = client->addr;
msgs[1].flags = client->flags | I2C_M_RD;
msgs[1].len = data_len;
msgs[1].buf = buffer;
ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
if (ret < 0)
dev_err(&client->adapter->dev, "i2c read failed\n");
else
memcpy(data, buffer, data_len);
kfree(buffer);
return ret;
}
static int husb311_i2c_write_regs(struct i2c_client *client, unsigned char cmd, unsigned char *data, unsigned char data_len)
{
struct i2c_msg msgs[1];
unsigned char *buffer;
int ret = 0;
buffer = kzalloc(data_len + 1, GFP_KERNEL);
if (!buffer)
return -ENOMEM;
buffer[0] = cmd;
memcpy(buffer + 1, data, data_len);
msgs[0].addr = client->addr;
msgs[0].flags = client->flags;
msgs[0].len = data_len + 1;
msgs[0].buf = buffer;
ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
if (ret < 0)
dev_err(&client->adapter->dev, "i2c write failed\n");
kfree(buffer);
return ret;
}
static int husb311_i2c_write_reg(struct i2c_client *client, unsigned char reg, unsigned char value)
{
unsigned char buf[2] = {'\0'};
buf[0] = value;
buf[1] = '\0';
return husb311_i2c_write_regs(client, reg, buf, 1);
}
static unsigned char husb311_i2c_read_reg(struct i2c_client *client, unsigned char reg)
{
int ret = -1;
unsigned char buf[2] = {'\0'};
ret = husb311_i2c_read_regs(client, reg, buf, 1);
if (ret < 0)
{
printk(KERN_ERR "husb311_i2c_read_regs 0x%x fail\n", reg);
return -1;
}
return buf[0];
}
static int husb311_init(struct i2c_client * client)
{
int ret = -1;
//unsigned char value = 0;
//unsigned char i = 0;
ret = husb311_i2c_write_reg(client, 0xA0, 0x1);
if (ret < 0)
{
printk(KERN_ERR "husb311_i2c_write_reg 0xA0 fail\n");
return -1;
}
for (;;)
{
ret = husb311_i2c_read_reg(client, 0x1E, &value);
if (ret)
{
printk(KERN_ERR "time out!!!\n");
return -1;
}
if (!(value & (1 << 6)) || (i > 20))
{
break;
}
msleep(100);
i++;
}
if (i > 20)
{
printk(KERN_ERR "time out!!!\n");
return -1;
}
ret = husb311_i2c_write_reg(client, 0x10, 0xff);
if (ret < 0)
{
printk(KERN_ERR "husb311_i2c_write_reg 0x10 fail\n");
return -1;
}
ret = husb311_i2c_write_reg(client, 0x11, 0xff);
if (ret < 0)
{
printk(KERN_ERR "husb311_i2c_write_reg 0x11 fail\n");
return -1;
}
ret = husb311_i2c_write_reg(client, 0x12, 0x1);
if (ret < 0)
{
printk(KERN_ERR "husb311_i2c_write_reg 0x12 fail\n");
return -1;
}
ret = husb311_i2c_write_reg(client, 0x13, 0x0);
if (ret < 0)
{
printk(KERN_ERR "husb311_i2c_write_reg 0x13 fail\n");
return -1;
}
ret = husb311_i2c_write_reg(client, 0x14, 0x0);
if (ret < 0)
{
printk(KERN_ERR "husb311_i2c_write_reg 0x14 fail\n");
return -1;
}
ret = husb311_i2c_write_reg(client, 0x90, 0x2);
if (ret < 0)
{
printk(KERN_ERR "husb311_i2c_write_reg 0x90 fail\n");
return -1;
}
ret = husb311_i2c_write_reg(client, 0x9f, 0x0);
if (ret < 0)
{
printk(KERN_ERR "husb311_i2c_write_reg 0x9f fail\n");
return -1;
}
ret = husb311_i2c_write_reg(client, 0x1a, 0xa);
if (ret < 0)
{
printk(KERN_ERR "husb311_i2c_write_reg 0x1a fail\n");
return -1;
}
return 0;
}
static void husb311_func(struct work_struct * work)
{
unsigned char value = 0;
int ret = husb311_i2c_read_reg(g_husb311_ctrl->client, 0x10, &value);
if (ret)
{
printk(KERN_ERR "husb311_i2c_write_reg 0x10 fail\n");
return;
}
if (value &(1 << 0))
{
ret = husb311_i2c_read_reg(g_husb311_ctrl->client, 0x1d, &value);
if (ret)
{
printk(KERN_ERR "husb311_i2c_write_reg 0x1d fail\n");
return;
}
if ((value & (0x3 << 2)) && ((value & (0x3 << 0))==0x0))
{
printk(KERN_ERR "CC2 is connect!!!");
}
if ((value & (0x3 << 0)) && ((value & (0x3 << 2))==0x0))
{
printk(KERN_ERR "CC1 is connect!!!");
}
husb311_i2c_write_reg(g_husb311_ctrl->client, 0x10, 0xff);
husb311_i2c_write_reg(g_husb311_ctrl->client, 0x11, 0xff);
}
enable_irq(g_husb311_ctrl->irq);
}
static DECLARE_WORK(husb311_work, husb311_func);
static irqreturn_t husb311_irq_handler(int irq, void *dev_id)
{
printk(KERN_ERR "------------husb311_irq_handler-------------\n");
schedule_work(&husb311_work);
disable_irq(g_husb311_ctrl->irq);
return IRQ_HANDLED;
}
static int husb311_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int ret = -1;
enum of_gpio_flags irq_flags;
struct device_node * np = client->dev.of_node;
printk(KERN_ERR "------------enter probe function-------------\n");
g_husb311_ctrl = kzalloc(sizeof(struct husb311_ctrl), GFP_KERNEL);
if (!g_husb311_ctrl)
{
printk(KERN_ERR "kzalloc fail\n");
return -ENOMEM;
}
g_husb311_ctrl->client = client;
g_husb311_ctrl->gpio = of_get_named_gpio_flags(np, "int-n-gpios", 0, (enum of_gpio_flags*)&irq_flags);
if (g_husb311_ctrl->gpio < 0)
{
printk(KERN_ERR "of_get_named_gpio_flags fail\n");
goto gpio_err;
}
printk(KERN_ERR "gpio:%d\n", g_husb311_ctrl->gpio);
ret = gpio_request(g_husb311_ctrl->gpio, "husb311 irq gpio");
if (ret < 0)
{
printk(KERN_ERR "gpio_request fail\n");
goto gpio_request_err;
}
g_husb311_ctrl->irq = gpio_to_irq(g_husb311_ctrl->gpio);
if (g_husb311_ctrl->irq < 0)
{
printk(KERN_ERR "gpio_to_irq fail\n");
goto to_irq_err;
}
printk(KERN_ERR "irq:%d\n", g_husb311_ctrl->irq);
ret = request_irq(g_husb311_ctrl->irq, husb311_irq_handler, irq_flags,
"husb311_irq", NULL);
printk(KERN_ERR "request_irq return:%d\n", ret);
if (ret != 0)
{
printk(KERN_ERR "request_irq fail\n");
goto request_irq_err;
}
/* init */
ret = husb311_init(client);
if (ret < 0)
{
printk(KERN_ERR "husb311_init fail\n");
goto husb311_init_err;
}
return 0;
husb311_init_err:
free_irq(g_husb311_ctrl->irq, NULL);
request_irq_err:
to_irq_err:
gpio_free(g_husb311_ctrl->gpio);
gpio_request_err:
gpio_err:
return -1;
}
static int husb311_remove(struct i2c_client *client)
{
free_irq(g_husb311_ctrl->irq, NULL);
gpio_free(g_husb311_ctrl->gpio);
return 0;
}
static const struct of_device_id husb311_of_match[] = {
{ .compatible = "husb311" },
{ },
};
static const struct i2c_device_id husb30x[] = {
{ "husb311", 0 },
{}
};
MODULE_DEVICE_TABLE(i2c, husb30x);
static struct i2c_driver husb311_i2c_driver = {
.driver = {
.name = "husb311",
.of_match_table = husb311_of_match,
},
.probe = husb311_probe,
.remove = husb311_remove,
.id_table = husb30x,
};
module_i2c_driver(husb311_i2c_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("linqi");
MODULE_DESCRIPTION("husb311 usb cc driver");