/* * It's irrelevant that the HW used to develop captouch driver is based * on Atmega88PA part and uses QtouchADC parts for sensing touch. * Calling this driver "captouch" is an arbitrary way to distinguish * the protocol this driver supported by other atmel/qtouch drivers. * * Captouch driver supports a newer/different version of the I2C * registers/commands than the qt1070.c driver. * Don't let the similarity of the general driver structure fool you. * * For raw i2c access from userspace, use i2cset/i2cget * to poke at /dev/i2c-N devices.
*/
/* * @i2c_client: I2C slave device client pointer * @input: Input device pointer * @num_btn: Number of buttons * @keycodes: map of button# to KeyCode * @prev_btn: Previous key state to detect button "press" or "release" * @xfer_buf: I2C transfer buffer
*/ struct atmel_captouch_device { struct i2c_client *client; struct input_dev *input;
u32 num_btn;
u32 keycodes[MAX_NUM_OF_BUTTONS];
u8 prev_btn;
u8 xfer_buf[8] ____cacheline_aligned;
};
/* * Read from I2C slave device * The protocol is that the client has to provide both the register address * and the length, and while reading back the device would prepend the data * with address and length for verification.
*/ staticint atmel_read(struct atmel_captouch_device *capdev,
u8 reg, u8 *data, size_t len)
{ struct i2c_client *client = capdev->client; struct device *dev = &client->dev; struct i2c_msg msg[2]; int err;
if (len > sizeof(capdev->xfer_buf) - 2) return -EINVAL;
if (capdev->xfer_buf[0] != reg) {
dev_err(dev, "I2C read error: register address does not match (%#02x vs %02x)\n",
capdev->xfer_buf[0], reg); return -ECOMM;
}
memcpy(data, &capdev->xfer_buf[2], len);
return 0;
}
/* * Handle interrupt and report the key changes to the input system. * Multi-touch can be supported; however, it really depends on whether * the device can multi-touch.
*/ static irqreturn_t atmel_captouch_isr(int irq, void *data)
{ struct atmel_captouch_device *capdev = data; struct device *dev = &capdev->client->dev; int error; int i;
u8 new_btn;
u8 changed_btn;
error = atmel_read(capdev, REG_KEY_STATE, &new_btn, 1); if (error) {
dev_err(dev, "failed to read button state: %d\n", error); goto out;
}
dev_dbg(dev, "%s: button state %#02x\n", __func__, new_btn);
for (i = 0; i < capdev->num_btn; i++) { if (changed_btn & BIT(i))
input_report_key(capdev->input,
capdev->keycodes[i],
new_btn & BIT(i));
}
input_sync(capdev->input);
out: return IRQ_HANDLED;
}
/* * Probe function to setup the device, input system and interrupt
*/ staticint atmel_captouch_probe(struct i2c_client *client)
{ struct atmel_captouch_device *capdev; struct device *dev = &client->dev; struct device_node *node; int i; int err;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_SMBUS_WORD_DATA |
I2C_FUNC_SMBUS_I2C_BLOCK)) {
dev_err(dev, "needed i2c functionality is not supported\n"); return -EINVAL;
}
capdev = devm_kzalloc(dev, sizeof(*capdev), GFP_KERNEL); if (!capdev) return -ENOMEM;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.