|
@@ -29,7 +29,7 @@ struct pixcir_i2c_ts_data {
|
|
|
struct i2c_client *client;
|
|
|
struct input_dev *input;
|
|
|
const struct pixcir_ts_platform_data *chip;
|
|
|
- bool exiting;
|
|
|
+ bool running;
|
|
|
};
|
|
|
|
|
|
static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
|
|
@@ -88,7 +88,7 @@ static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
|
|
|
{
|
|
|
struct pixcir_i2c_ts_data *tsdata = dev_id;
|
|
|
|
|
|
- while (!tsdata->exiting) {
|
|
|
+ while (tsdata->running) {
|
|
|
pixcir_ts_poscheck(tsdata);
|
|
|
|
|
|
if (tsdata->chip->attb_read_val())
|
|
@@ -100,6 +100,164 @@ static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
|
|
|
return IRQ_HANDLED;
|
|
|
}
|
|
|
|
|
|
+static int pixcir_set_power_mode(struct pixcir_i2c_ts_data *ts,
|
|
|
+ enum pixcir_power_mode mode)
|
|
|
+{
|
|
|
+ struct device *dev = &ts->client->dev;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_POWER_MODE);
|
|
|
+ if (ret < 0) {
|
|
|
+ dev_err(dev, "%s: can't read reg 0x%x : %d\n",
|
|
|
+ __func__, PIXCIR_REG_POWER_MODE, ret);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ ret &= ~PIXCIR_POWER_MODE_MASK;
|
|
|
+ ret |= mode;
|
|
|
+
|
|
|
+ /* Always AUTO_IDLE */
|
|
|
+ ret |= PIXCIR_POWER_ALLOW_IDLE;
|
|
|
+
|
|
|
+ ret = i2c_smbus_write_byte_data(ts->client, PIXCIR_REG_POWER_MODE, ret);
|
|
|
+ if (ret < 0) {
|
|
|
+ dev_err(dev, "%s: can't write reg 0x%x : %d\n",
|
|
|
+ __func__, PIXCIR_REG_POWER_MODE, ret);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Set the interrupt mode for the device i.e. ATTB line behaviour
|
|
|
+ *
|
|
|
+ * @polarity : 1 for active high, 0 for active low.
|
|
|
+ */
|
|
|
+static int pixcir_set_int_mode(struct pixcir_i2c_ts_data *ts,
|
|
|
+ enum pixcir_int_mode mode, bool polarity)
|
|
|
+{
|
|
|
+ struct device *dev = &ts->client->dev;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_INT_MODE);
|
|
|
+ if (ret < 0) {
|
|
|
+ dev_err(dev, "%s: can't read reg 0x%x : %d\n",
|
|
|
+ __func__, PIXCIR_REG_INT_MODE, ret);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ ret &= ~PIXCIR_INT_MODE_MASK;
|
|
|
+ ret |= mode;
|
|
|
+
|
|
|
+ if (polarity)
|
|
|
+ ret |= PIXCIR_INT_POL_HIGH;
|
|
|
+ else
|
|
|
+ ret &= ~PIXCIR_INT_POL_HIGH;
|
|
|
+
|
|
|
+ ret = i2c_smbus_write_byte_data(ts->client, PIXCIR_REG_INT_MODE, ret);
|
|
|
+ if (ret < 0) {
|
|
|
+ dev_err(dev, "%s: can't write reg 0x%x : %d\n",
|
|
|
+ __func__, PIXCIR_REG_INT_MODE, ret);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Enable/disable interrupt generation
|
|
|
+ */
|
|
|
+static int pixcir_int_enable(struct pixcir_i2c_ts_data *ts, bool enable)
|
|
|
+{
|
|
|
+ struct device *dev = &ts->client->dev;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_INT_MODE);
|
|
|
+ if (ret < 0) {
|
|
|
+ dev_err(dev, "%s: can't read reg 0x%x : %d\n",
|
|
|
+ __func__, PIXCIR_REG_INT_MODE, ret);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (enable)
|
|
|
+ ret |= PIXCIR_INT_ENABLE;
|
|
|
+ else
|
|
|
+ ret &= ~PIXCIR_INT_ENABLE;
|
|
|
+
|
|
|
+ ret = i2c_smbus_write_byte_data(ts->client, PIXCIR_REG_INT_MODE, ret);
|
|
|
+ if (ret < 0) {
|
|
|
+ dev_err(dev, "%s: can't write reg 0x%x : %d\n",
|
|
|
+ __func__, PIXCIR_REG_INT_MODE, ret);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int pixcir_start(struct pixcir_i2c_ts_data *ts)
|
|
|
+{
|
|
|
+ struct device *dev = &ts->client->dev;
|
|
|
+ int error;
|
|
|
+
|
|
|
+ /* LEVEL_TOUCH interrupt with active low polarity */
|
|
|
+ error = pixcir_set_int_mode(ts, PIXCIR_INT_LEVEL_TOUCH, 0);
|
|
|
+ if (error) {
|
|
|
+ dev_err(dev, "Failed to set interrupt mode: %d\n", error);
|
|
|
+ return error;
|
|
|
+ }
|
|
|
+
|
|
|
+ ts->running = true;
|
|
|
+ mb(); /* Update status before IRQ can fire */
|
|
|
+
|
|
|
+ /* enable interrupt generation */
|
|
|
+ error = pixcir_int_enable(ts, true);
|
|
|
+ if (error) {
|
|
|
+ dev_err(dev, "Failed to enable interrupt generation: %d\n",
|
|
|
+ error);
|
|
|
+ return error;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int pixcir_stop(struct pixcir_i2c_ts_data *ts)
|
|
|
+{
|
|
|
+ int error;
|
|
|
+
|
|
|
+ /* Disable interrupt generation */
|
|
|
+ error = pixcir_int_enable(ts, false);
|
|
|
+ if (error) {
|
|
|
+ dev_err(&ts->client->dev,
|
|
|
+ "Failed to disable interrupt generation: %d\n",
|
|
|
+ error);
|
|
|
+ return error;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Exit ISR if running, no more report parsing */
|
|
|
+ ts->running = false;
|
|
|
+ mb(); /* update status before we synchronize irq */
|
|
|
+
|
|
|
+ /* Wait till running ISR is complete */
|
|
|
+ synchronize_irq(ts->client->irq);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int pixcir_input_open(struct input_dev *dev)
|
|
|
+{
|
|
|
+ struct pixcir_i2c_ts_data *ts = input_get_drvdata(dev);
|
|
|
+
|
|
|
+ return pixcir_start(ts);
|
|
|
+}
|
|
|
+
|
|
|
+static void pixcir_input_close(struct input_dev *dev)
|
|
|
+{
|
|
|
+ struct pixcir_i2c_ts_data *ts = input_get_drvdata(dev);
|
|
|
+
|
|
|
+ pixcir_stop(ts);
|
|
|
+}
|
|
|
+
|
|
|
#ifdef CONFIG_PM_SLEEP
|
|
|
static int pixcir_i2c_ts_suspend(struct device *dev)
|
|
|
{
|
|
@@ -156,6 +314,8 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
|
|
|
|
|
|
input->name = client->name;
|
|
|
input->id.bustype = BUS_I2C;
|
|
|
+ input->open = pixcir_input_open;
|
|
|
+ input->close = pixcir_input_close;
|
|
|
input->dev.parent = &client->dev;
|
|
|
|
|
|
__set_bit(EV_KEY, input->evbit);
|
|
@@ -176,11 +336,22 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
|
|
|
return error;
|
|
|
}
|
|
|
|
|
|
+ /* Always be in IDLE mode to save power, device supports auto wake */
|
|
|
+ error = pixcir_set_power_mode(tsdata, PIXCIR_POWER_IDLE);
|
|
|
+ if (error) {
|
|
|
+ dev_err(dev, "Failed to set IDLE mode\n");
|
|
|
+ return error;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Stop device till opened */
|
|
|
+ error = pixcir_stop(tsdata);
|
|
|
+ if (error)
|
|
|
+ return error;
|
|
|
+
|
|
|
error = input_register_device(input);
|
|
|
if (error)
|
|
|
return error;
|
|
|
|
|
|
- i2c_set_clientdata(client, tsdata);
|
|
|
device_init_wakeup(&client->dev, 1);
|
|
|
|
|
|
return 0;
|
|
@@ -188,13 +359,8 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
|
|
|
|
|
|
static int pixcir_i2c_ts_remove(struct i2c_client *client)
|
|
|
{
|
|
|
- struct pixcir_i2c_ts_data *tsdata = i2c_get_clientdata(client);
|
|
|
-
|
|
|
device_init_wakeup(&client->dev, 0);
|
|
|
|
|
|
- tsdata->exiting = true;
|
|
|
- mb();
|
|
|
-
|
|
|
return 0;
|
|
|
}
|
|
|
|