Loading drivers/input/misc/ots_pat9125/pat9125_linux_driver.c +152 −326 Original line number Diff line number Diff line Loading @@ -4,378 +4,268 @@ * */ #include <linux/kernel.h> #include <linux/input.h> #include <linux/pm.h> #include <linux/i2c.h> #include <linux/module.h> #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/gpio.h> #include <linux/of_gpio.h> #include <linux/delay.h> #include <linux/dma-mapping.h> #include <linux/miscdevice.h> #include "pixart_ots.h" #include "pixart_platform.h" static int pat9125_init_input_data(void); #define pat9125_name "pixart_pat9125" #define pat9125_DEV_NAME pat9125_name static struct pat9125_linux_data_t pat9125data; static int pat9125_i2c_write(u8 reg, u8 *data, int len); static int pat9125_i2c_read(u8 reg, u8 *data); extern unsigned char ReadData(unsigned char addr) { u8 data = 0xff; struct pixart_pat9125_data { struct i2c_client *client; struct input_dev *input; int irq_gpio; u32 irq_flags; }; pat9125_i2c_read(addr, &data); return data; } extern void WriteData(unsigned char addr, unsigned char data) static int pat9125_i2c_write(struct i2c_client *client, u8 reg, u8 *data, int len) { pat9125_i2c_write(addr, &data, 1); } extern void delay_ms(int ms) { msleep(ms); } static int pat9125_i2c_write(u8 reg, u8 *data, int len) { u8 buf[20]; int rc; int ret = 0; int i; u8 buf[MAX_BUF_SIZE]; int ret = 0, i; struct device *dev = &client->dev; buf[0] = reg; if (len >= 20) { pr_debug( "%s (%d) : FAILED: buffer size is limitted(20) %d\n", __func__, __LINE__, len); dev_err(&pat9125data.client->dev, "pat9125_i2c_write FAILED: buffer size is limitted(20)\n"); if (len >= MAX_BUF_SIZE) { dev_err(dev, "%s Failed: buffer size is %d [Max Limit is %d]\n", __func__, len, MAX_BUF_SIZE); return -ENODEV; } for (i = 0 ; i < len; i++) buf[i+1] = data[i]; /* Returns negative errno, or else the number of bytes written. */ rc = i2c_master_send(pat9125data.client, buf, len+1); if (rc != len+1) { pr_debug( "%s (%d) : FAILED: writing to reg 0x%x\n", __func__, __LINE__, reg); ret = -ENODEV; } ret = i2c_master_send(client, buf, len+1); if (ret != len+1) dev_err(dev, "%s Failed: writing to reg 0x%x\n", __func__, reg); return ret; } static int pat9125_i2c_read(u8 reg, u8 *data) static int pat9125_i2c_read(struct i2c_client *client, u8 reg, u8 *data) { u8 buf[20]; int rc; u8 buf[MAX_BUF_SIZE]; int ret; struct device *dev = &client->dev; buf[0] = reg; /* * If everything went ok (i.e. 1 msg transmitted), *return #bytes transmitted, else error code. * thus if transmit is ok return value 1 * If everything went ok (1 msg transmitted), return #bytes transmitted, * else error code. thus if transmit is ok return value 1 */ rc = i2c_master_send(pat9125data.client, buf, 1); if (rc != 1) { pr_debug( "%s (%d) : FAILED: writing to address 0x%x\n", __func__, __LINE__, reg); return -ENODEV; ret = i2c_master_send(client, buf, 1); if (ret != 1) { dev_err(dev, "%s Failed: writing to reg 0x%x\n", __func__, reg); return ret; } /* returns negative errno, or else the number of bytes read */ rc = i2c_master_recv(pat9125data.client, buf, 1); if (rc != 1) { pr_debug( "%s (%d) : FAILED: reading data\n", __func__, __LINE__); return -ENODEV; ret = i2c_master_recv(client, buf, 1); if (ret != 1) { dev_err(dev, "%s Failed: reading reg 0x%x\n", __func__, reg); return ret; } *data = buf[0]; return 0; } void pixart_pat9125_ist(void) { } static irqreturn_t pixart_pat9125_irq(int irq, void *handle) { pixart_pat9125_ist(); return IRQ_HANDLED; } static int pat9125_start(void) { int err = (-1); pr_debug(">>> %s (%d)\n", __func__, __LINE__); err = request_threaded_irq(pat9125data.irq, NULL, pixart_pat9125_irq, pat9125data.irq_flags, "pixart_pat9125_irq", &pat9125data); if (err) pr_debug("irq %d busy?\n", pat9125data.irq); pat9125data.last_jiffies = jiffies_64; return err; } static void pat9125_stop(void) { free_irq(pat9125data.irq, &pat9125data); } static ssize_t pat9125_fops_read(struct file *filp, char *buf, size_t count, loff_t *l) { return 0; return ret; } static ssize_t pat9125_fops_write(struct file *filp, const char *buf, size_t count, loff_t *f_ops) unsigned char read_data(struct i2c_client *client, u8 addr) { return 0; } u8 data = 0xff; static long pat9125_fops_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { return 0; pat9125_i2c_read(client, addr, &data); return data; } static int pat9125_fops_open(struct inode *inode, struct file *filp) void write_data(struct i2c_client *client, u8 addr, u8 data) { return 0; pat9125_i2c_write(client, addr, &data, 1); } static int pat9125_fops_release(struct inode *inode, struct file *filp) static irqreturn_t pixart_pat9125_irq(int irq, void *data) { pr_debug(">>> %s (%d)\n", __func__, __LINE__); return 0; return IRQ_HANDLED; } static const struct file_operations pat9125_fops = { owner: THIS_MODULE, read : pat9125_fops_read, write : pat9125_fops_write, /* ioctl : pat9125_fops_ioctl, */ unlocked_ioctl : pat9125_fops_ioctl, open : pat9125_fops_open, release : pat9125_fops_release, }; /*----------------------------------------------------------------------------*/ struct miscdevice pat9125_device = { .minor = MISC_DYNAMIC_MINOR, .name = pat9125_name, .fops = &pat9125_fops, }; static ssize_t pat9125_test_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { char s[256]; char *p = s; pr_debug("%s (%d) : write_reg_store\n", __func__, __LINE__); memcpy(s, buf, sizeof(s)); char s[256], *p = s; int reg_data = 0, i; long rd_addr, wr_addr, wr_data; struct pixart_pat9125_data *data = (struct pixart_pat9125_data *)dev->driver_data; struct i2c_client *client = data->client; for (i = 0; i < sizeof(s); i++) s[i] = buf[i]; *(s+1) = '\0'; *(s+4) = '\0'; *(s+7) = '\0'; /* example(in console): echo w 12 34 > rw_reg */ if (*p == 'w') { long write_addr, write_data; p += 2; if (!kstrtol(p, 16, &write_addr)) { if (!kstrtol(p, 16, &wr_addr)) { p += 3; if (!kstrtol(p, 16, &write_data)) { pr_debug( "w 0x%x 0x%x\n", (u8)write_addr, (u8)write_data); WriteData((u8)write_addr, (u8)write_data); if (!kstrtol(p, 16, &wr_data)) { dev_dbg(dev, "w 0x%x 0x%x\n", (u8)wr_addr, (u8)wr_data); write_data(client, (u8)wr_addr, (u8)wr_data); } } } /* example(in console): echo r 12 > rw_reg */ } else if (*p == 'r') { long read_addr; else if (*p == 'r') { p += 2; if (!kstrtol(p, 16, &read_addr)) { int data = 0; data = ReadData((u8)read_addr); pr_debug( "r 0x%x 0x%x\n", (unsigned int)read_addr, data); if (!kstrtol(p, 16, &rd_addr)) { reg_data = read_data(client, (u8)rd_addr); dev_dbg(dev, "r 0x%x 0x%x\n", (unsigned int)rd_addr, reg_data); } } return count; } static ssize_t pat9125_test_show( struct device *dev, struct device_attribute *attr, char *buf) static ssize_t pat9125_test_show(struct device *dev, struct device_attribute *attr, char *buf) { /* cat */ pr_debug("%s (%d) :\n", __func__, __LINE__); return 0; } static DEVICE_ATTR( test, S_IRUGO | S_IWUSR | S_IWGRP, pat9125_test_show, pat9125_test_store); static struct device_attribute *pat9125_attr_list[] = { &dev_attr_test, }; static DEVICE_ATTR(test, S_IRUGO | S_IWUSR | S_IWGRP, pat9125_test_show, pat9125_test_store); static int pat9125_create_attr(struct device *dev) { int idx, err = 0; int num = ARRAY_SIZE(pat9125_attr_list); static struct attribute *pat9125_attr_list[] = { &dev_attr_test.attr, NULL, }; if (!dev) return -EINVAL; for (idx = 0; idx < num; idx++) { err = device_create_file(dev, pat9125_attr_list[idx]); if (err) { pr_debug( "device_create_file (%s) = %d\n", pat9125_attr_list[idx]->attr.name, err); break; } } return err; } static struct attribute_group pat9125_attr_grp = { .attrs = pat9125_attr_list, }; static int pat9125_i2c_probe( struct i2c_client *client, static int pat9125_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { int err = 0; struct pixart_pat9125_data *data; struct input_dev *input; struct device_node *np; struct device *dev = &client->dev; struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); pr_debug("%s (%d) : probe module....\n", __func__, __LINE__); memset(&pat9125data, 0, sizeof(pat9125data)); err = i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE); if (err < 0) goto error_return; pat9125data.client = client; err = misc_register(&pat9125_device); if (err) { pr_debug("pat9125_device register failed\n"); goto error_return; err = i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE); if (err < 0) { dev_err(dev, "I2C not supported\n"); return -ENXIO; } pat9125data.pat9125_device = pat9125_device.this_device; err = pat9125_create_attr(pat9125data.pat9125_device); if (err) { pr_debug("create attribute err = %d\n", err); goto error_return; if (client->dev.of_node) { data = devm_kzalloc(dev, sizeof(struct pixart_pat9125_data), GFP_KERNEL); if (!data) return -ENOMEM; } else { data = client->dev.platform_data; if (!data) { dev_err(dev, "Invalid pat9125 data\n"); return -EINVAL; } } data->client = client; if (pat9125_init_input_data() < 0) goto error_return; /* interrupt initialization */ pat9125data.i2c_dev = &client->dev; input = devm_input_allocate_device(dev); if (!input) { dev_err(dev, "Failed to alloc input device\n"); return -ENOMEM; } np = pat9125data.i2c_dev->of_node; pat9125data.irq_gpio = of_get_named_gpio_flags(np, "pixart_pat9125,irq-gpio", 0, &pat9125data.irq_flags); i2c_set_clientdata(client, data); input_set_drvdata(input, data); input->name = PAT9125_DEV_NAME; pr_debug( "irq_gpio: %d, irq_flags: 0x%x\n", pat9125data.irq_gpio, pat9125data.irq_flags); data->input = input; err = input_register_device(data->input); if (err < 0) { dev_err(dev, "Failed to register input device\n"); goto err_register_input_device; } if (!gpio_is_valid(pat9125data.irq_gpio)) { err = (-1); pr_debug( "invalid irq_gpio: %d\n", pat9125data.irq_gpio); goto error_return; if (!gpio_is_valid(data->irq_gpio)) { dev_err(dev, "invalid irq_gpio: %d\n", data->irq_gpio); return -EINVAL; } err = gpio_request(pat9125data.irq_gpio, "pixart_pat9125_irq_gpio"); err = gpio_request(data->irq_gpio, "pixart_pat9125_irq_gpio"); if (err) { pr_debug( "unable to request gpio [%d], [%d]\n", pat9125data.irq_gpio, err); goto error_return; dev_err(dev, "unable to request gpio %d\n", data->irq_gpio); return err; } err = gpio_direction_input(pat9125data.irq_gpio); err = gpio_direction_input(data->irq_gpio); if (err) { pr_debug("unable to set dir for gpio[%d], [%d]\n", pat9125data.irq_gpio, err); goto error_return; dev_err(dev, "unable to set dir for gpio %d\n", data->irq_gpio); goto free_gpio; } pat9125data.irq = gpio_to_irq(pat9125data.irq_gpio); if (!ots_sensor_init(client)) { err = -ENODEV; goto err_sensor_init; } if (!OTS_Sensor_Init()) goto error_return; err = devm_request_threaded_irq(dev, client->irq, NULL, pixart_pat9125_irq, (unsigned long)data->irq_flags, "pixart_pat9125_irq", data); if (err) { dev_err(dev, "Req irq %d failed, errno:%d\n", client->irq, err); goto err_request_threaded_irq; } if (!pat9125_start()) goto error_return; err = sysfs_create_group(&(input->dev.kobj), &pat9125_attr_grp); if (err) { dev_err(dev, "Failed to create sysfs group, errno:%d\n", err); goto err_sysfs_create; } return 0; error_return: err_sysfs_create: err_request_threaded_irq: err_sensor_init: free_gpio: gpio_free(data->irq_gpio); err_register_input_device: input_free_device(data->input); return err; } static int pat9125_i2c_remove(struct i2c_client *client) { struct pixart_pat9125_data *data = i2c_get_clientdata(client); devm_free_irq(&client->dev, client->irq, data); if (gpio_is_valid(data->irq_gpio)) gpio_free(data->irq_gpio); input_unregister_device(data->input); devm_kfree(&client->dev, data); data = NULL; return 0; } static int pat9125_suspend(struct device *dev) { pr_debug("%s (%d) : pat9125 suspend\n", __func__, __LINE__); { return 0; } static int pat9125_resume(struct device *dev) { pr_debug("%s (%d) : pat9125 resume\n", __func__, __LINE__); return 0; } static const struct i2c_device_id pat9125_device_id[] = { {pat9125_DEV_NAME, 0}, {PAT9125_DEV_NAME, 0}, {} }; MODULE_DEVICE_TABLE(i2c, pat9125_device_id); static const struct dev_pm_ops pat9125_pm_ops = { Loading @@ -390,7 +280,7 @@ static const struct of_device_id pixart_pat9125_match_table[] = { static struct i2c_driver pat9125_i2c_driver = { .driver = { .name = pat9125_DEV_NAME, .name = PAT9125_DEV_NAME, .owner = THIS_MODULE, .pm = &pat9125_pm_ops, .of_match_table = pixart_pat9125_match_table, Loading @@ -399,72 +289,8 @@ static struct i2c_driver pat9125_i2c_driver = { .remove = pat9125_i2c_remove, .id_table = pat9125_device_id, }; static int pat9125_open(struct input_dev *dev) { pr_debug(">>> %s (%d)\n", __func__, __LINE__); return 0; } static void pat9125_close(struct input_dev *dev) { pr_debug(">>> %s (%d)\n", __func__, __LINE__); } static int pat9125_init_input_data(void) { int ret = 0; module_i2c_driver(pat9125_i2c_driver); pr_debug("%s (%d) : initialize data\n", __func__, __LINE__); pat9125data.pat9125_input_dev = input_allocate_device(); if (!pat9125data.pat9125_input_dev) { pr_debug( "%s (%d) : could not allocate mouse input device\n", __func__, __LINE__); return -ENOMEM; } input_set_drvdata(pat9125data.pat9125_input_dev, &pat9125data); pat9125data.pat9125_input_dev->name = "Pixart pat9125"; pat9125data.pat9125_input_dev->open = pat9125_open; pat9125data.pat9125_input_dev->close = pat9125_close; ret = input_register_device(pat9125data.pat9125_input_dev); if (ret < 0) { input_free_device(pat9125data.pat9125_input_dev); pr_debug( "%s (%d) : could not register input device\n", __func__, __LINE__); return ret; } return 0; } static int __init pat9125_linux_init(void) { return i2c_add_driver(&pat9125_i2c_driver); } static void __exit pat9125_linux_exit(void) { pr_debug("%s (%d) : exit module\n", __func__, __LINE__); pat9125_stop(); misc_register(&pat9125_device); i2c_del_driver(&pat9125_i2c_driver); } module_init(pat9125_linux_init); module_exit(pat9125_linux_exit); MODULE_AUTHOR("pixart"); MODULE_DESCRIPTION("pixart pat9125 driver"); MODULE_LICENSE("GPL"); drivers/input/misc/ots_pat9125/pixart_ots.c +39 −33 Original line number Diff line number Diff line Loading @@ -4,11 +4,20 @@ * */ #include "pixart_platform.h" #include "pixart_ots.h" static void OTS_WriteRead(uint8_t address, uint8_t wdata); static void ots_write_read(struct i2c_client *client, u8 address, u8 wdata) { u8 read_value; do { write_data(client, address, wdata); read_value = read_data(client, address); } while (read_value != wdata); } bool OTS_Sensor_Init(void) bool ots_sensor_init(struct i2c_client *client) { unsigned char sensor_pid = 0, read_id_ok = 0; Loading @@ -16,56 +25,53 @@ bool OTS_Sensor_Init(void) * Read sensor_pid in address 0x00 to check if the * serial link is valid, read value should be 0x31. */ sensor_pid = ReadData(0x00); sensor_pid = read_data(client, PIXART_PAT9125_PRODUCT_ID1_REG); if (sensor_pid == 0x31) { if (sensor_pid == PIXART_PAT9125_SENSOR_ID) { read_id_ok = 1; /* * PAT9125 sensor recommended settings: * switch to bank0, not allowed to perform OTS_RegWriteRead * switch to bank0, not allowed to perform ots_write_read */ WriteData(0x7F, 0x00); write_data(client, PIXART_PAT9125_SELECT_BANK_REG, PIXART_PAT9125_BANK0); /* * software reset (i.e. set bit7 to 1). * It will reset to 0 automatically * so perform OTS_RegWriteRead is not allowed. */ WriteData(0x06, 0x97); write_data(client, PIXART_PAT9125_CONFIG_REG, PIXART_PAT9125_RESET); /* delay 1ms */ delay_ms(1); usleep_range(RESET_DELAY_US, RESET_DELAY_US + 1); /* disable write protect */ OTS_WriteRead(0x09, 0x5A); ots_write_read(client, PIXART_PAT9125_WRITE_PROTECT_REG, PIXART_PAT9125_DISABLE_WRITE_PROTECT); /* set X-axis resolution (depends on application) */ OTS_WriteRead(0x0D, 0x65); ots_write_read(client, PIXART_PAT9125_SET_CPI_RES_X_REG, PIXART_PAT9125_CPI_RESOLUTION_X); /* set Y-axis resolution (depends on application) */ OTS_WriteRead(0x0E, 0xFF); ots_write_read(client, PIXART_PAT9125_SET_CPI_RES_Y_REG, PIXART_PAT9125_CPI_RESOLUTION_Y); /* set 12-bit X/Y data format (depends on application) */ OTS_WriteRead(0x19, 0x04); ots_write_read(client, PIXART_PAT9125_ORIENTATION_REG, PIXART_PAT9125_MOTION_DATA_LENGTH); /* ONLY for VDD=VDDA=1.7~1.9V: for power saving */ OTS_WriteRead(0x4B, 0x04); ots_write_read(client, PIXART_PAT9125_VOLTAGE_SEGMENT_SEL_REG, PIXART_PAT9125_LOW_VOLTAGE_SEGMENT); if (ReadData(0x5E) == 0x04) { OTS_WriteRead(0x5E, 0x08); if (ReadData(0x5D) == 0x10) OTS_WriteRead(0x5D, 0x19); if (read_data(client, PIXART_PAT9125_MISC2_REG) == 0x04) { ots_write_read(client, PIXART_PAT9125_MISC2_REG, 0x08); if (read_data(client, PIXART_PAT9125_MISC1_REG) == 0x10) ots_write_read(client, PIXART_PAT9125_MISC1_REG, 0x19); } OTS_WriteRead(0x09, 0x00);/* enable write protect */ /* enable write protect */ ots_write_read(client, PIXART_PAT9125_WRITE_PROTECT_REG, PIXART_PAT9125_ENABLE_WRITE_PROTECT); } return read_id_ok; } static void OTS_WriteRead(uint8_t address, uint8_t wdata) { uint8_t read_value; do { /* Write data to specified address */ WriteData(address, wdata); /* Read back previous written data */ read_value = ReadData(address); /* Check if the data is correctly written */ } while (read_value != wdata); } drivers/input/misc/ots_pat9125/pixart_ots.h +35 −6 Original line number Diff line number Diff line Loading @@ -4,13 +4,42 @@ * */ #ifndef _PIXART_OTS_H_ #define _PIXART_OTS_H_ #ifndef __PIXART_OTS_H_ #define __PIXART_OTS_H_ #include "pixart_platform.h" #define PAT9125_DEV_NAME "pixart_pat9125" #define MAX_BUF_SIZE 20 #define RESET_DELAY_US 1000 /* export funtions */ bool OTS_Sensor_Init(void); void OTS_Sensor_ReadMotion(int16_t *dx, int16_t *dy); /* Register addresses */ #define PIXART_PAT9125_PRODUCT_ID1_REG 0x00 #define PIXART_PAT9125_PRODUCT_ID2_REG 0x01 #define PIXART_PAT9125_MOTION_STATUS_REG 0x02 #define PIXART_PAT9125_DELTA_X_LO_REG 0x03 #define PIXART_PAT9125_DELTA_Y_LO_REG 0x04 #define PIXART_PAT9125_CONFIG_REG 0x06 #define PIXART_PAT9125_WRITE_PROTECT_REG 0x09 #define PIXART_PAT9125_SET_CPI_RES_X_REG 0x0D #define PIXART_PAT9125_SET_CPI_RES_Y_REG 0x0E #define PIXART_PAT9125_DELTA_XY_HI_REG 0x12 #define PIXART_PAT9125_ORIENTATION_REG 0x19 #define PIXART_PAT9125_VOLTAGE_SEGMENT_SEL_REG 0x4B #define PIXART_PAT9125_SELECT_BANK_REG 0x7F #define PIXART_PAT9125_MISC1_REG 0x5D #define PIXART_PAT9125_MISC2_REG 0x5E /*Register configuration data */ #define PIXART_PAT9125_SENSOR_ID 0x31 #define PIXART_PAT9125_RESET 0x97 #define PIXART_PAT9125_MOTION_DATA_LENGTH 0x04 #define PIXART_PAT9125_BANK0 0x00 #define PIXART_PAT9125_DISABLE_WRITE_PROTECT 0x5A #define PIXART_PAT9125_ENABLE_WRITE_PROTECT 0x00 #define PIXART_PAT9125_CPI_RESOLUTION_X 0x65 #define PIXART_PAT9125_CPI_RESOLUTION_Y 0xFF #define PIXART_PAT9125_LOW_VOLTAGE_SEGMENT 0x04 #define PIXART_PAT9125_VALID_MOTION_DATA 0x80 /* Export functions */ bool ots_sensor_init(struct i2c_client *); #endif drivers/input/misc/ots_pat9125/pixart_platform.h +5 −13 Original line number Diff line number Diff line Loading @@ -4,22 +4,14 @@ * */ #ifndef _PIXART_PLATFORM_ #define _PIXART_PLATFORM_ #ifndef __PIXART_PLATFORM_H_ #define __PIXART_PLATFORM_H_ #include <linux/input.h> #include <linux/pm.h> #include <linux/spi/spi.h> #include <linux/module.h> #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/gpio.h> #include <linux/of_gpio.h> #include <linux/i2c.h> #include <linux/delay.h> #include <linux/types.h> /* extern functions */ extern unsigned char ReadData(unsigned char addr); extern void WriteData(unsigned char addr, unsigned char data); extern unsigned char read_data(struct i2c_client *, u8 addr); extern void write_data(struct i2c_client *, u8 addr, u8 data); #endif Loading
drivers/input/misc/ots_pat9125/pat9125_linux_driver.c +152 −326 Original line number Diff line number Diff line Loading @@ -4,378 +4,268 @@ * */ #include <linux/kernel.h> #include <linux/input.h> #include <linux/pm.h> #include <linux/i2c.h> #include <linux/module.h> #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/gpio.h> #include <linux/of_gpio.h> #include <linux/delay.h> #include <linux/dma-mapping.h> #include <linux/miscdevice.h> #include "pixart_ots.h" #include "pixart_platform.h" static int pat9125_init_input_data(void); #define pat9125_name "pixart_pat9125" #define pat9125_DEV_NAME pat9125_name static struct pat9125_linux_data_t pat9125data; static int pat9125_i2c_write(u8 reg, u8 *data, int len); static int pat9125_i2c_read(u8 reg, u8 *data); extern unsigned char ReadData(unsigned char addr) { u8 data = 0xff; struct pixart_pat9125_data { struct i2c_client *client; struct input_dev *input; int irq_gpio; u32 irq_flags; }; pat9125_i2c_read(addr, &data); return data; } extern void WriteData(unsigned char addr, unsigned char data) static int pat9125_i2c_write(struct i2c_client *client, u8 reg, u8 *data, int len) { pat9125_i2c_write(addr, &data, 1); } extern void delay_ms(int ms) { msleep(ms); } static int pat9125_i2c_write(u8 reg, u8 *data, int len) { u8 buf[20]; int rc; int ret = 0; int i; u8 buf[MAX_BUF_SIZE]; int ret = 0, i; struct device *dev = &client->dev; buf[0] = reg; if (len >= 20) { pr_debug( "%s (%d) : FAILED: buffer size is limitted(20) %d\n", __func__, __LINE__, len); dev_err(&pat9125data.client->dev, "pat9125_i2c_write FAILED: buffer size is limitted(20)\n"); if (len >= MAX_BUF_SIZE) { dev_err(dev, "%s Failed: buffer size is %d [Max Limit is %d]\n", __func__, len, MAX_BUF_SIZE); return -ENODEV; } for (i = 0 ; i < len; i++) buf[i+1] = data[i]; /* Returns negative errno, or else the number of bytes written. */ rc = i2c_master_send(pat9125data.client, buf, len+1); if (rc != len+1) { pr_debug( "%s (%d) : FAILED: writing to reg 0x%x\n", __func__, __LINE__, reg); ret = -ENODEV; } ret = i2c_master_send(client, buf, len+1); if (ret != len+1) dev_err(dev, "%s Failed: writing to reg 0x%x\n", __func__, reg); return ret; } static int pat9125_i2c_read(u8 reg, u8 *data) static int pat9125_i2c_read(struct i2c_client *client, u8 reg, u8 *data) { u8 buf[20]; int rc; u8 buf[MAX_BUF_SIZE]; int ret; struct device *dev = &client->dev; buf[0] = reg; /* * If everything went ok (i.e. 1 msg transmitted), *return #bytes transmitted, else error code. * thus if transmit is ok return value 1 * If everything went ok (1 msg transmitted), return #bytes transmitted, * else error code. thus if transmit is ok return value 1 */ rc = i2c_master_send(pat9125data.client, buf, 1); if (rc != 1) { pr_debug( "%s (%d) : FAILED: writing to address 0x%x\n", __func__, __LINE__, reg); return -ENODEV; ret = i2c_master_send(client, buf, 1); if (ret != 1) { dev_err(dev, "%s Failed: writing to reg 0x%x\n", __func__, reg); return ret; } /* returns negative errno, or else the number of bytes read */ rc = i2c_master_recv(pat9125data.client, buf, 1); if (rc != 1) { pr_debug( "%s (%d) : FAILED: reading data\n", __func__, __LINE__); return -ENODEV; ret = i2c_master_recv(client, buf, 1); if (ret != 1) { dev_err(dev, "%s Failed: reading reg 0x%x\n", __func__, reg); return ret; } *data = buf[0]; return 0; } void pixart_pat9125_ist(void) { } static irqreturn_t pixart_pat9125_irq(int irq, void *handle) { pixart_pat9125_ist(); return IRQ_HANDLED; } static int pat9125_start(void) { int err = (-1); pr_debug(">>> %s (%d)\n", __func__, __LINE__); err = request_threaded_irq(pat9125data.irq, NULL, pixart_pat9125_irq, pat9125data.irq_flags, "pixart_pat9125_irq", &pat9125data); if (err) pr_debug("irq %d busy?\n", pat9125data.irq); pat9125data.last_jiffies = jiffies_64; return err; } static void pat9125_stop(void) { free_irq(pat9125data.irq, &pat9125data); } static ssize_t pat9125_fops_read(struct file *filp, char *buf, size_t count, loff_t *l) { return 0; return ret; } static ssize_t pat9125_fops_write(struct file *filp, const char *buf, size_t count, loff_t *f_ops) unsigned char read_data(struct i2c_client *client, u8 addr) { return 0; } u8 data = 0xff; static long pat9125_fops_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { return 0; pat9125_i2c_read(client, addr, &data); return data; } static int pat9125_fops_open(struct inode *inode, struct file *filp) void write_data(struct i2c_client *client, u8 addr, u8 data) { return 0; pat9125_i2c_write(client, addr, &data, 1); } static int pat9125_fops_release(struct inode *inode, struct file *filp) static irqreturn_t pixart_pat9125_irq(int irq, void *data) { pr_debug(">>> %s (%d)\n", __func__, __LINE__); return 0; return IRQ_HANDLED; } static const struct file_operations pat9125_fops = { owner: THIS_MODULE, read : pat9125_fops_read, write : pat9125_fops_write, /* ioctl : pat9125_fops_ioctl, */ unlocked_ioctl : pat9125_fops_ioctl, open : pat9125_fops_open, release : pat9125_fops_release, }; /*----------------------------------------------------------------------------*/ struct miscdevice pat9125_device = { .minor = MISC_DYNAMIC_MINOR, .name = pat9125_name, .fops = &pat9125_fops, }; static ssize_t pat9125_test_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { char s[256]; char *p = s; pr_debug("%s (%d) : write_reg_store\n", __func__, __LINE__); memcpy(s, buf, sizeof(s)); char s[256], *p = s; int reg_data = 0, i; long rd_addr, wr_addr, wr_data; struct pixart_pat9125_data *data = (struct pixart_pat9125_data *)dev->driver_data; struct i2c_client *client = data->client; for (i = 0; i < sizeof(s); i++) s[i] = buf[i]; *(s+1) = '\0'; *(s+4) = '\0'; *(s+7) = '\0'; /* example(in console): echo w 12 34 > rw_reg */ if (*p == 'w') { long write_addr, write_data; p += 2; if (!kstrtol(p, 16, &write_addr)) { if (!kstrtol(p, 16, &wr_addr)) { p += 3; if (!kstrtol(p, 16, &write_data)) { pr_debug( "w 0x%x 0x%x\n", (u8)write_addr, (u8)write_data); WriteData((u8)write_addr, (u8)write_data); if (!kstrtol(p, 16, &wr_data)) { dev_dbg(dev, "w 0x%x 0x%x\n", (u8)wr_addr, (u8)wr_data); write_data(client, (u8)wr_addr, (u8)wr_data); } } } /* example(in console): echo r 12 > rw_reg */ } else if (*p == 'r') { long read_addr; else if (*p == 'r') { p += 2; if (!kstrtol(p, 16, &read_addr)) { int data = 0; data = ReadData((u8)read_addr); pr_debug( "r 0x%x 0x%x\n", (unsigned int)read_addr, data); if (!kstrtol(p, 16, &rd_addr)) { reg_data = read_data(client, (u8)rd_addr); dev_dbg(dev, "r 0x%x 0x%x\n", (unsigned int)rd_addr, reg_data); } } return count; } static ssize_t pat9125_test_show( struct device *dev, struct device_attribute *attr, char *buf) static ssize_t pat9125_test_show(struct device *dev, struct device_attribute *attr, char *buf) { /* cat */ pr_debug("%s (%d) :\n", __func__, __LINE__); return 0; } static DEVICE_ATTR( test, S_IRUGO | S_IWUSR | S_IWGRP, pat9125_test_show, pat9125_test_store); static struct device_attribute *pat9125_attr_list[] = { &dev_attr_test, }; static DEVICE_ATTR(test, S_IRUGO | S_IWUSR | S_IWGRP, pat9125_test_show, pat9125_test_store); static int pat9125_create_attr(struct device *dev) { int idx, err = 0; int num = ARRAY_SIZE(pat9125_attr_list); static struct attribute *pat9125_attr_list[] = { &dev_attr_test.attr, NULL, }; if (!dev) return -EINVAL; for (idx = 0; idx < num; idx++) { err = device_create_file(dev, pat9125_attr_list[idx]); if (err) { pr_debug( "device_create_file (%s) = %d\n", pat9125_attr_list[idx]->attr.name, err); break; } } return err; } static struct attribute_group pat9125_attr_grp = { .attrs = pat9125_attr_list, }; static int pat9125_i2c_probe( struct i2c_client *client, static int pat9125_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { int err = 0; struct pixart_pat9125_data *data; struct input_dev *input; struct device_node *np; struct device *dev = &client->dev; struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); pr_debug("%s (%d) : probe module....\n", __func__, __LINE__); memset(&pat9125data, 0, sizeof(pat9125data)); err = i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE); if (err < 0) goto error_return; pat9125data.client = client; err = misc_register(&pat9125_device); if (err) { pr_debug("pat9125_device register failed\n"); goto error_return; err = i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE); if (err < 0) { dev_err(dev, "I2C not supported\n"); return -ENXIO; } pat9125data.pat9125_device = pat9125_device.this_device; err = pat9125_create_attr(pat9125data.pat9125_device); if (err) { pr_debug("create attribute err = %d\n", err); goto error_return; if (client->dev.of_node) { data = devm_kzalloc(dev, sizeof(struct pixart_pat9125_data), GFP_KERNEL); if (!data) return -ENOMEM; } else { data = client->dev.platform_data; if (!data) { dev_err(dev, "Invalid pat9125 data\n"); return -EINVAL; } } data->client = client; if (pat9125_init_input_data() < 0) goto error_return; /* interrupt initialization */ pat9125data.i2c_dev = &client->dev; input = devm_input_allocate_device(dev); if (!input) { dev_err(dev, "Failed to alloc input device\n"); return -ENOMEM; } np = pat9125data.i2c_dev->of_node; pat9125data.irq_gpio = of_get_named_gpio_flags(np, "pixart_pat9125,irq-gpio", 0, &pat9125data.irq_flags); i2c_set_clientdata(client, data); input_set_drvdata(input, data); input->name = PAT9125_DEV_NAME; pr_debug( "irq_gpio: %d, irq_flags: 0x%x\n", pat9125data.irq_gpio, pat9125data.irq_flags); data->input = input; err = input_register_device(data->input); if (err < 0) { dev_err(dev, "Failed to register input device\n"); goto err_register_input_device; } if (!gpio_is_valid(pat9125data.irq_gpio)) { err = (-1); pr_debug( "invalid irq_gpio: %d\n", pat9125data.irq_gpio); goto error_return; if (!gpio_is_valid(data->irq_gpio)) { dev_err(dev, "invalid irq_gpio: %d\n", data->irq_gpio); return -EINVAL; } err = gpio_request(pat9125data.irq_gpio, "pixart_pat9125_irq_gpio"); err = gpio_request(data->irq_gpio, "pixart_pat9125_irq_gpio"); if (err) { pr_debug( "unable to request gpio [%d], [%d]\n", pat9125data.irq_gpio, err); goto error_return; dev_err(dev, "unable to request gpio %d\n", data->irq_gpio); return err; } err = gpio_direction_input(pat9125data.irq_gpio); err = gpio_direction_input(data->irq_gpio); if (err) { pr_debug("unable to set dir for gpio[%d], [%d]\n", pat9125data.irq_gpio, err); goto error_return; dev_err(dev, "unable to set dir for gpio %d\n", data->irq_gpio); goto free_gpio; } pat9125data.irq = gpio_to_irq(pat9125data.irq_gpio); if (!ots_sensor_init(client)) { err = -ENODEV; goto err_sensor_init; } if (!OTS_Sensor_Init()) goto error_return; err = devm_request_threaded_irq(dev, client->irq, NULL, pixart_pat9125_irq, (unsigned long)data->irq_flags, "pixart_pat9125_irq", data); if (err) { dev_err(dev, "Req irq %d failed, errno:%d\n", client->irq, err); goto err_request_threaded_irq; } if (!pat9125_start()) goto error_return; err = sysfs_create_group(&(input->dev.kobj), &pat9125_attr_grp); if (err) { dev_err(dev, "Failed to create sysfs group, errno:%d\n", err); goto err_sysfs_create; } return 0; error_return: err_sysfs_create: err_request_threaded_irq: err_sensor_init: free_gpio: gpio_free(data->irq_gpio); err_register_input_device: input_free_device(data->input); return err; } static int pat9125_i2c_remove(struct i2c_client *client) { struct pixart_pat9125_data *data = i2c_get_clientdata(client); devm_free_irq(&client->dev, client->irq, data); if (gpio_is_valid(data->irq_gpio)) gpio_free(data->irq_gpio); input_unregister_device(data->input); devm_kfree(&client->dev, data); data = NULL; return 0; } static int pat9125_suspend(struct device *dev) { pr_debug("%s (%d) : pat9125 suspend\n", __func__, __LINE__); { return 0; } static int pat9125_resume(struct device *dev) { pr_debug("%s (%d) : pat9125 resume\n", __func__, __LINE__); return 0; } static const struct i2c_device_id pat9125_device_id[] = { {pat9125_DEV_NAME, 0}, {PAT9125_DEV_NAME, 0}, {} }; MODULE_DEVICE_TABLE(i2c, pat9125_device_id); static const struct dev_pm_ops pat9125_pm_ops = { Loading @@ -390,7 +280,7 @@ static const struct of_device_id pixart_pat9125_match_table[] = { static struct i2c_driver pat9125_i2c_driver = { .driver = { .name = pat9125_DEV_NAME, .name = PAT9125_DEV_NAME, .owner = THIS_MODULE, .pm = &pat9125_pm_ops, .of_match_table = pixart_pat9125_match_table, Loading @@ -399,72 +289,8 @@ static struct i2c_driver pat9125_i2c_driver = { .remove = pat9125_i2c_remove, .id_table = pat9125_device_id, }; static int pat9125_open(struct input_dev *dev) { pr_debug(">>> %s (%d)\n", __func__, __LINE__); return 0; } static void pat9125_close(struct input_dev *dev) { pr_debug(">>> %s (%d)\n", __func__, __LINE__); } static int pat9125_init_input_data(void) { int ret = 0; module_i2c_driver(pat9125_i2c_driver); pr_debug("%s (%d) : initialize data\n", __func__, __LINE__); pat9125data.pat9125_input_dev = input_allocate_device(); if (!pat9125data.pat9125_input_dev) { pr_debug( "%s (%d) : could not allocate mouse input device\n", __func__, __LINE__); return -ENOMEM; } input_set_drvdata(pat9125data.pat9125_input_dev, &pat9125data); pat9125data.pat9125_input_dev->name = "Pixart pat9125"; pat9125data.pat9125_input_dev->open = pat9125_open; pat9125data.pat9125_input_dev->close = pat9125_close; ret = input_register_device(pat9125data.pat9125_input_dev); if (ret < 0) { input_free_device(pat9125data.pat9125_input_dev); pr_debug( "%s (%d) : could not register input device\n", __func__, __LINE__); return ret; } return 0; } static int __init pat9125_linux_init(void) { return i2c_add_driver(&pat9125_i2c_driver); } static void __exit pat9125_linux_exit(void) { pr_debug("%s (%d) : exit module\n", __func__, __LINE__); pat9125_stop(); misc_register(&pat9125_device); i2c_del_driver(&pat9125_i2c_driver); } module_init(pat9125_linux_init); module_exit(pat9125_linux_exit); MODULE_AUTHOR("pixart"); MODULE_DESCRIPTION("pixart pat9125 driver"); MODULE_LICENSE("GPL");
drivers/input/misc/ots_pat9125/pixart_ots.c +39 −33 Original line number Diff line number Diff line Loading @@ -4,11 +4,20 @@ * */ #include "pixart_platform.h" #include "pixart_ots.h" static void OTS_WriteRead(uint8_t address, uint8_t wdata); static void ots_write_read(struct i2c_client *client, u8 address, u8 wdata) { u8 read_value; do { write_data(client, address, wdata); read_value = read_data(client, address); } while (read_value != wdata); } bool OTS_Sensor_Init(void) bool ots_sensor_init(struct i2c_client *client) { unsigned char sensor_pid = 0, read_id_ok = 0; Loading @@ -16,56 +25,53 @@ bool OTS_Sensor_Init(void) * Read sensor_pid in address 0x00 to check if the * serial link is valid, read value should be 0x31. */ sensor_pid = ReadData(0x00); sensor_pid = read_data(client, PIXART_PAT9125_PRODUCT_ID1_REG); if (sensor_pid == 0x31) { if (sensor_pid == PIXART_PAT9125_SENSOR_ID) { read_id_ok = 1; /* * PAT9125 sensor recommended settings: * switch to bank0, not allowed to perform OTS_RegWriteRead * switch to bank0, not allowed to perform ots_write_read */ WriteData(0x7F, 0x00); write_data(client, PIXART_PAT9125_SELECT_BANK_REG, PIXART_PAT9125_BANK0); /* * software reset (i.e. set bit7 to 1). * It will reset to 0 automatically * so perform OTS_RegWriteRead is not allowed. */ WriteData(0x06, 0x97); write_data(client, PIXART_PAT9125_CONFIG_REG, PIXART_PAT9125_RESET); /* delay 1ms */ delay_ms(1); usleep_range(RESET_DELAY_US, RESET_DELAY_US + 1); /* disable write protect */ OTS_WriteRead(0x09, 0x5A); ots_write_read(client, PIXART_PAT9125_WRITE_PROTECT_REG, PIXART_PAT9125_DISABLE_WRITE_PROTECT); /* set X-axis resolution (depends on application) */ OTS_WriteRead(0x0D, 0x65); ots_write_read(client, PIXART_PAT9125_SET_CPI_RES_X_REG, PIXART_PAT9125_CPI_RESOLUTION_X); /* set Y-axis resolution (depends on application) */ OTS_WriteRead(0x0E, 0xFF); ots_write_read(client, PIXART_PAT9125_SET_CPI_RES_Y_REG, PIXART_PAT9125_CPI_RESOLUTION_Y); /* set 12-bit X/Y data format (depends on application) */ OTS_WriteRead(0x19, 0x04); ots_write_read(client, PIXART_PAT9125_ORIENTATION_REG, PIXART_PAT9125_MOTION_DATA_LENGTH); /* ONLY for VDD=VDDA=1.7~1.9V: for power saving */ OTS_WriteRead(0x4B, 0x04); ots_write_read(client, PIXART_PAT9125_VOLTAGE_SEGMENT_SEL_REG, PIXART_PAT9125_LOW_VOLTAGE_SEGMENT); if (ReadData(0x5E) == 0x04) { OTS_WriteRead(0x5E, 0x08); if (ReadData(0x5D) == 0x10) OTS_WriteRead(0x5D, 0x19); if (read_data(client, PIXART_PAT9125_MISC2_REG) == 0x04) { ots_write_read(client, PIXART_PAT9125_MISC2_REG, 0x08); if (read_data(client, PIXART_PAT9125_MISC1_REG) == 0x10) ots_write_read(client, PIXART_PAT9125_MISC1_REG, 0x19); } OTS_WriteRead(0x09, 0x00);/* enable write protect */ /* enable write protect */ ots_write_read(client, PIXART_PAT9125_WRITE_PROTECT_REG, PIXART_PAT9125_ENABLE_WRITE_PROTECT); } return read_id_ok; } static void OTS_WriteRead(uint8_t address, uint8_t wdata) { uint8_t read_value; do { /* Write data to specified address */ WriteData(address, wdata); /* Read back previous written data */ read_value = ReadData(address); /* Check if the data is correctly written */ } while (read_value != wdata); }
drivers/input/misc/ots_pat9125/pixart_ots.h +35 −6 Original line number Diff line number Diff line Loading @@ -4,13 +4,42 @@ * */ #ifndef _PIXART_OTS_H_ #define _PIXART_OTS_H_ #ifndef __PIXART_OTS_H_ #define __PIXART_OTS_H_ #include "pixart_platform.h" #define PAT9125_DEV_NAME "pixart_pat9125" #define MAX_BUF_SIZE 20 #define RESET_DELAY_US 1000 /* export funtions */ bool OTS_Sensor_Init(void); void OTS_Sensor_ReadMotion(int16_t *dx, int16_t *dy); /* Register addresses */ #define PIXART_PAT9125_PRODUCT_ID1_REG 0x00 #define PIXART_PAT9125_PRODUCT_ID2_REG 0x01 #define PIXART_PAT9125_MOTION_STATUS_REG 0x02 #define PIXART_PAT9125_DELTA_X_LO_REG 0x03 #define PIXART_PAT9125_DELTA_Y_LO_REG 0x04 #define PIXART_PAT9125_CONFIG_REG 0x06 #define PIXART_PAT9125_WRITE_PROTECT_REG 0x09 #define PIXART_PAT9125_SET_CPI_RES_X_REG 0x0D #define PIXART_PAT9125_SET_CPI_RES_Y_REG 0x0E #define PIXART_PAT9125_DELTA_XY_HI_REG 0x12 #define PIXART_PAT9125_ORIENTATION_REG 0x19 #define PIXART_PAT9125_VOLTAGE_SEGMENT_SEL_REG 0x4B #define PIXART_PAT9125_SELECT_BANK_REG 0x7F #define PIXART_PAT9125_MISC1_REG 0x5D #define PIXART_PAT9125_MISC2_REG 0x5E /*Register configuration data */ #define PIXART_PAT9125_SENSOR_ID 0x31 #define PIXART_PAT9125_RESET 0x97 #define PIXART_PAT9125_MOTION_DATA_LENGTH 0x04 #define PIXART_PAT9125_BANK0 0x00 #define PIXART_PAT9125_DISABLE_WRITE_PROTECT 0x5A #define PIXART_PAT9125_ENABLE_WRITE_PROTECT 0x00 #define PIXART_PAT9125_CPI_RESOLUTION_X 0x65 #define PIXART_PAT9125_CPI_RESOLUTION_Y 0xFF #define PIXART_PAT9125_LOW_VOLTAGE_SEGMENT 0x04 #define PIXART_PAT9125_VALID_MOTION_DATA 0x80 /* Export functions */ bool ots_sensor_init(struct i2c_client *); #endif
drivers/input/misc/ots_pat9125/pixart_platform.h +5 −13 Original line number Diff line number Diff line Loading @@ -4,22 +4,14 @@ * */ #ifndef _PIXART_PLATFORM_ #define _PIXART_PLATFORM_ #ifndef __PIXART_PLATFORM_H_ #define __PIXART_PLATFORM_H_ #include <linux/input.h> #include <linux/pm.h> #include <linux/spi/spi.h> #include <linux/module.h> #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/gpio.h> #include <linux/of_gpio.h> #include <linux/i2c.h> #include <linux/delay.h> #include <linux/types.h> /* extern functions */ extern unsigned char ReadData(unsigned char addr); extern void WriteData(unsigned char addr, unsigned char data); extern unsigned char read_data(struct i2c_client *, u8 addr); extern void write_data(struct i2c_client *, u8 addr, u8 data); #endif