blob: fe35168282ea790987d619d63c4edcce4d9da41c [file] [log] [blame]
/*
* Cypress CY8CMBR3xxx CapSense Express Controller Driver
* All registers mentioned in the document are little endian.
*/
#include <linux/bsearch.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/input/cy8cmbr3108.h>
#define CY8CMBR31XX_DRIVER_NAME "cy8cmbr3108"
/*
* Cypress controller is entering a low power state that it wakes from on the
* first address match, but will NACK it. Then, it will ACK the following
* addresses until it re-enters low power mode.
* We retry if the first few reads/writes fail.
*/
#define MAX_RETRIES 5
/*
* Capacitive sensor enable/disable configuration. (R/W)
* bit x corresponds to CSx
* 0: Disabled, 1: Enabled
*/
#define SENSOR_EN 0x00
/*
* Sensitivities (units: count/pF) for button sensors 0-3, 4-7
* Each sensor accounts for two bits
* Most sensitive <-----------------------------------------> Least sensitive
* 0: 50counts/0.1pF, 1: 50counts/0.2pF, 2: 50counts/0.3pF, 3: 50counts/0.4pF
*
* ADDR: SENSITIVITY_BASE
* +-------+-----+-----+-----+-----+-----+-----+-----+-----+
* | Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
* |-------+-----+-----+-----+-----+-----+-----+-----+-----|
* | sensor| CS3 | CS2 | CS1 | CS0 |
* +-------+-----------+-----------+-----------+-----------+
* ADDR: SENSITIVITY_BASE+1
* +-------+-----+-----+-----+-----+-----+-----+-----+-----+
* | Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
* |-------+-----+-----+-----+-----+-----+-----+-----+-----|
* | sensor| CS7 | CS6 | CS5 | CS4 |
* +-------+-----+-----+-----+-----+-----+-----+-----+-----+
*
*/
#define SENSITIVITY_BASE 0x08
/*
* Finger threshold (units: counts) for sensor 0. (R/W)
* The valid range of this bit field: 31~200
* The lower the more sensitive.
* Dafault value: 128
* sensor threshold address for CSx is 0x0C+x
*/
#define SENSOR_THRESHOLD_BASE 0x0C
/*
* Sensor ON debounce configuration.
* Number of consecutive scans for which a sensor's signal must be
* above the finger threshold plus hysteresis in order for the device to report
* an ON status.
* The valid range of this bit field: 1~15
*/
#define SENSOR_DEBOUNCE 0x1C
/*
* Button hysteresis override configuration.
* Bit 7 Hysteresis override. 0: Disabled, 1: Enabled
* Bit [4:0] Hysteresis value (unit: counts) to apply for button hysteresis
* override.
*/
#define BUTTON_HYS 0x1D
/*
* Low baseline reset parameter configuration for button sensor.
* Bit 7 Low_baseline reset threshold override. 0: Disabled, 1: Enabled
* Bit [6:0] Low baseline reset threshold
*/
#define BUTTON_LBR 0x1F
/*
* Button negative noise threshold configuration.
* Bit 7 Button negative noise threshold override. 0: Disabled, 1: Enabled
* Bit [6:0] Button negative noise threshold
*/
#define BUTTON_NNT 0x20
/*
* Button noise threshold configuration.
* Bit 7 Button noise threshold override. 0: Disabled, 1: Enabled
* Bit [6:0] Button noise threshold
*/
#define BUTTON_NT 0x21
/*
* Global sensing and processing configuration. (R/W)
* EMC solution enable (improves noise mitigation). (Bit 2)
* 0: EMC solution disabled, 1: enabled
*
* Automatic threshold enable/disable configuration. (Bit 3)
* 0: Disabled, 1: Enabled
* To use customized thresholds, this bit must be unset.
* Note that automatic thresholds can only be enabled if EMC solution is
* disabled.
*
* Button and slider auto-reset configuration. (Bit 4 and 5)
* This feature prevents a sensor from getting stuck ON in situations such as
* a metal object placed too close to it.
* 0: Disabled, 1: Enabled; timeout = 5s, 2: Enabled; timeout = 20s
*/
#define DEVICE_CFG2 0x4F
/*
* Look for Touch/Look for Prox scan refresh time selection. (R/W)
* Refresh interval in units of 20 ms. Default to 1.
* The valid range of this bit field: 1~25
* Bit 6 and 7 are reserved.
*/
#define REFRESH_CTRL 0x52
/*
* Timeout (in seconds) of no touch activity to trigger (R/W)
* Active mode -> Look for Touch mode
* Look for Touch mode -> Look for Prox mode
* Default value is 63.
* The valid range of this bit field: 0~63
* Bit 6 and 7 are reserved.
*/
#define STATE_TIMEOUT 0x55
/*
* Configuration data CRC. (R/W)
* CCITT CRC16 checksum for all data from offset 0 to 125.
* The valid value of this bit field ranges from 0 to 65535.
*/
#define CONFIG_CRC 0x7E // 16 bits wide, use word R/W
/*
* Command to execute. (R/W)
*
* Write x to CTRL_CMD...
* x=2: The device calculates a CRC checksum over the configuration data in
* this register map and compares the result with the content of CONFIG_CRC.
* If the two values match, the device saves the configuration and the CRC
* checksum to nonvolatile memory.
*
* x=3: The device calculates a CRC checksum over the configuration data in
* this register map and places the result in the CALC_CRC register.
*
* x=255: The device resets itself
*/
#define CTRL_CMD 0x86
/*
* Status returned by the most recently executed command. (R only)
* bit 0 indicates status returned by the most recently executed command
* 0: no error, 1: an error occurred
*/
#define CTRL_CMD_STATUS 0x88
/*
* Error code returned from most recently executed command. (R only)
* 0 : Command was successful
* 253: Write to flash failed
* 254: Stored configuration CRC checksum (in CONFIG_CRC register) did not
* match calculated configuration CRC checksum
* 255: Invalid command
*/
#define CTRL_CMD_ERR 0x89
/*
* Configuration data CRC calculated by host command. (R only)
*/
#define CALC_CRC 0x94 // 16 bits wide, use word R
/*
* Button status indicators. (R only)
* bit x corresponds to CSx.
* 0: Not activated, 1: Activated
* e.g. a value 6 (0b110) means CS2 and CS1 are activated.
*/
#define BUTTON_STAT 0xAA
/*
* Capacitive sensor 0 difference count signal. (R only)
* 16 bits wide but the MSB is reserved, so only LSB is used
* The valid range of this bit field: 0~255
* difference count address for sensor x is (0xBA + 2*x)
*/
#define DIFFERENCE_COUNT_SENSOR_BASE 0xBA
static const int kDefaultConfig = 0x4CF3;
struct cy8cmbr31xx {
struct i2c_client *client;
struct input_dev *input;
const struct cy8cmbr31xx_pdata *pdata;
char phys[32];
int irq;
int reset;
};
// return value read (non-negative) else negative errno on error
static int cy8cmbr31xx_read_regs_byte(struct i2c_client *client, u8 reg){
int ret, retry = 0;
do {
ret = i2c_smbus_read_byte_data(client, reg);
retry++;
} while( (ret < 0) && (retry < MAX_RETRIES) );
if (ret < 0) {
dev_err(&client->dev, "%s: failed to read reg 0x%x.\n",
__func__, reg);
return ret;
}
dev_dbg(&client->dev, "%s: read 0x%x from register 0x%x\n", __func__,
ret, reg);
dev_dbg(&client->dev, "%s: retry = %d\n", __func__, retry);
return ret;
}
// return negative errno else zero on success
static int cy8cmbr31xx_write_regs_byte(struct i2c_client *client, u8 reg,
u8 val)
{
int ret, retry = 0;
do {
ret = i2c_smbus_write_byte_data(client, reg, val);
retry++;
} while( (ret < 0) && (retry < MAX_RETRIES) );
if (ret < 0) {
dev_err(&client->dev, "%s: failed to write reg 0x%x.\n",
__func__, reg);
return ret;
}
dev_dbg(&client->dev, "%s: wrote 0x%x to register 0x%x\n", __func__,
val, reg);
dev_dbg(&client->dev, "%s: retry = %d\n", __func__, retry );
return ret;
}
// return value read (non-negative) else negative errno on error
static int cy8cmbr31xx_read_regs_word(struct i2c_client *client, u8 reg){
int ret, retry = 0;
do {
ret = i2c_smbus_read_word_data(client, reg);
retry++;
} while( (ret < 0) && (retry < MAX_RETRIES) );
if (ret < 0) {
dev_err(&client->dev, "%s: failed to read reg 0x%x.\n",
__func__, reg);
return ret;
}
dev_dbg(&client->dev, "%s: read 0x%x from register 0x%x\n", __func__,
ret, reg);
dev_dbg(&client->dev, "%s: retry = %d\n", __func__, retry );
return ret;
}
// return negative errno else zero on success
static int cy8cmbr31xx_write_regs_word(struct i2c_client *client, u8 reg,
u16 val)
{
int ret, retry = 0;
do {
ret = i2c_smbus_write_word_data(client, reg, val);
retry++;
} while( (ret < 0) && (retry < MAX_RETRIES) );
if (ret < 0) {
dev_err(&client->dev, "%s: failed to write reg 0x%x, "
"ret=%d\n", __func__, reg, ret);
return ret;
}
dev_dbg(&client->dev, "%s: wrote 0x%x to register 0x%x\n", __func__,
val, reg);
dev_dbg(&client->dev, "%s: retry = %d\n", __func__, retry);
return ret;
}
// must be called each time after writing to CTRL_CMD
// return zero on success
// positive value on control command error
// negative value on reading error
static int cy8cmbr31xx_check_control_cmd_status(struct i2c_client *client) {
int ret;
ret = cy8cmbr31xx_read_regs_byte(client, CTRL_CMD_STATUS);
if (ret < 0) {
dev_err(&client->dev, "%s: failed to get control command "
"status\n", __func__);
return ret;
} else if (ret & 0x1){
ret = cy8cmbr31xx_read_regs_byte(client, CTRL_CMD_ERR);
if (ret > 0)
dev_err(&client->dev,"%s: command error. err: %d\n",
__func__, ret);
return ret;
}
return 0;
}
// must be called each time configuration is changed (i.e. write is performed)
// return zero on success
// positive value on control command error
// negative value on r/w error
static int cy8cmbr31xx_save_configuration(struct i2c_client *client) {
int ret;
/* calculate CRC */
ret = cy8cmbr31xx_write_regs_byte(client, CTRL_CMD, 3);
if (ret < 0){
dev_err(&client->dev, "%s: failed to write calculate CRC "
"command.\n", __func__);
return ret;
}
ret = cy8cmbr31xx_check_control_cmd_status(client);
if ( ret != 0)
return ret;
msleep(1); //to allow calculating CRC
/* read out CRC just calculated */
ret = cy8cmbr31xx_read_regs_word(client, CALC_CRC);
if (ret < 0){
dev_err(&client->dev,"%s: failed to get calculated CRC\n",
__func__);
return ret;
}
/* copy the value over and store in CONFIG_CRC */
ret = cy8cmbr31xx_write_regs_word(client, CONFIG_CRC, ret);
if (ret < 0){
dev_err(&client->dev,"%s: failed to set CONFIG_CRC\n",
__func__);
return ret;
}
/* compare CRCs and save configuration */
ret = cy8cmbr31xx_write_regs_byte(client, CTRL_CMD, 2);
if (ret < 0){
dev_err(&client->dev, "%s: failed to save CRC\n", __func__);
return ret;
}
dev_info(&client->dev, "%s: saving CRC\n", __func__);
msleep(1000);
ret = cy8cmbr31xx_check_control_cmd_status(client);
if ( ret != 0) {
dev_err(&client->dev,"%s: failed to save configuration\n",
__func__);
return ret;
}
ret = cy8cmbr31xx_write_regs_byte(client, CTRL_CMD, 255);
if (ret < 0){
dev_err(&client->dev, "%s: failed to do software reset\n",
__func__);
return ret;
}
dev_info(&client->dev, "%s: successfully saved configuration\n",
__func__);
return 0;
}
static ssize_t cy8cmbr31xx_show_helper(struct i2c_client *client,
char *buf, u8 reg)
{
int ret;
ret = cy8cmbr31xx_read_regs_byte(client, reg);
if (ret < 0) {
return ret;
}
return scnprintf(buf, PAGE_SIZE, "%hhu\n", ret);
}
// use when you only care about few bits (must be consecutive) in that register
static ssize_t cy8cmbr31xx_show_helper_masked(struct i2c_client *client,
char *buf, u8 reg, u8 mask, u8 effective_lsb)
{
int ret;
ret = cy8cmbr31xx_read_regs_byte(client, reg);
if (ret < 0) {
return ret;
}
return scnprintf(buf, PAGE_SIZE, "%hhu\n",
(ret & mask) >> effective_lsb);
}
static ssize_t cy8cmbr31xx_store_helper(struct i2c_client *client,
const char *buf, size_t count, u8 reg)
{
int ret;
u8 val;
ret = sscanf(buf, "%hhu", &val);
if (ret != 1) {
dev_err(&client->dev, "%s: failed to parse input value (%s), "
"ret=%d.\n", __func__, buf, ret);
return -EINVAL;
}
if (val > 255) {
dev_err(&client->dev,
"%s: invalid input value (%s), must be in the range of "
"[0:255]\n", __func__, buf);
return -EINVAL;
}
ret = cy8cmbr31xx_write_regs_byte(client, reg, val);
if (ret < 0)
return ret;
ret = cy8cmbr31xx_save_configuration(client);
if (ret)
return ret;
return count;
}
// use when you only modify few bits (must be consecutive) in that register
static ssize_t cy8cmbr31xx_store_helper_masked(struct i2c_client *client,
const char *buf, size_t count, u8 reg, u8 mask, u8 effective_lsb)
{
int ret;
u8 val;
ret = sscanf(buf, "%hhu", &val);
if (ret != 1) {
dev_err(&client->dev, "%s: failed to parse input value (%s), "
"ret=%d.\n", __func__, buf, ret);
return -EINVAL;
}
if (val > (mask >> effective_lsb)) {
dev_err(&client->dev,
"%s: invalid input value (%s), must be in the range of "
"[0:%d]\n", __func__, buf, mask >> effective_lsb);
return -EINVAL;
}
ret = cy8cmbr31xx_read_regs_byte(client, reg);
if (ret < 0)
return ret;
val = (ret & ~mask) | (val << effective_lsb);
// config unchanged
if (val == ret)
return count;
ret = cy8cmbr31xx_write_regs_byte(client, reg, val);
if (ret < 0)
return ret;
ret = cy8cmbr31xx_save_configuration(client);
if (ret)
return ret;
return count;
}
static ssize_t cy8cmbr31xx_sensor_threshold_show(struct device *dev,
struct device_attribute *attr, char *buf){
struct i2c_client *client = to_i2c_client(dev);
struct cy8cmbr31xx *ts = i2c_get_clientdata(client);
unsigned int sensor_index;
int ret = sscanf(attr->attr.name, "thold%u", &sensor_index);
if (ret != 1) {
dev_err(dev, "%s: failed to get sensor index.\n", __func__);
return -EINVAL;
}
if (sensor_index >= ts->pdata->num_sensors) {
dev_err(dev, "%s: invalid sensor index: %d\n", __func__,
sensor_index);
return -EINVAL;
}
return cy8cmbr31xx_show_helper(client, buf,
SENSOR_THRESHOLD_BASE+sensor_index);
}
static ssize_t cy8cmbr31xx_sensor_threshold_store(struct device *dev,
struct device_attribute *attr, char *buf, ssize_t count){
struct i2c_client *client = to_i2c_client(dev);
struct cy8cmbr31xx *ts = i2c_get_clientdata(client);
unsigned int sensor_index;
int ret = sscanf(attr->attr.name, "thold%u", &sensor_index);
if (ret != 1) {
dev_err(dev, "%s: failed to get sensor index.\n", __func__);
return -EINVAL;
}
if (sensor_index >= ts->pdata->num_sensors) {
dev_err(dev, "%s: invalid sensor index: %d\n", __func__,
sensor_index);
return -EINVAL;
}
return cy8cmbr31xx_store_helper(client, buf, count,
SENSOR_THRESHOLD_BASE+sensor_index);
}
static ssize_t cy8cmbr31xx_sensitivity_show(struct device *dev,
struct device_attribute *attr, char *buf){
struct i2c_client *client = to_i2c_client(dev);
struct cy8cmbr31xx *ts = i2c_get_clientdata(client);
unsigned int sensor_index;
int ret = sscanf(attr->attr.name, "sens%u", &sensor_index);
if (ret != 1) {
dev_err(dev, "%s: failed to get sensor index.\n", __func__);
return -EINVAL;
}
if (sensor_index >= ts->pdata->num_sensors) {
dev_err(dev, "%s: invalid sensor index: %d\n", __func__,
sensor_index);
return -EINVAL;
}
return cy8cmbr31xx_show_helper_masked(client, buf,
SENSITIVITY_BASE + sensor_index / 4,
0x03 << (2 * (sensor_index % 4)), 2 * (sensor_index % 4));
}
static ssize_t cy8cmbr31xx_sensitivity_store(struct device *dev,
struct device_attribute *attr, char *buf, ssize_t count){
struct i2c_client *client = to_i2c_client(dev);
struct cy8cmbr31xx *ts = i2c_get_clientdata(client);
unsigned int sensor_index;
int ret = sscanf(attr->attr.name, "sens%u", &sensor_index);
if (ret != 1) {
dev_err(dev, "%s: failed to get sensor index.\n", __func__);
return -EINVAL;
}
if (sensor_index >= ts->pdata->num_sensors) {
dev_err(dev, "%s: invalid sensor index: %d\n", __func__,
sensor_index);
return -EINVAL;
}
return cy8cmbr31xx_store_helper_masked(client, buf, count,
SENSITIVITY_BASE + sensor_index / 4,
0x03 << (2 * (sensor_index % 4)), 2 * (sensor_index % 4));
}
static ssize_t cy8cmbr31xx_sensor_count_show(struct device *dev,
struct device_attribute *attr, char *buf){
struct i2c_client *client = to_i2c_client(dev);
struct cy8cmbr31xx *ts = i2c_get_clientdata(client);
unsigned int sensor_index;
int ret = sscanf(attr->attr.name, "count%u", &sensor_index);
if (ret != 1) {
dev_err(dev, "%s: failed to get sensor index.\n", __func__);
return -EINVAL;
}
if (sensor_index >= ts->pdata->num_sensors) {
dev_err(dev, "%s: invalid sensor index: %d\n", __func__,
sensor_index);
return -EINVAL;
}
return cy8cmbr31xx_show_helper(client, buf,
DIFFERENCE_COUNT_SENSOR_BASE+2*sensor_index);
}
static struct attribute **all_attrs;
static struct attribute_group cy8cmbr31xx_sensors_attr_group;
static struct device_attribute *sensors_attrs;
static void cy8cmbr31xx_delete_sensors_attr_array(int num_sensors) {
if (sensors_attrs) {
int i;
for (i = 0; i < 3 * num_sensors ; ++i) {
if (sensors_attrs[i].attr.name)
kfree(sensors_attrs[i].attr.name);
}
kfree(sensors_attrs);
}
kfree (all_attrs);
return;
}
static void cy8cmbr31xx_construct_sensors_attributes(int num_sensors,
struct kobject *kobj)
{
int i, error;
// need to NULL terminate the list of attributes -> add 1
all_attrs = kzalloc(sizeof(struct attribute *) * (num_sensors * 3 + 1),
GFP_KERNEL);
if (all_attrs == NULL)
return;
sensors_attrs = kzalloc(
sizeof(struct device_attribute) * num_sensors * 3, GFP_KERNEL);
if (sensors_attrs == NULL)
goto fail;
for (i = 0; i < 3 * num_sensors; ++i) {
char buf[8];
char* name;
if (i < num_sensors)
snprintf(buf, sizeof(buf), "count%u", i);
else if (i < 2 * num_sensors)
snprintf(buf, sizeof(buf), "thold%u", i - num_sensors);
else
snprintf(buf, sizeof(buf), "sens%u", i - 2 * num_sensors);
name = kzalloc(strlen(buf) + 1, GFP_KERNEL);
if (name == NULL)
goto fail;
strncpy(name, buf, strlen(buf) + 1);
sensors_attrs[i].attr.name = name;
if (i < num_sensors) { //count (R only)
sensors_attrs[i].attr.mode = S_IRUGO;
sensors_attrs[i].show = cy8cmbr31xx_sensor_count_show;
} else if (i < 2 * num_sensors){ //thold
sensors_attrs[i].attr.mode = S_IWUSR | S_IWGRP | S_IRUGO;
sensors_attrs[i].show = cy8cmbr31xx_sensor_threshold_show;
sensors_attrs[i].store = cy8cmbr31xx_sensor_threshold_store;
} else { //sens
sensors_attrs[i].attr.mode = S_IWUSR | S_IWGRP | S_IRUGO;
sensors_attrs[i].show = cy8cmbr31xx_sensitivity_show;
sensors_attrs[i].store = cy8cmbr31xx_sensitivity_store;
}
all_attrs[i] = &sensors_attrs[i].attr;
}
cy8cmbr31xx_sensors_attr_group.attrs = all_attrs;
error = sysfs_create_group(kobj, &cy8cmbr31xx_sensors_attr_group);
if (error)
printk("%s: failed to create sysfs, err:%d\n", __func__, error);
return;
fail:
cy8cmbr31xx_delete_sensors_attr_array(num_sensors);
}
static ssize_t cy8cmbr31xx_reset_store(struct device *dev,
struct device_attribute *attr, char *buf, ssize_t count){
int error;
struct i2c_client *client = to_i2c_client(dev);
struct cy8cmbr31xx *ts = i2c_get_clientdata(client);
error = gpio_request(ts->reset, "TouchRST");
if (error) {
dev_err(dev, "%s: failed to request GPIO%d.\n",
__func__, ts->reset);
return error;
}
error = gpio_direction_output(ts->reset, 1);
if (error) {
dev_err(dev, "%s: failed to set gpio to output high.\n",
__func__);
gpio_free(ts->reset);
return error;
}
dev_info(dev, "%s: resetting touch controller...\n", __func__);
gpio_set_value(ts->reset, 0);
msleep(1);
gpio_set_value(ts->reset, 1);
gpio_free(ts->reset);
return count;
}
static const struct map_entry {
const char* name;
const u8 reg;
const u8 mask;
const u8 lsb;
} kNameRegisterMaskLsbMap[] = {
// Must keep in alphabetical order to use bsearch
/* attr.name register mask lsb */
{"auto_threshold", DEVICE_CFG2, 0x08, 3},
{"debounce", SENSOR_DEBOUNCE, 0x0F, 0},
{"emc", DEVICE_CFG2, 0x04, 2},
{"hys_override", BUTTON_HYS, 0x80, 7},
{"hys_threshold", BUTTON_HYS, 0x1F, 0},
{"lbr_override", BUTTON_LBR, 0x80, 7},
{"lbr_threshold", BUTTON_LBR, 0x7F, 0},
{"nnt_override", BUTTON_NNT, 0x80, 7},
{"nnt_threshold", BUTTON_NNT, 0x7F, 0},
{"nt_override", BUTTON_NT, 0x80, 7},
{"nt_threshold", BUTTON_NT, 0x7F, 0},
{"refresh_ctrl", REFRESH_CTRL, 0x3F, 0},
{"state_timeout", STATE_TIMEOUT, 0x3F, 0},
};
const size_t kMapLength = ARRAY_SIZE(kNameRegisterMaskLsbMap);
static int compare_map_entry(const void *e1, const void *e2) {
struct map_entry *entry1 = (struct map_entry *) e1;
struct map_entry *entry2 = (struct map_entry *) e2;
return strcmp(entry1->name, entry2->name);
}
static ssize_t cy8cmbr31xx_common_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct map_entry key = {
.name = attr->attr.name,
};
struct map_entry *res;
res = bsearch(&key, kNameRegisterMaskLsbMap, kMapLength,
sizeof(kNameRegisterMaskLsbMap[0]), compare_map_entry);
if (res == NULL) {
printk("%s: attribute name (%s) cannot be found!\n", __func__,
key.name);
return -ENOENT;
}
return cy8cmbr31xx_show_helper_masked(client, buf, res->reg, res->mask,
res->lsb);
}
static ssize_t cy8cmbr31xx_common_store(struct device *dev,
struct device_attribute *attr, char *buf, size_t count) {
struct i2c_client *client = to_i2c_client(dev);
struct map_entry key, *res;
key.name = attr->attr.name;
res = bsearch(&key, kNameRegisterMaskLsbMap, kMapLength,
sizeof(struct map_entry), compare_map_entry);
if (res == NULL) {
printk("%s: attribute name (%s) cannot be found!\n", __func__,
key.name);
return -ENOENT;
}
return cy8cmbr31xx_store_helper_masked(client, buf, count, res->reg,
res->mask, res->lsb);
}
static struct attribute **all_common_attrs;
static struct attribute_group cy8cmbr31xx_common_attr_group;
static struct device_attribute *common_attrs;
static void cy8cmbr31xx_delete_common_attr_array(void) {
kfree(common_attrs);
kfree(all_common_attrs);
}
static void cy8cmbr31xx_construct_common_attributes(struct kobject *kobj)
{
int i, error;
// add 1 for attribute reset
size_t kCommonAttrLength = kMapLength + 1;
// need to NULL terminate the list of attributes -> add 1
all_common_attrs =
kzalloc(sizeof(struct attribute *) * kCommonAttrLength + 1,
GFP_KERNEL);
if (all_common_attrs == NULL)
return;
common_attrs =
kzalloc(sizeof(struct device_attribute) * kCommonAttrLength,
GFP_KERNEL);
if (common_attrs == NULL)
goto fail;
for (i = 0; i < kMapLength; ++i) {
common_attrs[i].attr.name = kNameRegisterMaskLsbMap[i].name;
common_attrs[i].attr.mode = S_IWUSR | S_IWGRP | S_IRUGO;
common_attrs[i].show = cy8cmbr31xx_common_show;
common_attrs[i].store = cy8cmbr31xx_common_store;
all_common_attrs[i] = &common_attrs[i].attr;
}
// The last one is for reset
common_attrs[i].attr.name = "reset";
common_attrs[i].attr.mode = S_IWUSR | S_IWGRP | S_IRUGO;
common_attrs[i].show = NULL;
common_attrs[i].store = cy8cmbr31xx_reset_store;
all_common_attrs[i] = &common_attrs[i].attr;
cy8cmbr31xx_common_attr_group.attrs = all_common_attrs;
error = sysfs_create_group(kobj, &cy8cmbr31xx_common_attr_group);
if (error)
printk("%s: failed to create sysfs, err:%d\n", __func__, error);
return;
fail:
cy8cmbr31xx_delete_common_attr_array();
}
static void cy8cmbr31xx_report_touch(struct cy8cmbr31xx *ts)
{
struct i2c_client *client = ts->client;
struct input_dev *input = ts->input;
int ret;
ret = cy8cmbr31xx_read_regs_byte(client, BUTTON_STAT);
if (ret >= 0) {
input_event(input, EV_MSC, MSC_PULSELED, ret);
input_sync(input);
// TODO(yichunko): remove this
printk("%s: button status: %d\n", __func__, ret);
}
}
static irqreturn_t cy8cmbr31xx_interrupt(int irq, void *handle)
{
struct cy8cmbr31xx *ts = handle;
cy8cmbr31xx_report_touch(ts);
return IRQ_HANDLED;
}
#ifdef CONFIG_OF
static struct cy8cmbr31xx_pdata *cy8cmbr31xx_parse_devtree(
struct i2c_client *client)
{
struct device *dev = &client->dev;
struct device_node *node;
struct cy8cmbr31xx_pdata *pdata;
int touch_gpio = -1;
int reset_gpio = -1;
int error = 0;
node = dev->of_node;
if (!node) {
dev_err(dev, "%s: of_node is NULL.\n", __func__);
return -ENODEV;
}
pdata = devm_kzalloc(dev, sizeof(struct device_node), GFP_KERNEL);
if (!pdata) {
dev_err(dev, "%s: not enough memory left.\n", __func__);
return -ENOMEM;
}
if (of_property_read_u32(node, "num_sensors", &pdata->num_sensors)) {
dev_err(dev, "%s: failed to get number of sensors.\n",
__func__);
devm_kfree(dev, pdata);
return ERR_PTR(-EINVAL);
}
/* interrupt gpio. */
touch_gpio = of_get_named_gpio(node, "touch_gpio", 0);
if (!gpio_is_valid(touch_gpio))
goto exit;
error = gpio_request(touch_gpio, "TouchIRQ");
if (error)
goto exit;
error = gpio_direction_input(touch_gpio);
if (error) {
gpio_free(touch_gpio);
goto exit;
}
pdata->irq = gpio_to_irq(touch_gpio);
if (pdata->irq < 0) {
dev_err(dev, "%s: failed to get irq number for GPIO%d. "
"err:%d.\n", __func__, touch_gpio, pdata->irq);
goto exit;
}
/* reset gpio */
reset_gpio = of_get_named_gpio(node, "reset_gpio", 0);
if (!gpio_is_valid(reset_gpio))
goto exit;
pdata->reset = reset_gpio;
return pdata;
exit:
if (touch_gpio != -1)
gpio_free(touch_gpio);
dev_err(dev, "%s: Failed to request gpio\n", __func__);
return -ENODEV;
}
#endif
// return zero on success
// positive value on control command error
// negative value on r/w error
static int cy8cmbr31xx_init(struct cy8cmbr31xx *ts)
{
struct i2c_client *client = ts->client;
int ret, i;
ret = cy8cmbr31xx_read_regs_word(client, CONFIG_CRC);
// skip the rest if configuration is default.
if (ret == kDefaultConfig) {
dev_info(&client->dev, "%s: default setting, no further "
"action needed.\n", __func__);
return 0;
}
if (ret > 0) {
dev_info(&client->dev, "%s: configuration data CRC (0x%x), "
"does not match, need to re-configure.\n", __func__,
ret);
}
/* Enable CS4 and CS5 */
ret = cy8cmbr31xx_write_regs_byte(client, SENSOR_EN, 0x30);
if (ret < 0) {
dev_err(&client->dev, "%s: failed to configure CS4, CS5, "
"ret=%d.\n", __func__, ret);
return ret;
}
ret = cy8cmbr31xx_write_regs_byte(client, DEVICE_CFG2, 0x14);
if (ret < 0) {
dev_err(&client->dev, "%s: failed to enable auto-reset and "
"EMC, ret=%d.\n", __func__, ret);
return ret;
}
ret = cy8cmbr31xx_write_regs_word(client, SENSITIVITY_BASE, 0x00);
if (ret < 0) {
dev_err(&client->dev, "%s: failed to reset sensitivity0, "
"ret=%d.\n", __func__, ret);
return ret;
}
ret = cy8cmbr31xx_write_regs_word(client, SENSITIVITY_BASE+1, 0x0F);
if (ret < 0) {
dev_err(&client->dev, "%s: failed to reset sensitivity1, "
"ret=%d.\n", __func__, ret);
return ret;
}
for (i = 0; i < 6; ++i) {
u8 value;
if ( i <= 3 ) {
value = 0x80;
} else {
value = 0x5A;
}
ret = cy8cmbr31xx_write_regs_byte(client,
SENSOR_THRESHOLD_BASE + i,
value);
if (ret < 0) {
dev_err(&client->dev, "%s: failed to set "
"threshold %d to default value(%d). "
"ret=%d.\n", __func__, i, value, ret);
return ret;
}
}
ret = cy8cmbr31xx_write_regs_word(client, REFRESH_CTRL, 0x01);
if (ret < 0) {
dev_err(&client->dev, "%s: failed to set refresh interval, "
"ret=%d.\n", __func__, ret);
return ret;
}
ret = cy8cmbr31xx_write_regs_word(client, STATE_TIMEOUT, 0x3F);
if (ret < 0) {
dev_err(&client->dev, "%s: failed to set timeout of no touch "
"activity, ret=%d.\n", __func__, ret);
return ret;
}
ret = cy8cmbr31xx_write_regs_word(client, SENSOR_DEBOUNCE, 0x03);
if (ret < 0) {
dev_err(&client->dev, "%s: failed to reset sensor debounce "
"configuration, ret=%d.\n", __func__, ret);
return ret;
}
ret = cy8cmbr31xx_write_regs_word(client, BUTTON_HYS, 0x0C);
if (ret < 0) {
dev_err(&client->dev, "%s: failed to reset hysteresis "
"override configuration, ret=%d.\n", __func__, ret);
return ret;
}
ret = cy8cmbr31xx_write_regs_word(client, BUTTON_LBR, 0x32);
if (ret < 0) {
dev_err(&client->dev, "%s: failed to reset low baseline "
"parameter configuration, ret=%d.\n", __func__, ret);
return ret;
}
ret = cy8cmbr31xx_write_regs_word(client, BUTTON_NNT, 0x33);
if (ret < 0) {
dev_err(&client->dev, "%s: failed to reset negative noise "
"threshold configuration, ret=%d.\n", __func__, ret);
return ret;
}
ret = cy8cmbr31xx_write_regs_word(client, BUTTON_NT, 0x33);
if (ret < 0) {
dev_err(&client->dev, "%s: failed to reset noise threshold "
"configuration, ret=%d.\n", __func__, ret);
return ret;
}
ret = cy8cmbr31xx_save_configuration(client);
return ret;
}
// return zero on success
static int cy8cmbr31xx_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct cy8cmbr31xx *ts;
struct device *dev = &client->dev;
const struct cy8cmbr31xx_pdata *pdata = dev_get_platdata(dev);
struct input_dev *input_dev;
int error = 0;
if (!pdata) {
pdata = cy8cmbr31xx_parse_devtree(client);
if (IS_ERR(pdata)) {
dev_err(dev,
"%s: failed to get device data from device tree.\n",
__func__);
error = -EINVAL;
goto err_get_pdata;
}
}
ts = kzalloc(sizeof(struct cy8cmbr31xx), GFP_KERNEL);
input_dev = input_allocate_device();
if (!ts || !input_dev) {
dev_err(&client->dev, "%s: No enough memory.\n", __func__);
error = -ENOMEM;
goto err_free_mem;
}
ts->client = client;
ts->input = input_dev;
ts->pdata = pdata;
ts->irq = pdata->irq;
ts->reset = pdata->reset;
snprintf(ts->phys, sizeof(ts->phys), "%s/input0",
dev_name(&client->dev));
input_dev->name = CY8CMBR31XX_DRIVER_NAME;
input_dev->phys = ts->phys;
input_dev->id.bustype = BUS_I2C;
input_dev->evbit[0] = BIT_MASK(EV_MSC);
// use MSC_PULSELED for joplin to report button status
// since MSC_RAW has been used for rotation speed in chirp
input_set_capability(input_dev, EV_MSC, MSC_PULSELED);
input_set_drvdata(input_dev, ts);
i2c_set_clientdata(client, ts);
error = cy8cmbr31xx_init(ts);
if (error) {
dev_err(&client->dev, "%s: init failed...\n", __func__ );
goto err_free_mem;
}
cy8cmbr31xx_construct_sensors_attributes(pdata->num_sensors,
&client->dev.kobj);
cy8cmbr31xx_construct_common_attributes(&client->dev.kobj);
error = input_register_device(input_dev);
if (error) {
dev_err(&client->dev,
"%s: failed to register input_dev, err:%d\n",
__func__, error);
goto err_remove_sysfs;
}
error = request_threaded_irq(pdata->irq, NULL, cy8cmbr31xx_interrupt,
IRQF_ONESHOT | IRQF_TRIGGER_RISING,
client->name, ts);
if (error) {
dev_err(&client->dev, "%s: failed to request IRQ %d, err:%d\n",
__func__, ts->irq, error);
goto err_unregister_device;
}
dev_info(&client->dev, "%s: probe successfully!\n", __func__);
return 0;
err_unregister_device:
input_unregister_device(input_dev);
input_dev = NULL;
err_remove_sysfs:
sysfs_remove_group(&client->dev.kobj, &cy8cmbr31xx_common_attr_group);
cy8cmbr31xx_delete_common_attr_array();
sysfs_remove_group(&client->dev.kobj, &cy8cmbr31xx_sensors_attr_group);
cy8cmbr31xx_delete_sensors_attr_array(pdata->num_sensors);
err_free_mem:
input_free_device(input_dev);
kfree(ts);
err_get_pdata:
return error;
}
static int cy8cmbr31xx_remove(struct i2c_client *client)
{
return 0;
}
static void cy8cmbr31xx_shutdown(struct i2c_client *client)
{
struct cy8cmbr31xx *ts = i2c_get_clientdata(client);
int num_sensors = ts->pdata->num_sensors;
dev_info(&client->dev, "%s: prepare to shutdown device.\n", __func__);
sysfs_remove_group(&client->dev.kobj, &cy8cmbr31xx_common_attr_group);
cy8cmbr31xx_delete_common_attr_array();
sysfs_remove_group(&client->dev.kobj, &cy8cmbr31xx_sensors_attr_group);
cy8cmbr31xx_delete_sensors_attr_array(num_sensors);
kfree(ts);
}
static const struct i2c_device_id cy8cmbr31xx_idtable[] = {
{ CY8CMBR31XX_DRIVER_NAME, 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, cy8cmbr31xx_idtable);
#ifdef CONFIG_OF
static const struct of_device_id cy8cmbr31xx_of_match[] = {
{ .compatible = CY8CMBR31XX_DRIVER_NAME },
{ }
};
#endif
static struct i2c_driver cy8cmbr31xx_driver = {
.driver = {
.name = CY8CMBR31XX_DRIVER_NAME,
.owner = THIS_MODULE,
.pm = NULL,
.of_match_table = of_match_ptr(cy8cmbr31xx_of_match),
},
.probe = cy8cmbr31xx_probe,
.remove = cy8cmbr31xx_remove,
.shutdown = cy8cmbr31xx_shutdown,
.id_table = cy8cmbr31xx_idtable,
};
module_i2c_driver(cy8cmbr31xx_driver);
MODULE_AUTHOR("Yi-Chun Gina Ko <yichunko@google.com>");
MODULE_DESCRIPTION("CYPRESS CY8CMBR31XX CAPSENSE TOUCH driver");
MODULE_LICENSE("GPL");