1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2562b42d3SAndrew Duggan /*
3562b42d3SAndrew Duggan * Copyright (c) 2012-2016 Synaptics Incorporated
4562b42d3SAndrew Duggan */
5562b42d3SAndrew Duggan
6562b42d3SAndrew Duggan #include <linux/kernel.h>
7562b42d3SAndrew Duggan #include <linux/rmi.h>
8562b42d3SAndrew Duggan #include <linux/input.h>
9562b42d3SAndrew Duggan #include <linux/slab.h>
10562b42d3SAndrew Duggan #include "rmi_driver.h"
11562b42d3SAndrew Duggan
12562b42d3SAndrew Duggan #define RMI_F30_QUERY_SIZE 2
13562b42d3SAndrew Duggan
14562b42d3SAndrew Duggan /* Defs for Query 0 */
15562b42d3SAndrew Duggan #define RMI_F30_EXTENDED_PATTERNS 0x01
16bf3e8502SDmitry Torokhov #define RMI_F30_HAS_MAPPABLE_BUTTONS BIT(1)
17bf3e8502SDmitry Torokhov #define RMI_F30_HAS_LED BIT(2)
18bf3e8502SDmitry Torokhov #define RMI_F30_HAS_GPIO BIT(3)
19bf3e8502SDmitry Torokhov #define RMI_F30_HAS_HAPTIC BIT(4)
20bf3e8502SDmitry Torokhov #define RMI_F30_HAS_GPIO_DRV_CTL BIT(5)
21bf3e8502SDmitry Torokhov #define RMI_F30_HAS_MECH_MOUSE_BTNS BIT(6)
22562b42d3SAndrew Duggan
23562b42d3SAndrew Duggan /* Defs for Query 1 */
24562b42d3SAndrew Duggan #define RMI_F30_GPIO_LED_COUNT 0x1F
25562b42d3SAndrew Duggan
26562b42d3SAndrew Duggan /* Defs for Control Registers */
27562b42d3SAndrew Duggan #define RMI_F30_CTRL_1_GPIO_DEBOUNCE 0x01
28bf3e8502SDmitry Torokhov #define RMI_F30_CTRL_1_HALT BIT(4)
29bf3e8502SDmitry Torokhov #define RMI_F30_CTRL_1_HALTED BIT(5)
30562b42d3SAndrew Duggan #define RMI_F30_CTRL_10_NUM_MECH_MOUSE_BTNS 0x03
31562b42d3SAndrew Duggan
32562b42d3SAndrew Duggan #define RMI_F30_CTRL_MAX_REGS 32
33bf3e8502SDmitry Torokhov #define RMI_F30_CTRL_MAX_BYTES DIV_ROUND_UP(RMI_F30_CTRL_MAX_REGS, 8)
34562b42d3SAndrew Duggan #define RMI_F30_CTRL_MAX_REG_BLOCKS 11
35562b42d3SAndrew Duggan
36562b42d3SAndrew Duggan #define RMI_F30_CTRL_REGS_MAX_SIZE (RMI_F30_CTRL_MAX_BYTES \
37562b42d3SAndrew Duggan + 1 \
38562b42d3SAndrew Duggan + RMI_F30_CTRL_MAX_BYTES \
39562b42d3SAndrew Duggan + RMI_F30_CTRL_MAX_BYTES \
40562b42d3SAndrew Duggan + RMI_F30_CTRL_MAX_BYTES \
41562b42d3SAndrew Duggan + 6 \
42562b42d3SAndrew Duggan + RMI_F30_CTRL_MAX_REGS \
43562b42d3SAndrew Duggan + RMI_F30_CTRL_MAX_REGS \
44562b42d3SAndrew Duggan + RMI_F30_CTRL_MAX_BYTES \
45562b42d3SAndrew Duggan + 1 \
46562b42d3SAndrew Duggan + 1)
47562b42d3SAndrew Duggan
4881dec809SBenjamin Tissoires #define TRACKSTICK_RANGE_START 3
4981dec809SBenjamin Tissoires #define TRACKSTICK_RANGE_END 6
5081dec809SBenjamin Tissoires
51bf3e8502SDmitry Torokhov struct rmi_f30_ctrl_data {
52bf3e8502SDmitry Torokhov int address;
53bf3e8502SDmitry Torokhov int length;
54bf3e8502SDmitry Torokhov u8 *regs;
55bf3e8502SDmitry Torokhov };
56bf3e8502SDmitry Torokhov
57562b42d3SAndrew Duggan struct f30_data {
58562b42d3SAndrew Duggan /* Query Data */
59562b42d3SAndrew Duggan bool has_extended_pattern;
60562b42d3SAndrew Duggan bool has_mappable_buttons;
61562b42d3SAndrew Duggan bool has_led;
62562b42d3SAndrew Duggan bool has_gpio;
63562b42d3SAndrew Duggan bool has_haptic;
64562b42d3SAndrew Duggan bool has_gpio_driver_control;
65562b42d3SAndrew Duggan bool has_mech_mouse_btns;
66562b42d3SAndrew Duggan u8 gpioled_count;
67562b42d3SAndrew Duggan
68562b42d3SAndrew Duggan u8 register_count;
69562b42d3SAndrew Duggan
70562b42d3SAndrew Duggan /* Control Register Data */
71562b42d3SAndrew Duggan struct rmi_f30_ctrl_data ctrl[RMI_F30_CTRL_MAX_REG_BLOCKS];
72562b42d3SAndrew Duggan u8 ctrl_regs[RMI_F30_CTRL_REGS_MAX_SIZE];
73562b42d3SAndrew Duggan u32 ctrl_regs_size;
74562b42d3SAndrew Duggan
75562b42d3SAndrew Duggan u8 data_regs[RMI_F30_CTRL_MAX_BYTES];
76562b42d3SAndrew Duggan u16 *gpioled_key_map;
77562b42d3SAndrew Duggan
78562b42d3SAndrew Duggan struct input_dev *input;
7981dec809SBenjamin Tissoires
8081dec809SBenjamin Tissoires struct rmi_function *f03;
8181dec809SBenjamin Tissoires bool trackstick_buttons;
82562b42d3SAndrew Duggan };
83562b42d3SAndrew Duggan
rmi_f30_read_control_parameters(struct rmi_function * fn,struct f30_data * f30)84562b42d3SAndrew Duggan static int rmi_f30_read_control_parameters(struct rmi_function *fn,
85562b42d3SAndrew Duggan struct f30_data *f30)
86562b42d3SAndrew Duggan {
87bf3e8502SDmitry Torokhov int error;
88562b42d3SAndrew Duggan
89bf3e8502SDmitry Torokhov error = rmi_read_block(fn->rmi_dev, fn->fd.control_base_addr,
90562b42d3SAndrew Duggan f30->ctrl_regs, f30->ctrl_regs_size);
91562b42d3SAndrew Duggan if (error) {
92bf3e8502SDmitry Torokhov dev_err(&fn->dev,
93bf3e8502SDmitry Torokhov "%s: Could not read control registers at 0x%x: %d\n",
94562b42d3SAndrew Duggan __func__, fn->fd.control_base_addr, error);
95562b42d3SAndrew Duggan return error;
96562b42d3SAndrew Duggan }
97562b42d3SAndrew Duggan
98562b42d3SAndrew Duggan return 0;
99562b42d3SAndrew Duggan }
100562b42d3SAndrew Duggan
rmi_f30_report_button(struct rmi_function * fn,struct f30_data * f30,unsigned int button)101bf3e8502SDmitry Torokhov static void rmi_f30_report_button(struct rmi_function *fn,
102bf3e8502SDmitry Torokhov struct f30_data *f30, unsigned int button)
103bf3e8502SDmitry Torokhov {
104bf3e8502SDmitry Torokhov unsigned int reg_num = button >> 3;
105bf3e8502SDmitry Torokhov unsigned int bit_num = button & 0x07;
10681dec809SBenjamin Tissoires u16 key_code = f30->gpioled_key_map[button];
107bf3e8502SDmitry Torokhov bool key_down = !(f30->data_regs[reg_num] & BIT(bit_num));
108bf3e8502SDmitry Torokhov
10981dec809SBenjamin Tissoires if (f30->trackstick_buttons &&
11081dec809SBenjamin Tissoires button >= TRACKSTICK_RANGE_START &&
11181dec809SBenjamin Tissoires button <= TRACKSTICK_RANGE_END) {
11281dec809SBenjamin Tissoires rmi_f03_overwrite_button(f30->f03, key_code, key_down);
11381dec809SBenjamin Tissoires } else {
114bf3e8502SDmitry Torokhov rmi_dbg(RMI_DEBUG_FN, &fn->dev,
115bf3e8502SDmitry Torokhov "%s: call input report key (0x%04x) value (0x%02x)",
11681dec809SBenjamin Tissoires __func__, key_code, key_down);
117bf3e8502SDmitry Torokhov
11881dec809SBenjamin Tissoires input_report_key(f30->input, key_code, key_down);
11981dec809SBenjamin Tissoires }
120bf3e8502SDmitry Torokhov }
121bf3e8502SDmitry Torokhov
rmi_f30_attention(int irq,void * ctx)12224d28e4fSNick Dyer static irqreturn_t rmi_f30_attention(int irq, void *ctx)
123562b42d3SAndrew Duggan {
12424d28e4fSNick Dyer struct rmi_function *fn = ctx;
125562b42d3SAndrew Duggan struct f30_data *f30 = dev_get_drvdata(&fn->dev);
126bf3e8502SDmitry Torokhov struct rmi_driver_data *drvdata = dev_get_drvdata(&fn->rmi_dev->dev);
127bf3e8502SDmitry Torokhov int error;
128562b42d3SAndrew Duggan int i;
129562b42d3SAndrew Duggan
130562b42d3SAndrew Duggan /* Read the gpi led data. */
131ae9979c3SBenjamin Tissoires if (drvdata->attn_data.data) {
132ae9979c3SBenjamin Tissoires if (drvdata->attn_data.size < f30->register_count) {
133bf3e8502SDmitry Torokhov dev_warn(&fn->dev,
134bf3e8502SDmitry Torokhov "F30 interrupted, but data is missing\n");
13524d28e4fSNick Dyer return IRQ_HANDLED;
1366d0dbeaeSAndrew Duggan }
137ae9979c3SBenjamin Tissoires memcpy(f30->data_regs, drvdata->attn_data.data,
138562b42d3SAndrew Duggan f30->register_count);
139ae9979c3SBenjamin Tissoires drvdata->attn_data.data += f30->register_count;
140ae9979c3SBenjamin Tissoires drvdata->attn_data.size -= f30->register_count;
141562b42d3SAndrew Duggan } else {
142bf3e8502SDmitry Torokhov error = rmi_read_block(fn->rmi_dev, fn->fd.data_base_addr,
143562b42d3SAndrew Duggan f30->data_regs, f30->register_count);
144bf3e8502SDmitry Torokhov if (error) {
145bf3e8502SDmitry Torokhov dev_err(&fn->dev,
146bf3e8502SDmitry Torokhov "%s: Failed to read F30 data registers: %d\n",
147bf3e8502SDmitry Torokhov __func__, error);
14824d28e4fSNick Dyer return IRQ_RETVAL(error);
149562b42d3SAndrew Duggan }
150562b42d3SAndrew Duggan }
151562b42d3SAndrew Duggan
15281dec809SBenjamin Tissoires if (f30->has_gpio) {
153bf3e8502SDmitry Torokhov for (i = 0; i < f30->gpioled_count; i++)
154bf3e8502SDmitry Torokhov if (f30->gpioled_key_map[i] != KEY_RESERVED)
155bf3e8502SDmitry Torokhov rmi_f30_report_button(fn, f30, i);
15681dec809SBenjamin Tissoires if (f30->trackstick_buttons)
15781dec809SBenjamin Tissoires rmi_f03_commit_buttons(f30->f03);
15881dec809SBenjamin Tissoires }
159562b42d3SAndrew Duggan
16024d28e4fSNick Dyer return IRQ_HANDLED;
161562b42d3SAndrew Duggan }
162562b42d3SAndrew Duggan
rmi_f30_config(struct rmi_function * fn)163562b42d3SAndrew Duggan static int rmi_f30_config(struct rmi_function *fn)
164562b42d3SAndrew Duggan {
165562b42d3SAndrew Duggan struct f30_data *f30 = dev_get_drvdata(&fn->dev);
166562b42d3SAndrew Duggan struct rmi_driver *drv = fn->rmi_dev->driver;
167562b42d3SAndrew Duggan const struct rmi_device_platform_data *pdata =
168562b42d3SAndrew Duggan rmi_get_platform_data(fn->rmi_dev);
169562b42d3SAndrew Duggan int error;
170562b42d3SAndrew Duggan
171*261bfb33SVincent Huang /* can happen if gpio_data.disable is set */
172b6573da1SBenjamin Tissoires if (!f30)
173b6573da1SBenjamin Tissoires return 0;
174b6573da1SBenjamin Tissoires
175*261bfb33SVincent Huang if (pdata->gpio_data.trackstick_buttons) {
17681dec809SBenjamin Tissoires /* Try [re-]establish link to F03. */
17781dec809SBenjamin Tissoires f30->f03 = rmi_find_function(fn->rmi_dev, 0x03);
17881dec809SBenjamin Tissoires f30->trackstick_buttons = f30->f03 != NULL;
17981dec809SBenjamin Tissoires }
18081dec809SBenjamin Tissoires
181*261bfb33SVincent Huang if (pdata->gpio_data.disable) {
182562b42d3SAndrew Duggan drv->clear_irq_bits(fn->rmi_dev, fn->irq_mask);
183562b42d3SAndrew Duggan } else {
184562b42d3SAndrew Duggan /* Write Control Register values back to device */
185562b42d3SAndrew Duggan error = rmi_write_block(fn->rmi_dev, fn->fd.control_base_addr,
186562b42d3SAndrew Duggan f30->ctrl_regs, f30->ctrl_regs_size);
187562b42d3SAndrew Duggan if (error) {
188bf3e8502SDmitry Torokhov dev_err(&fn->dev,
189bf3e8502SDmitry Torokhov "%s: Could not write control registers at 0x%x: %d\n",
190562b42d3SAndrew Duggan __func__, fn->fd.control_base_addr, error);
191562b42d3SAndrew Duggan return error;
192562b42d3SAndrew Duggan }
193562b42d3SAndrew Duggan
194562b42d3SAndrew Duggan drv->set_irq_bits(fn->rmi_dev, fn->irq_mask);
195562b42d3SAndrew Duggan }
196bf3e8502SDmitry Torokhov
197562b42d3SAndrew Duggan return 0;
198562b42d3SAndrew Duggan }
199562b42d3SAndrew Duggan
rmi_f30_set_ctrl_data(struct rmi_f30_ctrl_data * ctrl,int * ctrl_addr,int len,u8 ** reg)200bf3e8502SDmitry Torokhov static void rmi_f30_set_ctrl_data(struct rmi_f30_ctrl_data *ctrl,
201562b42d3SAndrew Duggan int *ctrl_addr, int len, u8 **reg)
202562b42d3SAndrew Duggan {
203562b42d3SAndrew Duggan ctrl->address = *ctrl_addr;
204562b42d3SAndrew Duggan ctrl->length = len;
205562b42d3SAndrew Duggan ctrl->regs = *reg;
206562b42d3SAndrew Duggan *ctrl_addr += len;
207562b42d3SAndrew Duggan *reg += len;
208562b42d3SAndrew Duggan }
209562b42d3SAndrew Duggan
rmi_f30_is_valid_button(int button,struct rmi_f30_ctrl_data * ctrl)210bf3e8502SDmitry Torokhov static bool rmi_f30_is_valid_button(int button, struct rmi_f30_ctrl_data *ctrl)
211562b42d3SAndrew Duggan {
212562b42d3SAndrew Duggan int byte_position = button >> 3;
213562b42d3SAndrew Duggan int bit_position = button & 0x07;
214562b42d3SAndrew Duggan
215562b42d3SAndrew Duggan /*
216562b42d3SAndrew Duggan * ctrl2 -> dir == 0 -> input mode
217562b42d3SAndrew Duggan * ctrl3 -> data == 1 -> actual button
218562b42d3SAndrew Duggan */
219562b42d3SAndrew Duggan return !(ctrl[2].regs[byte_position] & BIT(bit_position)) &&
220562b42d3SAndrew Duggan (ctrl[3].regs[byte_position] & BIT(bit_position));
221562b42d3SAndrew Duggan }
222562b42d3SAndrew Duggan
rmi_f30_map_gpios(struct rmi_function * fn,struct f30_data * f30)223bf3e8502SDmitry Torokhov static int rmi_f30_map_gpios(struct rmi_function *fn,
224bf3e8502SDmitry Torokhov struct f30_data *f30)
225562b42d3SAndrew Duggan {
226bf3e8502SDmitry Torokhov const struct rmi_device_platform_data *pdata =
227bf3e8502SDmitry Torokhov rmi_get_platform_data(fn->rmi_dev);
228bf3e8502SDmitry Torokhov struct input_dev *input = f30->input;
229bf3e8502SDmitry Torokhov unsigned int button = BTN_LEFT;
23081dec809SBenjamin Tissoires unsigned int trackstick_button = BTN_LEFT;
23181dec809SBenjamin Tissoires bool button_mapped = false;
232562b42d3SAndrew Duggan int i;
2333e64fcbdSAndrew Duggan int button_count = min_t(u8, f30->gpioled_count, TRACKSTICK_RANGE_END);
234562b42d3SAndrew Duggan
235bf3e8502SDmitry Torokhov f30->gpioled_key_map = devm_kcalloc(&fn->dev,
2363e64fcbdSAndrew Duggan button_count,
237bf3e8502SDmitry Torokhov sizeof(f30->gpioled_key_map[0]),
238562b42d3SAndrew Duggan GFP_KERNEL);
239bf3e8502SDmitry Torokhov if (!f30->gpioled_key_map) {
240bf3e8502SDmitry Torokhov dev_err(&fn->dev, "Failed to allocate gpioled map memory.\n");
241562b42d3SAndrew Duggan return -ENOMEM;
242bf3e8502SDmitry Torokhov }
243562b42d3SAndrew Duggan
2443e64fcbdSAndrew Duggan for (i = 0; i < button_count; i++) {
24581dec809SBenjamin Tissoires if (!rmi_f30_is_valid_button(i, f30->ctrl))
24681dec809SBenjamin Tissoires continue;
24781dec809SBenjamin Tissoires
248*261bfb33SVincent Huang if (pdata->gpio_data.trackstick_buttons &&
24981dec809SBenjamin Tissoires i >= TRACKSTICK_RANGE_START && i < TRACKSTICK_RANGE_END) {
25081dec809SBenjamin Tissoires f30->gpioled_key_map[i] = trackstick_button++;
251*261bfb33SVincent Huang } else if (!pdata->gpio_data.buttonpad || !button_mapped) {
252bf3e8502SDmitry Torokhov f30->gpioled_key_map[i] = button;
253bf3e8502SDmitry Torokhov input_set_capability(input, EV_KEY, button++);
25481dec809SBenjamin Tissoires button_mapped = true;
255bf3e8502SDmitry Torokhov }
256bf3e8502SDmitry Torokhov }
257562b42d3SAndrew Duggan
258bf3e8502SDmitry Torokhov input->keycode = f30->gpioled_key_map;
259bf3e8502SDmitry Torokhov input->keycodesize = sizeof(f30->gpioled_key_map[0]);
260bf3e8502SDmitry Torokhov input->keycodemax = f30->gpioled_count;
261bf3e8502SDmitry Torokhov
26281dec809SBenjamin Tissoires /*
26381dec809SBenjamin Tissoires * Buttonpad could be also inferred from f30->has_mech_mouse_btns,
264522214d9SBenjamin Tissoires * but I am not sure, so use only the pdata info and the number of
265522214d9SBenjamin Tissoires * mapped buttons.
26681dec809SBenjamin Tissoires */
267*261bfb33SVincent Huang if (pdata->gpio_data.buttonpad || (button - BTN_LEFT == 1))
26881dec809SBenjamin Tissoires __set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
26981dec809SBenjamin Tissoires
270bf3e8502SDmitry Torokhov return 0;
271bf3e8502SDmitry Torokhov }
272bf3e8502SDmitry Torokhov
rmi_f30_initialize(struct rmi_function * fn,struct f30_data * f30)273bf3e8502SDmitry Torokhov static int rmi_f30_initialize(struct rmi_function *fn, struct f30_data *f30)
274bf3e8502SDmitry Torokhov {
275bf3e8502SDmitry Torokhov u8 *ctrl_reg = f30->ctrl_regs;
276bf3e8502SDmitry Torokhov int control_address = fn->fd.control_base_addr;
277bf3e8502SDmitry Torokhov u8 buf[RMI_F30_QUERY_SIZE];
278bf3e8502SDmitry Torokhov int error;
279bf3e8502SDmitry Torokhov
280bf3e8502SDmitry Torokhov error = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr,
281bf3e8502SDmitry Torokhov buf, RMI_F30_QUERY_SIZE);
282bf3e8502SDmitry Torokhov if (error) {
283bf3e8502SDmitry Torokhov dev_err(&fn->dev, "Failed to read query register\n");
284bf3e8502SDmitry Torokhov return error;
285562b42d3SAndrew Duggan }
286562b42d3SAndrew Duggan
287562b42d3SAndrew Duggan f30->has_extended_pattern = buf[0] & RMI_F30_EXTENDED_PATTERNS;
288562b42d3SAndrew Duggan f30->has_mappable_buttons = buf[0] & RMI_F30_HAS_MAPPABLE_BUTTONS;
289562b42d3SAndrew Duggan f30->has_led = buf[0] & RMI_F30_HAS_LED;
290562b42d3SAndrew Duggan f30->has_gpio = buf[0] & RMI_F30_HAS_GPIO;
291562b42d3SAndrew Duggan f30->has_haptic = buf[0] & RMI_F30_HAS_HAPTIC;
292562b42d3SAndrew Duggan f30->has_gpio_driver_control = buf[0] & RMI_F30_HAS_GPIO_DRV_CTL;
293562b42d3SAndrew Duggan f30->has_mech_mouse_btns = buf[0] & RMI_F30_HAS_MECH_MOUSE_BTNS;
294562b42d3SAndrew Duggan f30->gpioled_count = buf[1] & RMI_F30_GPIO_LED_COUNT;
295562b42d3SAndrew Duggan
296bf3e8502SDmitry Torokhov f30->register_count = DIV_ROUND_UP(f30->gpioled_count, 8);
297562b42d3SAndrew Duggan
298562b42d3SAndrew Duggan if (f30->has_gpio && f30->has_led)
299562b42d3SAndrew Duggan rmi_f30_set_ctrl_data(&f30->ctrl[0], &control_address,
300562b42d3SAndrew Duggan f30->register_count, &ctrl_reg);
301562b42d3SAndrew Duggan
302bf3e8502SDmitry Torokhov rmi_f30_set_ctrl_data(&f30->ctrl[1], &control_address,
303bf3e8502SDmitry Torokhov sizeof(u8), &ctrl_reg);
304562b42d3SAndrew Duggan
305562b42d3SAndrew Duggan if (f30->has_gpio) {
306562b42d3SAndrew Duggan rmi_f30_set_ctrl_data(&f30->ctrl[2], &control_address,
307562b42d3SAndrew Duggan f30->register_count, &ctrl_reg);
308562b42d3SAndrew Duggan
309562b42d3SAndrew Duggan rmi_f30_set_ctrl_data(&f30->ctrl[3], &control_address,
310562b42d3SAndrew Duggan f30->register_count, &ctrl_reg);
311562b42d3SAndrew Duggan }
312562b42d3SAndrew Duggan
313562b42d3SAndrew Duggan if (f30->has_led) {
314562b42d3SAndrew Duggan rmi_f30_set_ctrl_data(&f30->ctrl[4], &control_address,
315562b42d3SAndrew Duggan f30->register_count, &ctrl_reg);
316562b42d3SAndrew Duggan
317562b42d3SAndrew Duggan rmi_f30_set_ctrl_data(&f30->ctrl[5], &control_address,
318bf3e8502SDmitry Torokhov f30->has_extended_pattern ? 6 : 2,
319bf3e8502SDmitry Torokhov &ctrl_reg);
320562b42d3SAndrew Duggan }
321562b42d3SAndrew Duggan
322562b42d3SAndrew Duggan if (f30->has_led || f30->has_gpio_driver_control) {
323562b42d3SAndrew Duggan /* control 6 uses a byte per gpio/led */
324562b42d3SAndrew Duggan rmi_f30_set_ctrl_data(&f30->ctrl[6], &control_address,
325562b42d3SAndrew Duggan f30->gpioled_count, &ctrl_reg);
326562b42d3SAndrew Duggan }
327562b42d3SAndrew Duggan
328562b42d3SAndrew Duggan if (f30->has_mappable_buttons) {
329562b42d3SAndrew Duggan /* control 7 uses a byte per gpio/led */
330562b42d3SAndrew Duggan rmi_f30_set_ctrl_data(&f30->ctrl[7], &control_address,
331562b42d3SAndrew Duggan f30->gpioled_count, &ctrl_reg);
332562b42d3SAndrew Duggan }
333562b42d3SAndrew Duggan
334562b42d3SAndrew Duggan if (f30->has_haptic) {
335562b42d3SAndrew Duggan rmi_f30_set_ctrl_data(&f30->ctrl[8], &control_address,
336562b42d3SAndrew Duggan f30->register_count, &ctrl_reg);
337562b42d3SAndrew Duggan
338562b42d3SAndrew Duggan rmi_f30_set_ctrl_data(&f30->ctrl[9], &control_address,
339562b42d3SAndrew Duggan sizeof(u8), &ctrl_reg);
340562b42d3SAndrew Duggan }
341562b42d3SAndrew Duggan
342562b42d3SAndrew Duggan if (f30->has_mech_mouse_btns)
343562b42d3SAndrew Duggan rmi_f30_set_ctrl_data(&f30->ctrl[10], &control_address,
344562b42d3SAndrew Duggan sizeof(u8), &ctrl_reg);
345562b42d3SAndrew Duggan
346bf3e8502SDmitry Torokhov f30->ctrl_regs_size = ctrl_reg -
347bf3e8502SDmitry Torokhov f30->ctrl_regs ?: RMI_F30_CTRL_REGS_MAX_SIZE;
348562b42d3SAndrew Duggan
349bf3e8502SDmitry Torokhov error = rmi_f30_read_control_parameters(fn, f30);
350bf3e8502SDmitry Torokhov if (error) {
351562b42d3SAndrew Duggan dev_err(&fn->dev,
352bf3e8502SDmitry Torokhov "Failed to initialize F30 control params: %d\n",
353bf3e8502SDmitry Torokhov error);
354bf3e8502SDmitry Torokhov return error;
355562b42d3SAndrew Duggan }
356562b42d3SAndrew Duggan
3570a135b88SBenjamin Tissoires if (f30->has_gpio) {
358bf3e8502SDmitry Torokhov error = rmi_f30_map_gpios(fn, f30);
359bf3e8502SDmitry Torokhov if (error)
360bf3e8502SDmitry Torokhov return error;
361562b42d3SAndrew Duggan }
362562b42d3SAndrew Duggan
363562b42d3SAndrew Duggan return 0;
364562b42d3SAndrew Duggan }
365562b42d3SAndrew Duggan
rmi_f30_probe(struct rmi_function * fn)366562b42d3SAndrew Duggan static int rmi_f30_probe(struct rmi_function *fn)
367562b42d3SAndrew Duggan {
368bf3e8502SDmitry Torokhov struct rmi_device *rmi_dev = fn->rmi_dev;
369562b42d3SAndrew Duggan const struct rmi_device_platform_data *pdata =
370bf3e8502SDmitry Torokhov rmi_get_platform_data(rmi_dev);
371bf3e8502SDmitry Torokhov struct rmi_driver_data *drv_data = dev_get_drvdata(&rmi_dev->dev);
372bf3e8502SDmitry Torokhov struct f30_data *f30;
373bf3e8502SDmitry Torokhov int error;
374562b42d3SAndrew Duggan
375*261bfb33SVincent Huang if (pdata->gpio_data.disable)
376562b42d3SAndrew Duggan return 0;
377562b42d3SAndrew Duggan
378bf3e8502SDmitry Torokhov if (!drv_data->input) {
379bf3e8502SDmitry Torokhov dev_info(&fn->dev, "F30: no input device found, ignoring\n");
380bf3e8502SDmitry Torokhov return -ENXIO;
381bf3e8502SDmitry Torokhov }
382562b42d3SAndrew Duggan
383bf3e8502SDmitry Torokhov f30 = devm_kzalloc(&fn->dev, sizeof(*f30), GFP_KERNEL);
384bf3e8502SDmitry Torokhov if (!f30)
385bf3e8502SDmitry Torokhov return -ENOMEM;
386562b42d3SAndrew Duggan
387bf3e8502SDmitry Torokhov f30->input = drv_data->input;
388bf3e8502SDmitry Torokhov
389bf3e8502SDmitry Torokhov error = rmi_f30_initialize(fn, f30);
390bf3e8502SDmitry Torokhov if (error)
391bf3e8502SDmitry Torokhov return error;
392bf3e8502SDmitry Torokhov
393bf3e8502SDmitry Torokhov dev_set_drvdata(&fn->dev, f30);
394562b42d3SAndrew Duggan return 0;
395562b42d3SAndrew Duggan }
396562b42d3SAndrew Duggan
397562b42d3SAndrew Duggan struct rmi_function_handler rmi_f30_handler = {
398562b42d3SAndrew Duggan .driver = {
399562b42d3SAndrew Duggan .name = "rmi4_f30",
400562b42d3SAndrew Duggan },
401562b42d3SAndrew Duggan .func = 0x30,
402562b42d3SAndrew Duggan .probe = rmi_f30_probe,
403562b42d3SAndrew Duggan .config = rmi_f30_config,
404562b42d3SAndrew Duggan .attention = rmi_f30_attention,
405562b42d3SAndrew Duggan };
406