10004520aSAndi Shyti // SPDX-License-Identifier: GPL-2.0
253fefdd1SLinus Walleij // Melfas MMS114/MMS136/MMS152 touchscreen device driver
30004520aSAndi Shyti //
40004520aSAndi Shyti // Copyright (c) 2012 Samsung Electronics Co., Ltd.
50004520aSAndi Shyti // Author: Joonyoung Shim <jy0922.shim@samsung.com>
607b8481dSJoonyoung Shim
707b8481dSJoonyoung Shim #include <linux/module.h>
807b8481dSJoonyoung Shim #include <linux/delay.h>
9ad5396eeSTomasz Figa #include <linux/of.h>
1007b8481dSJoonyoung Shim #include <linux/i2c.h>
1107b8481dSJoonyoung Shim #include <linux/input/mt.h>
125b0d0033SSimon Shields #include <linux/input/touchscreen.h>
1307b8481dSJoonyoung Shim #include <linux/interrupt.h>
1407b8481dSJoonyoung Shim #include <linux/regulator/consumer.h>
1507b8481dSJoonyoung Shim #include <linux/slab.h>
1607b8481dSJoonyoung Shim
1707b8481dSJoonyoung Shim /* Write only registers */
1807b8481dSJoonyoung Shim #define MMS114_MODE_CONTROL 0x01
1907b8481dSJoonyoung Shim #define MMS114_OPERATION_MODE_MASK 0xE
207546db02SAndi Shyti #define MMS114_ACTIVE BIT(1)
2107b8481dSJoonyoung Shim
2207b8481dSJoonyoung Shim #define MMS114_XY_RESOLUTION_H 0x02
2307b8481dSJoonyoung Shim #define MMS114_X_RESOLUTION 0x03
2407b8481dSJoonyoung Shim #define MMS114_Y_RESOLUTION 0x04
2507b8481dSJoonyoung Shim #define MMS114_CONTACT_THRESHOLD 0x05
2607b8481dSJoonyoung Shim #define MMS114_MOVING_THRESHOLD 0x06
2707b8481dSJoonyoung Shim
2807b8481dSJoonyoung Shim /* Read only registers */
2907b8481dSJoonyoung Shim #define MMS114_PACKET_SIZE 0x0F
3013e94540SAndi Shyti #define MMS114_INFORMATION 0x10
3107b8481dSJoonyoung Shim #define MMS114_TSP_REV 0xF0
3207b8481dSJoonyoung Shim
3372b0c0cfSSimon Shields #define MMS152_FW_REV 0xE1
3472b0c0cfSSimon Shields #define MMS152_COMPAT_GROUP 0xF2
3572b0c0cfSSimon Shields
3607b8481dSJoonyoung Shim /* Minimum delay time is 50us between stop and start signal of i2c */
3707b8481dSJoonyoung Shim #define MMS114_I2C_DELAY 50
3807b8481dSJoonyoung Shim
3907b8481dSJoonyoung Shim /* 200ms needs after power on */
4007b8481dSJoonyoung Shim #define MMS114_POWERON_DELAY 200
4107b8481dSJoonyoung Shim
4207b8481dSJoonyoung Shim /* Touchscreen absolute values */
4307b8481dSJoonyoung Shim #define MMS114_MAX_AREA 0xff
4407b8481dSJoonyoung Shim
45*bf93349bSArtur Weber #define MMS114_MAX_TOUCHKEYS 15
4607b8481dSJoonyoung Shim #define MMS114_MAX_TOUCH 10
4753fefdd1SLinus Walleij #define MMS114_EVENT_SIZE 8
4853fefdd1SLinus Walleij #define MMS136_EVENT_SIZE 6
4907b8481dSJoonyoung Shim
5007b8481dSJoonyoung Shim /* Touch type */
5107b8481dSJoonyoung Shim #define MMS114_TYPE_NONE 0
5207b8481dSJoonyoung Shim #define MMS114_TYPE_TOUCHSCREEN 1
5307b8481dSJoonyoung Shim #define MMS114_TYPE_TOUCHKEY 2
5407b8481dSJoonyoung Shim
5572b0c0cfSSimon Shields enum mms_type {
5672b0c0cfSSimon Shields TYPE_MMS114 = 114,
57ab108678SLinus Walleij TYPE_MMS134S = 134,
5853fefdd1SLinus Walleij TYPE_MMS136 = 136,
5972b0c0cfSSimon Shields TYPE_MMS152 = 152,
607842087bSStephan Gerhold TYPE_MMS345L = 345,
6172b0c0cfSSimon Shields };
6272b0c0cfSSimon Shields
6307b8481dSJoonyoung Shim struct mms114_data {
6407b8481dSJoonyoung Shim struct i2c_client *client;
6507b8481dSJoonyoung Shim struct input_dev *input_dev;
6607b8481dSJoonyoung Shim struct regulator *core_reg;
6707b8481dSJoonyoung Shim struct regulator *io_reg;
685b0d0033SSimon Shields struct touchscreen_properties props;
6972b0c0cfSSimon Shields enum mms_type type;
705b0d0033SSimon Shields unsigned int contact_threshold;
715b0d0033SSimon Shields unsigned int moving_threshold;
7207b8481dSJoonyoung Shim
73*bf93349bSArtur Weber u32 keycodes[MMS114_MAX_TOUCHKEYS];
74*bf93349bSArtur Weber int num_keycodes;
75*bf93349bSArtur Weber
7607b8481dSJoonyoung Shim /* Use cache data for mode control register(write only) */
7707b8481dSJoonyoung Shim u8 cache_mode_control;
7807b8481dSJoonyoung Shim };
7907b8481dSJoonyoung Shim
8007b8481dSJoonyoung Shim struct mms114_touch {
8107b8481dSJoonyoung Shim u8 id:4, reserved_bit4:1, type:2, pressed:1;
8207b8481dSJoonyoung Shim u8 x_hi:4, y_hi:4;
8307b8481dSJoonyoung Shim u8 x_lo;
8407b8481dSJoonyoung Shim u8 y_lo;
8507b8481dSJoonyoung Shim u8 width;
8607b8481dSJoonyoung Shim u8 strength;
8707b8481dSJoonyoung Shim u8 reserved[2];
8807b8481dSJoonyoung Shim } __packed;
8907b8481dSJoonyoung Shim
__mms114_read_reg(struct mms114_data * data,unsigned int reg,unsigned int len,u8 * val)9007b8481dSJoonyoung Shim static int __mms114_read_reg(struct mms114_data *data, unsigned int reg,
9107b8481dSJoonyoung Shim unsigned int len, u8 *val)
9207b8481dSJoonyoung Shim {
9307b8481dSJoonyoung Shim struct i2c_client *client = data->client;
9407b8481dSJoonyoung Shim struct i2c_msg xfer[2];
9507b8481dSJoonyoung Shim u8 buf = reg & 0xff;
9607b8481dSJoonyoung Shim int error;
9707b8481dSJoonyoung Shim
9807b8481dSJoonyoung Shim if (reg <= MMS114_MODE_CONTROL && reg + len > MMS114_MODE_CONTROL)
9907b8481dSJoonyoung Shim BUG();
10007b8481dSJoonyoung Shim
1013f8f7705SStephan Gerhold /* Write register */
10207b8481dSJoonyoung Shim xfer[0].addr = client->addr;
1033f8f7705SStephan Gerhold xfer[0].flags = client->flags & I2C_M_TEN;
10407b8481dSJoonyoung Shim xfer[0].len = 1;
10507b8481dSJoonyoung Shim xfer[0].buf = &buf;
10607b8481dSJoonyoung Shim
10707b8481dSJoonyoung Shim /* Read data */
10807b8481dSJoonyoung Shim xfer[1].addr = client->addr;
1093f8f7705SStephan Gerhold xfer[1].flags = (client->flags & I2C_M_TEN) | I2C_M_RD;
11007b8481dSJoonyoung Shim xfer[1].len = len;
11107b8481dSJoonyoung Shim xfer[1].buf = val;
11207b8481dSJoonyoung Shim
11307b8481dSJoonyoung Shim error = i2c_transfer(client->adapter, xfer, 2);
11407b8481dSJoonyoung Shim if (error != 2) {
11507b8481dSJoonyoung Shim dev_err(&client->dev,
11607b8481dSJoonyoung Shim "%s: i2c transfer failed (%d)\n", __func__, error);
11707b8481dSJoonyoung Shim return error < 0 ? error : -EIO;
11807b8481dSJoonyoung Shim }
11907b8481dSJoonyoung Shim udelay(MMS114_I2C_DELAY);
12007b8481dSJoonyoung Shim
12107b8481dSJoonyoung Shim return 0;
12207b8481dSJoonyoung Shim }
12307b8481dSJoonyoung Shim
mms114_read_reg(struct mms114_data * data,unsigned int reg)12407b8481dSJoonyoung Shim static int mms114_read_reg(struct mms114_data *data, unsigned int reg)
12507b8481dSJoonyoung Shim {
12607b8481dSJoonyoung Shim u8 val;
12707b8481dSJoonyoung Shim int error;
12807b8481dSJoonyoung Shim
12907b8481dSJoonyoung Shim if (reg == MMS114_MODE_CONTROL)
13007b8481dSJoonyoung Shim return data->cache_mode_control;
13107b8481dSJoonyoung Shim
13207b8481dSJoonyoung Shim error = __mms114_read_reg(data, reg, 1, &val);
13307b8481dSJoonyoung Shim return error < 0 ? error : val;
13407b8481dSJoonyoung Shim }
13507b8481dSJoonyoung Shim
mms114_write_reg(struct mms114_data * data,unsigned int reg,unsigned int val)13607b8481dSJoonyoung Shim static int mms114_write_reg(struct mms114_data *data, unsigned int reg,
13707b8481dSJoonyoung Shim unsigned int val)
13807b8481dSJoonyoung Shim {
13907b8481dSJoonyoung Shim struct i2c_client *client = data->client;
14007b8481dSJoonyoung Shim u8 buf[2];
14107b8481dSJoonyoung Shim int error;
14207b8481dSJoonyoung Shim
14307b8481dSJoonyoung Shim buf[0] = reg & 0xff;
14407b8481dSJoonyoung Shim buf[1] = val & 0xff;
14507b8481dSJoonyoung Shim
14607b8481dSJoonyoung Shim error = i2c_master_send(client, buf, 2);
14707b8481dSJoonyoung Shim if (error != 2) {
14807b8481dSJoonyoung Shim dev_err(&client->dev,
14907b8481dSJoonyoung Shim "%s: i2c send failed (%d)\n", __func__, error);
15007b8481dSJoonyoung Shim return error < 0 ? error : -EIO;
15107b8481dSJoonyoung Shim }
15207b8481dSJoonyoung Shim udelay(MMS114_I2C_DELAY);
15307b8481dSJoonyoung Shim
15407b8481dSJoonyoung Shim if (reg == MMS114_MODE_CONTROL)
15507b8481dSJoonyoung Shim data->cache_mode_control = val;
15607b8481dSJoonyoung Shim
15707b8481dSJoonyoung Shim return 0;
15807b8481dSJoonyoung Shim }
15907b8481dSJoonyoung Shim
mms114_process_mt(struct mms114_data * data,struct mms114_touch * touch)16007b8481dSJoonyoung Shim static void mms114_process_mt(struct mms114_data *data, struct mms114_touch *touch)
16107b8481dSJoonyoung Shim {
16207b8481dSJoonyoung Shim struct i2c_client *client = data->client;
16307b8481dSJoonyoung Shim struct input_dev *input_dev = data->input_dev;
16407b8481dSJoonyoung Shim unsigned int id;
16507b8481dSJoonyoung Shim unsigned int x;
16607b8481dSJoonyoung Shim unsigned int y;
16707b8481dSJoonyoung Shim
16807b8481dSJoonyoung Shim if (touch->id > MMS114_MAX_TOUCH) {
16907b8481dSJoonyoung Shim dev_err(&client->dev, "Wrong touch id (%d)\n", touch->id);
17007b8481dSJoonyoung Shim return;
17107b8481dSJoonyoung Shim }
17207b8481dSJoonyoung Shim
17307b8481dSJoonyoung Shim id = touch->id - 1;
17407b8481dSJoonyoung Shim x = touch->x_lo | touch->x_hi << 8;
17507b8481dSJoonyoung Shim y = touch->y_lo | touch->y_hi << 8;
17607b8481dSJoonyoung Shim
17707b8481dSJoonyoung Shim dev_dbg(&client->dev,
17807b8481dSJoonyoung Shim "id: %d, type: %d, pressed: %d, x: %d, y: %d, width: %d, strength: %d\n",
17907b8481dSJoonyoung Shim id, touch->type, touch->pressed,
18007b8481dSJoonyoung Shim x, y, touch->width, touch->strength);
18107b8481dSJoonyoung Shim
18207b8481dSJoonyoung Shim input_mt_slot(input_dev, id);
18307b8481dSJoonyoung Shim input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, touch->pressed);
18407b8481dSJoonyoung Shim
18507b8481dSJoonyoung Shim if (touch->pressed) {
1865b0d0033SSimon Shields touchscreen_report_pos(input_dev, &data->props, x, y, true);
18707b8481dSJoonyoung Shim input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, touch->width);
18807b8481dSJoonyoung Shim input_report_abs(input_dev, ABS_MT_PRESSURE, touch->strength);
18907b8481dSJoonyoung Shim }
19007b8481dSJoonyoung Shim }
19107b8481dSJoonyoung Shim
mms114_process_touchkey(struct mms114_data * data,struct mms114_touch * touch)192*bf93349bSArtur Weber static void mms114_process_touchkey(struct mms114_data *data,
193*bf93349bSArtur Weber struct mms114_touch *touch)
194*bf93349bSArtur Weber {
195*bf93349bSArtur Weber struct i2c_client *client = data->client;
196*bf93349bSArtur Weber struct input_dev *input_dev = data->input_dev;
197*bf93349bSArtur Weber unsigned int keycode_id;
198*bf93349bSArtur Weber
199*bf93349bSArtur Weber if (touch->id == 0)
200*bf93349bSArtur Weber return;
201*bf93349bSArtur Weber
202*bf93349bSArtur Weber if (touch->id > data->num_keycodes) {
203*bf93349bSArtur Weber dev_err(&client->dev, "Wrong touch id for touchkey (%d)\n",
204*bf93349bSArtur Weber touch->id);
205*bf93349bSArtur Weber return;
206*bf93349bSArtur Weber }
207*bf93349bSArtur Weber
208*bf93349bSArtur Weber keycode_id = touch->id - 1;
209*bf93349bSArtur Weber dev_dbg(&client->dev, "keycode id: %d, pressed: %d\n", keycode_id,
210*bf93349bSArtur Weber touch->pressed);
211*bf93349bSArtur Weber
212*bf93349bSArtur Weber input_report_key(input_dev, data->keycodes[keycode_id], touch->pressed);
213*bf93349bSArtur Weber }
214*bf93349bSArtur Weber
mms114_interrupt(int irq,void * dev_id)21507b8481dSJoonyoung Shim static irqreturn_t mms114_interrupt(int irq, void *dev_id)
21607b8481dSJoonyoung Shim {
21707b8481dSJoonyoung Shim struct mms114_data *data = dev_id;
218*bf93349bSArtur Weber struct i2c_client *client = data->client;
21907b8481dSJoonyoung Shim struct input_dev *input_dev = data->input_dev;
22007b8481dSJoonyoung Shim struct mms114_touch touch[MMS114_MAX_TOUCH];
22107b8481dSJoonyoung Shim int packet_size;
22207b8481dSJoonyoung Shim int touch_size;
22307b8481dSJoonyoung Shim int index;
22407b8481dSJoonyoung Shim int error;
22507b8481dSJoonyoung Shim
22607b8481dSJoonyoung Shim mutex_lock(&input_dev->mutex);
227d69f0a43SAndrzej Pietrasiewicz if (!input_device_enabled(input_dev)) {
22807b8481dSJoonyoung Shim mutex_unlock(&input_dev->mutex);
22907b8481dSJoonyoung Shim goto out;
23007b8481dSJoonyoung Shim }
23107b8481dSJoonyoung Shim mutex_unlock(&input_dev->mutex);
23207b8481dSJoonyoung Shim
23307b8481dSJoonyoung Shim packet_size = mms114_read_reg(data, MMS114_PACKET_SIZE);
23407b8481dSJoonyoung Shim if (packet_size <= 0)
23507b8481dSJoonyoung Shim goto out;
23607b8481dSJoonyoung Shim
23753fefdd1SLinus Walleij /* MMS136 has slightly different event size */
238ab108678SLinus Walleij if (data->type == TYPE_MMS134S || data->type == TYPE_MMS136)
23953fefdd1SLinus Walleij touch_size = packet_size / MMS136_EVENT_SIZE;
24053fefdd1SLinus Walleij else
24153fefdd1SLinus Walleij touch_size = packet_size / MMS114_EVENT_SIZE;
24207b8481dSJoonyoung Shim
24313e94540SAndi Shyti error = __mms114_read_reg(data, MMS114_INFORMATION, packet_size,
24407b8481dSJoonyoung Shim (u8 *)touch);
24507b8481dSJoonyoung Shim if (error < 0)
24607b8481dSJoonyoung Shim goto out;
24707b8481dSJoonyoung Shim
248*bf93349bSArtur Weber for (index = 0; index < touch_size; index++) {
249*bf93349bSArtur Weber switch (touch[index].type) {
250*bf93349bSArtur Weber case MMS114_TYPE_TOUCHSCREEN:
25107b8481dSJoonyoung Shim mms114_process_mt(data, touch + index);
252*bf93349bSArtur Weber break;
253*bf93349bSArtur Weber
254*bf93349bSArtur Weber case MMS114_TYPE_TOUCHKEY:
255*bf93349bSArtur Weber mms114_process_touchkey(data, touch + index);
256*bf93349bSArtur Weber break;
257*bf93349bSArtur Weber
258*bf93349bSArtur Weber default:
259*bf93349bSArtur Weber dev_err(&client->dev, "Wrong touch type (%d)\n",
260*bf93349bSArtur Weber touch[index].type);
261*bf93349bSArtur Weber break;
262*bf93349bSArtur Weber }
263*bf93349bSArtur Weber }
26407b8481dSJoonyoung Shim
26507b8481dSJoonyoung Shim input_mt_report_pointer_emulation(data->input_dev, true);
26607b8481dSJoonyoung Shim input_sync(data->input_dev);
26707b8481dSJoonyoung Shim
26807b8481dSJoonyoung Shim out:
26907b8481dSJoonyoung Shim return IRQ_HANDLED;
27007b8481dSJoonyoung Shim }
27107b8481dSJoonyoung Shim
mms114_set_active(struct mms114_data * data,bool active)27207b8481dSJoonyoung Shim static int mms114_set_active(struct mms114_data *data, bool active)
27307b8481dSJoonyoung Shim {
27407b8481dSJoonyoung Shim int val;
27507b8481dSJoonyoung Shim
27607b8481dSJoonyoung Shim val = mms114_read_reg(data, MMS114_MODE_CONTROL);
27707b8481dSJoonyoung Shim if (val < 0)
27807b8481dSJoonyoung Shim return val;
27907b8481dSJoonyoung Shim
28007b8481dSJoonyoung Shim val &= ~MMS114_OPERATION_MODE_MASK;
28107b8481dSJoonyoung Shim
28207b8481dSJoonyoung Shim /* If active is false, sleep mode */
28307b8481dSJoonyoung Shim if (active)
28407b8481dSJoonyoung Shim val |= MMS114_ACTIVE;
28507b8481dSJoonyoung Shim
28607b8481dSJoonyoung Shim return mms114_write_reg(data, MMS114_MODE_CONTROL, val);
28707b8481dSJoonyoung Shim }
28807b8481dSJoonyoung Shim
mms114_get_version(struct mms114_data * data)28907b8481dSJoonyoung Shim static int mms114_get_version(struct mms114_data *data)
29007b8481dSJoonyoung Shim {
29107b8481dSJoonyoung Shim struct device *dev = &data->client->dev;
29207b8481dSJoonyoung Shim u8 buf[6];
29372b0c0cfSSimon Shields int group;
29407b8481dSJoonyoung Shim int error;
29507b8481dSJoonyoung Shim
29672b0c0cfSSimon Shields switch (data->type) {
2977842087bSStephan Gerhold case TYPE_MMS345L:
2987842087bSStephan Gerhold error = __mms114_read_reg(data, MMS152_FW_REV, 3, buf);
2997842087bSStephan Gerhold if (error)
3007842087bSStephan Gerhold return error;
3017842087bSStephan Gerhold
3027842087bSStephan Gerhold dev_info(dev, "TSP FW Rev: bootloader 0x%x / core 0x%x / config 0x%x\n",
3037842087bSStephan Gerhold buf[0], buf[1], buf[2]);
3047842087bSStephan Gerhold break;
3057842087bSStephan Gerhold
30672b0c0cfSSimon Shields case TYPE_MMS152:
30772b0c0cfSSimon Shields error = __mms114_read_reg(data, MMS152_FW_REV, 3, buf);
30872b0c0cfSSimon Shields if (error)
30972b0c0cfSSimon Shields return error;
31072b0c0cfSSimon Shields
31172b0c0cfSSimon Shields group = i2c_smbus_read_byte_data(data->client,
31272b0c0cfSSimon Shields MMS152_COMPAT_GROUP);
31372b0c0cfSSimon Shields if (group < 0)
31472b0c0cfSSimon Shields return group;
31572b0c0cfSSimon Shields
31672b0c0cfSSimon Shields dev_info(dev, "TSP FW Rev: bootloader 0x%x / core 0x%x / config 0x%x, Compat group: %c\n",
31772b0c0cfSSimon Shields buf[0], buf[1], buf[2], group);
31872b0c0cfSSimon Shields break;
31972b0c0cfSSimon Shields
32072b0c0cfSSimon Shields case TYPE_MMS114:
321ab108678SLinus Walleij case TYPE_MMS134S:
32253fefdd1SLinus Walleij case TYPE_MMS136:
32307b8481dSJoonyoung Shim error = __mms114_read_reg(data, MMS114_TSP_REV, 6, buf);
32472b0c0cfSSimon Shields if (error)
32507b8481dSJoonyoung Shim return error;
32607b8481dSJoonyoung Shim
32707b8481dSJoonyoung Shim dev_info(dev, "TSP Rev: 0x%x, HW Rev: 0x%x, Firmware Ver: 0x%x\n",
32807b8481dSJoonyoung Shim buf[0], buf[1], buf[3]);
32972b0c0cfSSimon Shields break;
33072b0c0cfSSimon Shields }
33107b8481dSJoonyoung Shim
33207b8481dSJoonyoung Shim return 0;
33307b8481dSJoonyoung Shim }
33407b8481dSJoonyoung Shim
mms114_setup_regs(struct mms114_data * data)33507b8481dSJoonyoung Shim static int mms114_setup_regs(struct mms114_data *data)
33607b8481dSJoonyoung Shim {
3375b0d0033SSimon Shields const struct touchscreen_properties *props = &data->props;
33807b8481dSJoonyoung Shim int val;
33907b8481dSJoonyoung Shim int error;
34007b8481dSJoonyoung Shim
34107b8481dSJoonyoung Shim error = mms114_get_version(data);
34207b8481dSJoonyoung Shim if (error < 0)
34307b8481dSJoonyoung Shim return error;
34407b8481dSJoonyoung Shim
345ab108678SLinus Walleij /* MMS114, MMS134S and MMS136 have configuration and power on registers */
346ab108678SLinus Walleij if (data->type != TYPE_MMS114 && data->type != TYPE_MMS134S &&
347ab108678SLinus Walleij data->type != TYPE_MMS136)
34872b0c0cfSSimon Shields return 0;
34972b0c0cfSSimon Shields
35007b8481dSJoonyoung Shim error = mms114_set_active(data, true);
35107b8481dSJoonyoung Shim if (error < 0)
35207b8481dSJoonyoung Shim return error;
35307b8481dSJoonyoung Shim
3545b0d0033SSimon Shields val = (props->max_x >> 8) & 0xf;
3555b0d0033SSimon Shields val |= ((props->max_y >> 8) & 0xf) << 4;
35607b8481dSJoonyoung Shim error = mms114_write_reg(data, MMS114_XY_RESOLUTION_H, val);
35707b8481dSJoonyoung Shim if (error < 0)
35807b8481dSJoonyoung Shim return error;
35907b8481dSJoonyoung Shim
3605b0d0033SSimon Shields val = props->max_x & 0xff;
36107b8481dSJoonyoung Shim error = mms114_write_reg(data, MMS114_X_RESOLUTION, val);
36207b8481dSJoonyoung Shim if (error < 0)
36307b8481dSJoonyoung Shim return error;
36407b8481dSJoonyoung Shim
3655b0d0033SSimon Shields val = props->max_x & 0xff;
36607b8481dSJoonyoung Shim error = mms114_write_reg(data, MMS114_Y_RESOLUTION, val);
36707b8481dSJoonyoung Shim if (error < 0)
36807b8481dSJoonyoung Shim return error;
36907b8481dSJoonyoung Shim
3705b0d0033SSimon Shields if (data->contact_threshold) {
37107b8481dSJoonyoung Shim error = mms114_write_reg(data, MMS114_CONTACT_THRESHOLD,
3725b0d0033SSimon Shields data->contact_threshold);
37307b8481dSJoonyoung Shim if (error < 0)
37407b8481dSJoonyoung Shim return error;
37507b8481dSJoonyoung Shim }
37607b8481dSJoonyoung Shim
3775b0d0033SSimon Shields if (data->moving_threshold) {
37807b8481dSJoonyoung Shim error = mms114_write_reg(data, MMS114_MOVING_THRESHOLD,
3795b0d0033SSimon Shields data->moving_threshold);
38007b8481dSJoonyoung Shim if (error < 0)
38107b8481dSJoonyoung Shim return error;
38207b8481dSJoonyoung Shim }
38307b8481dSJoonyoung Shim
38407b8481dSJoonyoung Shim return 0;
38507b8481dSJoonyoung Shim }
38607b8481dSJoonyoung Shim
mms114_start(struct mms114_data * data)38707b8481dSJoonyoung Shim static int mms114_start(struct mms114_data *data)
38807b8481dSJoonyoung Shim {
38907b8481dSJoonyoung Shim struct i2c_client *client = data->client;
39007b8481dSJoonyoung Shim int error;
39107b8481dSJoonyoung Shim
3924b7d293cSMark Brown error = regulator_enable(data->core_reg);
3934b7d293cSMark Brown if (error) {
3944b7d293cSMark Brown dev_err(&client->dev, "Failed to enable avdd: %d\n", error);
3954b7d293cSMark Brown return error;
3964b7d293cSMark Brown }
3974b7d293cSMark Brown
3984b7d293cSMark Brown error = regulator_enable(data->io_reg);
3994b7d293cSMark Brown if (error) {
4004b7d293cSMark Brown dev_err(&client->dev, "Failed to enable vdd: %d\n", error);
4014b7d293cSMark Brown regulator_disable(data->core_reg);
4024b7d293cSMark Brown return error;
4034b7d293cSMark Brown }
4044b7d293cSMark Brown
405a22e88fdSAndi Shyti msleep(MMS114_POWERON_DELAY);
40607b8481dSJoonyoung Shim
40707b8481dSJoonyoung Shim error = mms114_setup_regs(data);
4084b7d293cSMark Brown if (error < 0) {
4094b7d293cSMark Brown regulator_disable(data->io_reg);
4104b7d293cSMark Brown regulator_disable(data->core_reg);
41107b8481dSJoonyoung Shim return error;
4124b7d293cSMark Brown }
41307b8481dSJoonyoung Shim
41407b8481dSJoonyoung Shim enable_irq(client->irq);
41507b8481dSJoonyoung Shim
41607b8481dSJoonyoung Shim return 0;
41707b8481dSJoonyoung Shim }
41807b8481dSJoonyoung Shim
mms114_stop(struct mms114_data * data)41907b8481dSJoonyoung Shim static void mms114_stop(struct mms114_data *data)
42007b8481dSJoonyoung Shim {
42107b8481dSJoonyoung Shim struct i2c_client *client = data->client;
4224b7d293cSMark Brown int error;
42307b8481dSJoonyoung Shim
42407b8481dSJoonyoung Shim disable_irq(client->irq);
42507b8481dSJoonyoung Shim
4264b7d293cSMark Brown error = regulator_disable(data->io_reg);
4274b7d293cSMark Brown if (error)
4284b7d293cSMark Brown dev_warn(&client->dev, "Failed to disable vdd: %d\n", error);
4294b7d293cSMark Brown
4304b7d293cSMark Brown error = regulator_disable(data->core_reg);
4314b7d293cSMark Brown if (error)
4324b7d293cSMark Brown dev_warn(&client->dev, "Failed to disable avdd: %d\n", error);
43307b8481dSJoonyoung Shim }
43407b8481dSJoonyoung Shim
mms114_input_open(struct input_dev * dev)43507b8481dSJoonyoung Shim static int mms114_input_open(struct input_dev *dev)
43607b8481dSJoonyoung Shim {
43707b8481dSJoonyoung Shim struct mms114_data *data = input_get_drvdata(dev);
43807b8481dSJoonyoung Shim
43907b8481dSJoonyoung Shim return mms114_start(data);
44007b8481dSJoonyoung Shim }
44107b8481dSJoonyoung Shim
mms114_input_close(struct input_dev * dev)44207b8481dSJoonyoung Shim static void mms114_input_close(struct input_dev *dev)
44307b8481dSJoonyoung Shim {
44407b8481dSJoonyoung Shim struct mms114_data *data = input_get_drvdata(dev);
44507b8481dSJoonyoung Shim
44607b8481dSJoonyoung Shim mms114_stop(data);
44707b8481dSJoonyoung Shim }
44807b8481dSJoonyoung Shim
mms114_parse_legacy_bindings(struct mms114_data * data)4495b0d0033SSimon Shields static int mms114_parse_legacy_bindings(struct mms114_data *data)
450ad5396eeSTomasz Figa {
4515b0d0033SSimon Shields struct device *dev = &data->client->dev;
4525b0d0033SSimon Shields struct touchscreen_properties *props = &data->props;
453ad5396eeSTomasz Figa
4545b0d0033SSimon Shields if (device_property_read_u32(dev, "x-size", &props->max_x)) {
4555b0d0033SSimon Shields dev_dbg(dev, "failed to get legacy x-size property\n");
4565b0d0033SSimon Shields return -EINVAL;
457ad5396eeSTomasz Figa }
458ad5396eeSTomasz Figa
4595b0d0033SSimon Shields if (device_property_read_u32(dev, "y-size", &props->max_y)) {
4605b0d0033SSimon Shields dev_dbg(dev, "failed to get legacy y-size property\n");
4615b0d0033SSimon Shields return -EINVAL;
46286a39bffSJavier Martinez Canillas }
463ad5396eeSTomasz Figa
4645b0d0033SSimon Shields device_property_read_u32(dev, "contact-threshold",
4655b0d0033SSimon Shields &data->contact_threshold);
4665b0d0033SSimon Shields device_property_read_u32(dev, "moving-threshold",
4675b0d0033SSimon Shields &data->moving_threshold);
468ad5396eeSTomasz Figa
4695b0d0033SSimon Shields if (device_property_read_bool(dev, "x-invert"))
4705b0d0033SSimon Shields props->invert_x = true;
4715b0d0033SSimon Shields if (device_property_read_bool(dev, "y-invert"))
4725b0d0033SSimon Shields props->invert_y = true;
473ad5396eeSTomasz Figa
4745b0d0033SSimon Shields props->swap_x_y = false;
475ad5396eeSTomasz Figa
4765b0d0033SSimon Shields return 0;
477ad5396eeSTomasz Figa }
478ad5396eeSTomasz Figa
mms114_probe(struct i2c_client * client)4795e857ccfSUwe Kleine-König static int mms114_probe(struct i2c_client *client)
48007b8481dSJoonyoung Shim {
48107b8481dSJoonyoung Shim struct mms114_data *data;
48207b8481dSJoonyoung Shim struct input_dev *input_dev;
48372b0c0cfSSimon Shields const void *match_data;
48407b8481dSJoonyoung Shim int error;
485*bf93349bSArtur Weber int i;
48607b8481dSJoonyoung Shim
4873f8f7705SStephan Gerhold if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
4883f8f7705SStephan Gerhold dev_err(&client->dev, "Not supported I2C adapter\n");
48907b8481dSJoonyoung Shim return -ENODEV;
49007b8481dSJoonyoung Shim }
49107b8481dSJoonyoung Shim
4928a0b6c5dSSachin Kamat data = devm_kzalloc(&client->dev, sizeof(struct mms114_data),
4938a0b6c5dSSachin Kamat GFP_KERNEL);
4948a0b6c5dSSachin Kamat input_dev = devm_input_allocate_device(&client->dev);
49507b8481dSJoonyoung Shim if (!data || !input_dev) {
49607b8481dSJoonyoung Shim dev_err(&client->dev, "Failed to allocate memory\n");
4978a0b6c5dSSachin Kamat return -ENOMEM;
49807b8481dSJoonyoung Shim }
49907b8481dSJoonyoung Shim
50007b8481dSJoonyoung Shim data->client = client;
50107b8481dSJoonyoung Shim data->input_dev = input_dev;
5025b0d0033SSimon Shields
5038d13c764SStephan Gerhold match_data = device_get_match_data(&client->dev);
50472b0c0cfSSimon Shields if (!match_data)
50572b0c0cfSSimon Shields return -EINVAL;
50672b0c0cfSSimon Shields
50772b0c0cfSSimon Shields data->type = (enum mms_type)match_data;
50872b0c0cfSSimon Shields
509*bf93349bSArtur Weber data->num_keycodes = device_property_count_u32(&client->dev,
510*bf93349bSArtur Weber "linux,keycodes");
511*bf93349bSArtur Weber if (data->num_keycodes == -EINVAL) {
512*bf93349bSArtur Weber data->num_keycodes = 0;
513*bf93349bSArtur Weber } else if (data->num_keycodes < 0) {
514*bf93349bSArtur Weber dev_err(&client->dev,
515*bf93349bSArtur Weber "Unable to parse linux,keycodes property: %d\n",
516*bf93349bSArtur Weber data->num_keycodes);
517*bf93349bSArtur Weber return data->num_keycodes;
518*bf93349bSArtur Weber } else if (data->num_keycodes > MMS114_MAX_TOUCHKEYS) {
519*bf93349bSArtur Weber dev_warn(&client->dev,
520*bf93349bSArtur Weber "Found %d linux,keycodes but max is %d, ignoring the rest\n",
521*bf93349bSArtur Weber data->num_keycodes, MMS114_MAX_TOUCHKEYS);
522*bf93349bSArtur Weber data->num_keycodes = MMS114_MAX_TOUCHKEYS;
523*bf93349bSArtur Weber }
524*bf93349bSArtur Weber
525*bf93349bSArtur Weber if (data->num_keycodes > 0) {
526*bf93349bSArtur Weber error = device_property_read_u32_array(&client->dev,
527*bf93349bSArtur Weber "linux,keycodes",
528*bf93349bSArtur Weber data->keycodes,
529*bf93349bSArtur Weber data->num_keycodes);
530*bf93349bSArtur Weber if (error) {
531*bf93349bSArtur Weber dev_err(&client->dev,
532*bf93349bSArtur Weber "Unable to read linux,keycodes values: %d\n",
533*bf93349bSArtur Weber error);
534*bf93349bSArtur Weber return error;
535*bf93349bSArtur Weber }
536*bf93349bSArtur Weber
537*bf93349bSArtur Weber input_dev->keycode = data->keycodes;
538*bf93349bSArtur Weber input_dev->keycodemax = data->num_keycodes;
539*bf93349bSArtur Weber input_dev->keycodesize = sizeof(data->keycodes[0]);
540*bf93349bSArtur Weber for (i = 0; i < data->num_keycodes; i++)
541*bf93349bSArtur Weber input_set_capability(input_dev,
542*bf93349bSArtur Weber EV_KEY, data->keycodes[i]);
543*bf93349bSArtur Weber }
544*bf93349bSArtur Weber
5455b0d0033SSimon Shields input_set_capability(input_dev, EV_ABS, ABS_MT_POSITION_X);
5465b0d0033SSimon Shields input_set_capability(input_dev, EV_ABS, ABS_MT_POSITION_Y);
5475b0d0033SSimon Shields input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, 255, 0, 0);
5485b0d0033SSimon Shields input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
5495b0d0033SSimon Shields 0, MMS114_MAX_AREA, 0, 0);
5505b0d0033SSimon Shields
5515b0d0033SSimon Shields touchscreen_parse_properties(input_dev, true, &data->props);
5525b0d0033SSimon Shields if (!data->props.max_x || !data->props.max_y) {
5535b0d0033SSimon Shields dev_dbg(&client->dev,
5545b0d0033SSimon Shields "missing X/Y size properties, trying legacy bindings\n");
5555b0d0033SSimon Shields error = mms114_parse_legacy_bindings(data);
5565b0d0033SSimon Shields if (error)
5575b0d0033SSimon Shields return error;
5585b0d0033SSimon Shields
5595b0d0033SSimon Shields input_set_abs_params(input_dev, ABS_MT_POSITION_X,
5605b0d0033SSimon Shields 0, data->props.max_x, 0, 0);
5615b0d0033SSimon Shields input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
5625b0d0033SSimon Shields 0, data->props.max_y, 0, 0);
5635b0d0033SSimon Shields }
5645b0d0033SSimon Shields
565ab108678SLinus Walleij if (data->type == TYPE_MMS114 || data->type == TYPE_MMS134S ||
566ab108678SLinus Walleij data->type == TYPE_MMS136) {
5675b0d0033SSimon Shields /*
5685b0d0033SSimon Shields * The firmware handles movement and pressure fuzz, so
5695b0d0033SSimon Shields * don't duplicate that in software.
5705b0d0033SSimon Shields */
5715b0d0033SSimon Shields data->moving_threshold = input_abs_get_fuzz(input_dev,
5725b0d0033SSimon Shields ABS_MT_POSITION_X);
5735b0d0033SSimon Shields data->contact_threshold = input_abs_get_fuzz(input_dev,
5745b0d0033SSimon Shields ABS_MT_PRESSURE);
5755b0d0033SSimon Shields input_abs_set_fuzz(input_dev, ABS_MT_POSITION_X, 0);
5765b0d0033SSimon Shields input_abs_set_fuzz(input_dev, ABS_MT_POSITION_Y, 0);
5775b0d0033SSimon Shields input_abs_set_fuzz(input_dev, ABS_MT_PRESSURE, 0);
57872b0c0cfSSimon Shields }
57907b8481dSJoonyoung Shim
58072b0c0cfSSimon Shields input_dev->name = devm_kasprintf(&client->dev, GFP_KERNEL,
58172b0c0cfSSimon Shields "MELFAS MMS%d Touchscreen",
58272b0c0cfSSimon Shields data->type);
58372b0c0cfSSimon Shields if (!input_dev->name)
58472b0c0cfSSimon Shields return -ENOMEM;
58572b0c0cfSSimon Shields
58607b8481dSJoonyoung Shim input_dev->id.bustype = BUS_I2C;
58707b8481dSJoonyoung Shim input_dev->dev.parent = &client->dev;
58807b8481dSJoonyoung Shim input_dev->open = mms114_input_open;
58907b8481dSJoonyoung Shim input_dev->close = mms114_input_close;
59007b8481dSJoonyoung Shim
591477baf7eSDmitry Torokhov error = input_mt_init_slots(input_dev, MMS114_MAX_TOUCH,
592477baf7eSDmitry Torokhov INPUT_MT_DIRECT);
593477baf7eSDmitry Torokhov if (error)
594477baf7eSDmitry Torokhov return error;
595477baf7eSDmitry Torokhov
59607b8481dSJoonyoung Shim input_set_drvdata(input_dev, data);
59707b8481dSJoonyoung Shim i2c_set_clientdata(client, data);
59807b8481dSJoonyoung Shim
5998a0b6c5dSSachin Kamat data->core_reg = devm_regulator_get(&client->dev, "avdd");
60007b8481dSJoonyoung Shim if (IS_ERR(data->core_reg)) {
60107b8481dSJoonyoung Shim error = PTR_ERR(data->core_reg);
60207b8481dSJoonyoung Shim dev_err(&client->dev,
60307b8481dSJoonyoung Shim "Unable to get the Core regulator (%d)\n", error);
6048a0b6c5dSSachin Kamat return error;
60507b8481dSJoonyoung Shim }
60607b8481dSJoonyoung Shim
6078a0b6c5dSSachin Kamat data->io_reg = devm_regulator_get(&client->dev, "vdd");
60807b8481dSJoonyoung Shim if (IS_ERR(data->io_reg)) {
60907b8481dSJoonyoung Shim error = PTR_ERR(data->io_reg);
61007b8481dSJoonyoung Shim dev_err(&client->dev,
61107b8481dSJoonyoung Shim "Unable to get the IO regulator (%d)\n", error);
6128a0b6c5dSSachin Kamat return error;
61307b8481dSJoonyoung Shim }
61407b8481dSJoonyoung Shim
6155e703b88SDmitry Torokhov error = devm_request_threaded_irq(&client->dev, client->irq,
616bcd9730aSBarry Song NULL, mms114_interrupt,
617bcd9730aSBarry Song IRQF_ONESHOT | IRQF_NO_AUTOEN,
6188a0b6c5dSSachin Kamat dev_name(&client->dev), data);
61907b8481dSJoonyoung Shim if (error) {
62007b8481dSJoonyoung Shim dev_err(&client->dev, "Failed to register interrupt\n");
6218a0b6c5dSSachin Kamat return error;
62207b8481dSJoonyoung Shim }
62307b8481dSJoonyoung Shim
62407b8481dSJoonyoung Shim error = input_register_device(data->input_dev);
6258a0b6c5dSSachin Kamat if (error) {
6268a0b6c5dSSachin Kamat dev_err(&client->dev, "Failed to register input device\n");
62707b8481dSJoonyoung Shim return error;
62807b8481dSJoonyoung Shim }
62907b8481dSJoonyoung Shim
63007b8481dSJoonyoung Shim return 0;
63107b8481dSJoonyoung Shim }
63207b8481dSJoonyoung Shim
mms114_suspend(struct device * dev)6339b61c454SJonathan Cameron static int mms114_suspend(struct device *dev)
63407b8481dSJoonyoung Shim {
63507b8481dSJoonyoung Shim struct i2c_client *client = to_i2c_client(dev);
63607b8481dSJoonyoung Shim struct mms114_data *data = i2c_get_clientdata(client);
63707b8481dSJoonyoung Shim struct input_dev *input_dev = data->input_dev;
63807b8481dSJoonyoung Shim int id;
63907b8481dSJoonyoung Shim
64007b8481dSJoonyoung Shim /* Release all touch */
64107b8481dSJoonyoung Shim for (id = 0; id < MMS114_MAX_TOUCH; id++) {
64207b8481dSJoonyoung Shim input_mt_slot(input_dev, id);
6435fc70e35SJiada Wang input_mt_report_slot_inactive(input_dev);
64407b8481dSJoonyoung Shim }
64507b8481dSJoonyoung Shim
64607b8481dSJoonyoung Shim input_mt_report_pointer_emulation(input_dev, true);
64707b8481dSJoonyoung Shim input_sync(input_dev);
64807b8481dSJoonyoung Shim
64907b8481dSJoonyoung Shim mutex_lock(&input_dev->mutex);
650d69f0a43SAndrzej Pietrasiewicz if (input_device_enabled(input_dev))
65107b8481dSJoonyoung Shim mms114_stop(data);
65207b8481dSJoonyoung Shim mutex_unlock(&input_dev->mutex);
65307b8481dSJoonyoung Shim
65407b8481dSJoonyoung Shim return 0;
65507b8481dSJoonyoung Shim }
65607b8481dSJoonyoung Shim
mms114_resume(struct device * dev)6579b61c454SJonathan Cameron static int mms114_resume(struct device *dev)
65807b8481dSJoonyoung Shim {
65907b8481dSJoonyoung Shim struct i2c_client *client = to_i2c_client(dev);
66007b8481dSJoonyoung Shim struct mms114_data *data = i2c_get_clientdata(client);
66107b8481dSJoonyoung Shim struct input_dev *input_dev = data->input_dev;
66207b8481dSJoonyoung Shim int error;
66307b8481dSJoonyoung Shim
66407b8481dSJoonyoung Shim mutex_lock(&input_dev->mutex);
665d69f0a43SAndrzej Pietrasiewicz if (input_device_enabled(input_dev)) {
66607b8481dSJoonyoung Shim error = mms114_start(data);
66707b8481dSJoonyoung Shim if (error < 0) {
66807b8481dSJoonyoung Shim mutex_unlock(&input_dev->mutex);
66907b8481dSJoonyoung Shim return error;
67007b8481dSJoonyoung Shim }
67107b8481dSJoonyoung Shim }
67207b8481dSJoonyoung Shim mutex_unlock(&input_dev->mutex);
67307b8481dSJoonyoung Shim
67407b8481dSJoonyoung Shim return 0;
67507b8481dSJoonyoung Shim }
67607b8481dSJoonyoung Shim
6779b61c454SJonathan Cameron static DEFINE_SIMPLE_DEV_PM_OPS(mms114_pm_ops, mms114_suspend, mms114_resume);
67807b8481dSJoonyoung Shim
67907b8481dSJoonyoung Shim static const struct i2c_device_id mms114_id[] = {
68007b8481dSJoonyoung Shim { "mms114", 0 },
68107b8481dSJoonyoung Shim { }
68207b8481dSJoonyoung Shim };
68307b8481dSJoonyoung Shim MODULE_DEVICE_TABLE(i2c, mms114_id);
68407b8481dSJoonyoung Shim
685ad5396eeSTomasz Figa #ifdef CONFIG_OF
686e3c3f4a9SJingoo Han static const struct of_device_id mms114_dt_match[] = {
68772b0c0cfSSimon Shields {
68872b0c0cfSSimon Shields .compatible = "melfas,mms114",
68972b0c0cfSSimon Shields .data = (void *)TYPE_MMS114,
69072b0c0cfSSimon Shields }, {
691ab108678SLinus Walleij .compatible = "melfas,mms134s",
692ab108678SLinus Walleij .data = (void *)TYPE_MMS134S,
693ab108678SLinus Walleij }, {
69453fefdd1SLinus Walleij .compatible = "melfas,mms136",
69553fefdd1SLinus Walleij .data = (void *)TYPE_MMS136,
69653fefdd1SLinus Walleij }, {
69772b0c0cfSSimon Shields .compatible = "melfas,mms152",
69872b0c0cfSSimon Shields .data = (void *)TYPE_MMS152,
6997842087bSStephan Gerhold }, {
7007842087bSStephan Gerhold .compatible = "melfas,mms345l",
7017842087bSStephan Gerhold .data = (void *)TYPE_MMS345L,
70272b0c0cfSSimon Shields },
703ad5396eeSTomasz Figa { }
704ad5396eeSTomasz Figa };
70502d9bd05SJavier Martinez Canillas MODULE_DEVICE_TABLE(of, mms114_dt_match);
706ad5396eeSTomasz Figa #endif
707ad5396eeSTomasz Figa
70807b8481dSJoonyoung Shim static struct i2c_driver mms114_driver = {
70907b8481dSJoonyoung Shim .driver = {
71007b8481dSJoonyoung Shim .name = "mms114",
7119b61c454SJonathan Cameron .pm = pm_sleep_ptr(&mms114_pm_ops),
712ad5396eeSTomasz Figa .of_match_table = of_match_ptr(mms114_dt_match),
71307b8481dSJoonyoung Shim },
714d8bde56dSUwe Kleine-König .probe = mms114_probe,
71507b8481dSJoonyoung Shim .id_table = mms114_id,
71607b8481dSJoonyoung Shim };
71707b8481dSJoonyoung Shim
71807b8481dSJoonyoung Shim module_i2c_driver(mms114_driver);
71907b8481dSJoonyoung Shim
72007b8481dSJoonyoung Shim /* Module information */
72107b8481dSJoonyoung Shim MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
72207b8481dSJoonyoung Shim MODULE_DESCRIPTION("MELFAS mms114 Touchscreen driver");
723498e7e7eSAndi Shyti MODULE_LICENSE("GPL v2");
724