xref: /openbmc/linux/drivers/input/rmi4/rmi_f30.c (revision ae9979c3)
1562b42d3SAndrew Duggan /*
2562b42d3SAndrew Duggan  * Copyright (c) 2012-2016 Synaptics Incorporated
3562b42d3SAndrew Duggan  *
4562b42d3SAndrew Duggan  * This program is free software; you can redistribute it and/or modify it
5562b42d3SAndrew Duggan  * under the terms of the GNU General Public License version 2 as published by
6562b42d3SAndrew Duggan  * the Free Software Foundation.
7562b42d3SAndrew Duggan  */
8562b42d3SAndrew Duggan 
9562b42d3SAndrew Duggan #include <linux/kernel.h>
10562b42d3SAndrew Duggan #include <linux/rmi.h>
11562b42d3SAndrew Duggan #include <linux/input.h>
12562b42d3SAndrew Duggan #include <linux/slab.h>
13562b42d3SAndrew Duggan #include "rmi_driver.h"
14562b42d3SAndrew Duggan 
15562b42d3SAndrew Duggan #define RMI_F30_QUERY_SIZE			2
16562b42d3SAndrew Duggan 
17562b42d3SAndrew Duggan /* Defs for Query 0 */
18562b42d3SAndrew Duggan #define RMI_F30_EXTENDED_PATTERNS		0x01
19562b42d3SAndrew Duggan #define RMI_F30_HAS_MAPPABLE_BUTTONS		(1 << 1)
20562b42d3SAndrew Duggan #define RMI_F30_HAS_LED			(1 << 2)
21562b42d3SAndrew Duggan #define RMI_F30_HAS_GPIO			(1 << 3)
22562b42d3SAndrew Duggan #define RMI_F30_HAS_HAPTIC			(1 << 4)
23562b42d3SAndrew Duggan #define RMI_F30_HAS_GPIO_DRV_CTL		(1 << 5)
24562b42d3SAndrew Duggan #define RMI_F30_HAS_MECH_MOUSE_BTNS		(1 << 6)
25562b42d3SAndrew Duggan 
26562b42d3SAndrew Duggan /* Defs for Query 1 */
27562b42d3SAndrew Duggan #define RMI_F30_GPIO_LED_COUNT			0x1F
28562b42d3SAndrew Duggan 
29562b42d3SAndrew Duggan /* Defs for Control Registers */
30562b42d3SAndrew Duggan #define RMI_F30_CTRL_1_GPIO_DEBOUNCE		0x01
31562b42d3SAndrew Duggan #define RMI_F30_CTRL_1_HALT			(1 << 4)
32562b42d3SAndrew Duggan #define RMI_F30_CTRL_1_HALTED			(1 << 5)
33562b42d3SAndrew Duggan #define RMI_F30_CTRL_10_NUM_MECH_MOUSE_BTNS	0x03
34562b42d3SAndrew Duggan 
35562b42d3SAndrew Duggan struct rmi_f30_ctrl_data {
36562b42d3SAndrew Duggan 	int address;
37562b42d3SAndrew Duggan 	int length;
38562b42d3SAndrew Duggan 	u8 *regs;
39562b42d3SAndrew Duggan };
40562b42d3SAndrew Duggan 
41562b42d3SAndrew Duggan #define RMI_F30_CTRL_MAX_REGS		32
42562b42d3SAndrew Duggan #define RMI_F30_CTRL_MAX_BYTES		((RMI_F30_CTRL_MAX_REGS + 7) >> 3)
43562b42d3SAndrew Duggan #define RMI_F30_CTRL_MAX_REG_BLOCKS	11
44562b42d3SAndrew Duggan 
45562b42d3SAndrew Duggan #define RMI_F30_CTRL_REGS_MAX_SIZE (RMI_F30_CTRL_MAX_BYTES		\
46562b42d3SAndrew Duggan 					+ 1				\
47562b42d3SAndrew Duggan 					+ RMI_F30_CTRL_MAX_BYTES	\
48562b42d3SAndrew Duggan 					+ RMI_F30_CTRL_MAX_BYTES	\
49562b42d3SAndrew Duggan 					+ RMI_F30_CTRL_MAX_BYTES	\
50562b42d3SAndrew Duggan 					+ 6				\
51562b42d3SAndrew Duggan 					+ RMI_F30_CTRL_MAX_REGS		\
52562b42d3SAndrew Duggan 					+ RMI_F30_CTRL_MAX_REGS		\
53562b42d3SAndrew Duggan 					+ RMI_F30_CTRL_MAX_BYTES	\
54562b42d3SAndrew Duggan 					+ 1				\
55562b42d3SAndrew Duggan 					+ 1)
56562b42d3SAndrew Duggan 
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;
79562b42d3SAndrew Duggan };
80562b42d3SAndrew Duggan 
81562b42d3SAndrew Duggan static int rmi_f30_read_control_parameters(struct rmi_function *fn,
82562b42d3SAndrew Duggan 						struct f30_data *f30)
83562b42d3SAndrew Duggan {
84562b42d3SAndrew Duggan 	struct rmi_device *rmi_dev = fn->rmi_dev;
85562b42d3SAndrew Duggan 	int error = 0;
86562b42d3SAndrew Duggan 
87562b42d3SAndrew Duggan 	error = rmi_read_block(rmi_dev, fn->fd.control_base_addr,
88562b42d3SAndrew Duggan 				f30->ctrl_regs, f30->ctrl_regs_size);
89562b42d3SAndrew Duggan 	if (error) {
90562b42d3SAndrew Duggan 		dev_err(&rmi_dev->dev, "%s : Could not read control registers at 0x%x error (%d)\n",
91562b42d3SAndrew Duggan 			__func__, fn->fd.control_base_addr, error);
92562b42d3SAndrew Duggan 		return error;
93562b42d3SAndrew Duggan 	}
94562b42d3SAndrew Duggan 
95562b42d3SAndrew Duggan 	return 0;
96562b42d3SAndrew Duggan }
97562b42d3SAndrew Duggan 
98562b42d3SAndrew Duggan static int rmi_f30_attention(struct rmi_function *fn, unsigned long *irq_bits)
99562b42d3SAndrew Duggan {
100562b42d3SAndrew Duggan 	struct f30_data *f30 = dev_get_drvdata(&fn->dev);
101562b42d3SAndrew Duggan 	struct rmi_device *rmi_dev = fn->rmi_dev;
102ae9979c3SBenjamin Tissoires 	struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev);
103562b42d3SAndrew Duggan 	int retval;
104562b42d3SAndrew Duggan 	int gpiled = 0;
105562b42d3SAndrew Duggan 	int value = 0;
106562b42d3SAndrew Duggan 	int i;
107562b42d3SAndrew Duggan 	int reg_num;
108562b42d3SAndrew Duggan 
109562b42d3SAndrew Duggan 	if (!f30->input)
110562b42d3SAndrew Duggan 		return 0;
111562b42d3SAndrew Duggan 
112562b42d3SAndrew Duggan 	/* Read the gpi led data. */
113ae9979c3SBenjamin Tissoires 	if (drvdata->attn_data.data) {
114ae9979c3SBenjamin Tissoires 		if (drvdata->attn_data.size < f30->register_count) {
1156d0dbeaeSAndrew Duggan 			dev_warn(&fn->dev, "F30 interrupted, but data is missing\n");
1166d0dbeaeSAndrew Duggan 			return 0;
1176d0dbeaeSAndrew Duggan 		}
118ae9979c3SBenjamin Tissoires 		memcpy(f30->data_regs, drvdata->attn_data.data,
119562b42d3SAndrew Duggan 			f30->register_count);
120ae9979c3SBenjamin Tissoires 		drvdata->attn_data.data += f30->register_count;
121ae9979c3SBenjamin Tissoires 		drvdata->attn_data.size -= f30->register_count;
122562b42d3SAndrew Duggan 	} else {
123562b42d3SAndrew Duggan 		retval = rmi_read_block(rmi_dev, fn->fd.data_base_addr,
124562b42d3SAndrew Duggan 			f30->data_regs, f30->register_count);
125562b42d3SAndrew Duggan 
126562b42d3SAndrew Duggan 		if (retval) {
127562b42d3SAndrew Duggan 			dev_err(&fn->dev, "%s: Failed to read F30 data registers.\n",
128562b42d3SAndrew Duggan 				__func__);
129562b42d3SAndrew Duggan 			return retval;
130562b42d3SAndrew Duggan 		}
131562b42d3SAndrew Duggan 	}
132562b42d3SAndrew Duggan 
133562b42d3SAndrew Duggan 	for (reg_num = 0; reg_num < f30->register_count; ++reg_num) {
134562b42d3SAndrew Duggan 		for (i = 0; gpiled < f30->gpioled_count && i < 8; ++i,
135562b42d3SAndrew Duggan 			++gpiled) {
136562b42d3SAndrew Duggan 			if (f30->gpioled_key_map[gpiled] != 0) {
137562b42d3SAndrew Duggan 				/* buttons have pull up resistors */
138562b42d3SAndrew Duggan 				value = (((f30->data_regs[reg_num] >> i) & 0x01)
139562b42d3SAndrew Duggan 									== 0);
140562b42d3SAndrew Duggan 
141562b42d3SAndrew Duggan 				rmi_dbg(RMI_DEBUG_FN, &fn->dev,
142562b42d3SAndrew Duggan 					"%s: call input report key (0x%04x) value (0x%02x)",
143562b42d3SAndrew Duggan 					__func__,
144562b42d3SAndrew Duggan 					f30->gpioled_key_map[gpiled], value);
145562b42d3SAndrew Duggan 				input_report_key(f30->input,
146562b42d3SAndrew Duggan 						 f30->gpioled_key_map[gpiled],
147562b42d3SAndrew Duggan 						 value);
148562b42d3SAndrew Duggan 			}
149562b42d3SAndrew Duggan 
150562b42d3SAndrew Duggan 		}
151562b42d3SAndrew Duggan 	}
152562b42d3SAndrew Duggan 
153562b42d3SAndrew Duggan 	return 0;
154562b42d3SAndrew Duggan }
155562b42d3SAndrew Duggan 
156562b42d3SAndrew Duggan static int rmi_f30_register_device(struct rmi_function *fn)
157562b42d3SAndrew Duggan {
158562b42d3SAndrew Duggan 	int i;
159562b42d3SAndrew Duggan 	struct rmi_device *rmi_dev = fn->rmi_dev;
160562b42d3SAndrew Duggan 	struct rmi_driver_data *drv_data = dev_get_drvdata(&rmi_dev->dev);
161562b42d3SAndrew Duggan 	struct f30_data *f30 = dev_get_drvdata(&fn->dev);
162562b42d3SAndrew Duggan 	struct input_dev *input_dev;
163562b42d3SAndrew Duggan 	int button_count = 0;
164562b42d3SAndrew Duggan 
165562b42d3SAndrew Duggan 	input_dev = drv_data->input;
166562b42d3SAndrew Duggan 	if (!input_dev) {
167562b42d3SAndrew Duggan 		dev_info(&fn->dev, "F30: no input device found, ignoring.\n");
168562b42d3SAndrew Duggan 		return -EINVAL;
169562b42d3SAndrew Duggan 	}
170562b42d3SAndrew Duggan 
171562b42d3SAndrew Duggan 	f30->input = input_dev;
172562b42d3SAndrew Duggan 
173562b42d3SAndrew Duggan 	set_bit(EV_KEY, input_dev->evbit);
174562b42d3SAndrew Duggan 
175562b42d3SAndrew Duggan 	input_dev->keycode = f30->gpioled_key_map;
176562b42d3SAndrew Duggan 	input_dev->keycodesize = sizeof(u16);
177562b42d3SAndrew Duggan 	input_dev->keycodemax = f30->gpioled_count;
178562b42d3SAndrew Duggan 
179562b42d3SAndrew Duggan 	for (i = 0; i < f30->gpioled_count; i++) {
180562b42d3SAndrew Duggan 		if (f30->gpioled_key_map[i] != 0) {
181562b42d3SAndrew Duggan 			input_set_capability(input_dev, EV_KEY,
182562b42d3SAndrew Duggan 						f30->gpioled_key_map[i]);
183562b42d3SAndrew Duggan 			button_count++;
184562b42d3SAndrew Duggan 		}
185562b42d3SAndrew Duggan 	}
186562b42d3SAndrew Duggan 
187562b42d3SAndrew Duggan 	if (button_count == 1)
188562b42d3SAndrew Duggan 		__set_bit(INPUT_PROP_BUTTONPAD, input_dev->propbit);
189562b42d3SAndrew Duggan 	return 0;
190562b42d3SAndrew Duggan }
191562b42d3SAndrew Duggan 
192562b42d3SAndrew Duggan static int rmi_f30_config(struct rmi_function *fn)
193562b42d3SAndrew Duggan {
194562b42d3SAndrew Duggan 	struct f30_data *f30 = dev_get_drvdata(&fn->dev);
195562b42d3SAndrew Duggan 	struct rmi_driver *drv = fn->rmi_dev->driver;
196562b42d3SAndrew Duggan 	const struct rmi_device_platform_data *pdata =
197562b42d3SAndrew Duggan 				rmi_get_platform_data(fn->rmi_dev);
198562b42d3SAndrew Duggan 	int error;
199562b42d3SAndrew Duggan 
2000a135b88SBenjamin Tissoires 	if (pdata->f30_data.disable) {
201562b42d3SAndrew Duggan 		drv->clear_irq_bits(fn->rmi_dev, fn->irq_mask);
202562b42d3SAndrew Duggan 	} else {
203562b42d3SAndrew Duggan 		/* Write Control Register values back to device */
204562b42d3SAndrew Duggan 		error = rmi_write_block(fn->rmi_dev, fn->fd.control_base_addr,
205562b42d3SAndrew Duggan 					f30->ctrl_regs, f30->ctrl_regs_size);
206562b42d3SAndrew Duggan 		if (error) {
207562b42d3SAndrew Duggan 			dev_err(&fn->rmi_dev->dev,
208562b42d3SAndrew Duggan 				"%s : Could not write control registers at 0x%x error (%d)\n",
209562b42d3SAndrew Duggan 				__func__, fn->fd.control_base_addr, error);
210562b42d3SAndrew Duggan 			return error;
211562b42d3SAndrew Duggan 		}
212562b42d3SAndrew Duggan 
213562b42d3SAndrew Duggan 		drv->set_irq_bits(fn->rmi_dev, fn->irq_mask);
214562b42d3SAndrew Duggan 	}
215562b42d3SAndrew Duggan 	return 0;
216562b42d3SAndrew Duggan }
217562b42d3SAndrew Duggan 
218562b42d3SAndrew Duggan static inline void rmi_f30_set_ctrl_data(struct rmi_f30_ctrl_data *ctrl,
219562b42d3SAndrew Duggan 					int *ctrl_addr, int len, u8 **reg)
220562b42d3SAndrew Duggan {
221562b42d3SAndrew Duggan 	ctrl->address = *ctrl_addr;
222562b42d3SAndrew Duggan 	ctrl->length = len;
223562b42d3SAndrew Duggan 	ctrl->regs = *reg;
224562b42d3SAndrew Duggan 	*ctrl_addr += len;
225562b42d3SAndrew Duggan 	*reg += len;
226562b42d3SAndrew Duggan }
227562b42d3SAndrew Duggan 
228562b42d3SAndrew Duggan static inline bool rmi_f30_is_valid_button(int button,
229562b42d3SAndrew Duggan 		struct rmi_f30_ctrl_data *ctrl)
230562b42d3SAndrew Duggan {
231562b42d3SAndrew Duggan 	int byte_position = button >> 3;
232562b42d3SAndrew Duggan 	int bit_position = button & 0x07;
233562b42d3SAndrew Duggan 
234562b42d3SAndrew Duggan 	/*
235562b42d3SAndrew Duggan 	 * ctrl2 -> dir == 0 -> input mode
236562b42d3SAndrew Duggan 	 * ctrl3 -> data == 1 -> actual button
237562b42d3SAndrew Duggan 	 */
238562b42d3SAndrew Duggan 	return !(ctrl[2].regs[byte_position] & BIT(bit_position)) &&
239562b42d3SAndrew Duggan 		(ctrl[3].regs[byte_position] & BIT(bit_position));
240562b42d3SAndrew Duggan }
241562b42d3SAndrew Duggan 
242562b42d3SAndrew Duggan static inline int rmi_f30_initialize(struct rmi_function *fn)
243562b42d3SAndrew Duggan {
244562b42d3SAndrew Duggan 	struct f30_data *f30;
245562b42d3SAndrew Duggan 	struct rmi_device *rmi_dev = fn->rmi_dev;
246562b42d3SAndrew Duggan 	const struct rmi_device_platform_data *pdata;
247562b42d3SAndrew Duggan 	int retval = 0;
248562b42d3SAndrew Duggan 	int control_address;
249562b42d3SAndrew Duggan 	int i;
250562b42d3SAndrew Duggan 	int button;
251562b42d3SAndrew Duggan 	u8 buf[RMI_F30_QUERY_SIZE];
252562b42d3SAndrew Duggan 	u8 *ctrl_reg;
253562b42d3SAndrew Duggan 	u8 *map_memory;
254562b42d3SAndrew Duggan 
255562b42d3SAndrew Duggan 	f30 = devm_kzalloc(&fn->dev, sizeof(struct f30_data),
256562b42d3SAndrew Duggan 			   GFP_KERNEL);
257562b42d3SAndrew Duggan 	if (!f30)
258562b42d3SAndrew Duggan 		return -ENOMEM;
259562b42d3SAndrew Duggan 
260562b42d3SAndrew Duggan 	dev_set_drvdata(&fn->dev, f30);
261562b42d3SAndrew Duggan 
262562b42d3SAndrew Duggan 	retval = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr, buf,
263562b42d3SAndrew Duggan 				RMI_F30_QUERY_SIZE);
264562b42d3SAndrew Duggan 
265562b42d3SAndrew Duggan 	if (retval) {
266562b42d3SAndrew Duggan 		dev_err(&fn->dev, "Failed to read query register.\n");
267562b42d3SAndrew Duggan 		return retval;
268562b42d3SAndrew Duggan 	}
269562b42d3SAndrew Duggan 
270562b42d3SAndrew Duggan 	f30->has_extended_pattern = buf[0] & RMI_F30_EXTENDED_PATTERNS;
271562b42d3SAndrew Duggan 	f30->has_mappable_buttons = buf[0] & RMI_F30_HAS_MAPPABLE_BUTTONS;
272562b42d3SAndrew Duggan 	f30->has_led = buf[0] & RMI_F30_HAS_LED;
273562b42d3SAndrew Duggan 	f30->has_gpio = buf[0] & RMI_F30_HAS_GPIO;
274562b42d3SAndrew Duggan 	f30->has_haptic = buf[0] & RMI_F30_HAS_HAPTIC;
275562b42d3SAndrew Duggan 	f30->has_gpio_driver_control = buf[0] & RMI_F30_HAS_GPIO_DRV_CTL;
276562b42d3SAndrew Duggan 	f30->has_mech_mouse_btns = buf[0] & RMI_F30_HAS_MECH_MOUSE_BTNS;
277562b42d3SAndrew Duggan 	f30->gpioled_count = buf[1] & RMI_F30_GPIO_LED_COUNT;
278562b42d3SAndrew Duggan 
279562b42d3SAndrew Duggan 	f30->register_count = (f30->gpioled_count + 7) >> 3;
280562b42d3SAndrew Duggan 
281562b42d3SAndrew Duggan 	control_address = fn->fd.control_base_addr;
282562b42d3SAndrew Duggan 	ctrl_reg = f30->ctrl_regs;
283562b42d3SAndrew Duggan 
284562b42d3SAndrew Duggan 	if (f30->has_gpio && f30->has_led)
285562b42d3SAndrew Duggan 		rmi_f30_set_ctrl_data(&f30->ctrl[0], &control_address,
286562b42d3SAndrew Duggan 					f30->register_count, &ctrl_reg);
287562b42d3SAndrew Duggan 
288562b42d3SAndrew Duggan 	rmi_f30_set_ctrl_data(&f30->ctrl[1], &control_address, sizeof(u8),
289562b42d3SAndrew Duggan 				&ctrl_reg);
290562b42d3SAndrew Duggan 
291562b42d3SAndrew Duggan 	if (f30->has_gpio) {
292562b42d3SAndrew Duggan 		rmi_f30_set_ctrl_data(&f30->ctrl[2], &control_address,
293562b42d3SAndrew Duggan 					f30->register_count, &ctrl_reg);
294562b42d3SAndrew Duggan 
295562b42d3SAndrew Duggan 		rmi_f30_set_ctrl_data(&f30->ctrl[3], &control_address,
296562b42d3SAndrew Duggan 					f30->register_count, &ctrl_reg);
297562b42d3SAndrew Duggan 	}
298562b42d3SAndrew Duggan 
299562b42d3SAndrew Duggan 	if (f30->has_led) {
300562b42d3SAndrew Duggan 		int ctrl5_len;
301562b42d3SAndrew Duggan 
302562b42d3SAndrew Duggan 		rmi_f30_set_ctrl_data(&f30->ctrl[4], &control_address,
303562b42d3SAndrew Duggan 					f30->register_count, &ctrl_reg);
304562b42d3SAndrew Duggan 
305562b42d3SAndrew Duggan 		if (f30->has_extended_pattern)
306562b42d3SAndrew Duggan 			ctrl5_len = 6;
307562b42d3SAndrew Duggan 		else
308562b42d3SAndrew Duggan 			ctrl5_len = 2;
309562b42d3SAndrew Duggan 
310562b42d3SAndrew Duggan 		rmi_f30_set_ctrl_data(&f30->ctrl[5], &control_address,
311562b42d3SAndrew Duggan 					ctrl5_len, &ctrl_reg);
312562b42d3SAndrew Duggan 	}
313562b42d3SAndrew Duggan 
314562b42d3SAndrew Duggan 	if (f30->has_led || f30->has_gpio_driver_control) {
315562b42d3SAndrew Duggan 		/* control 6 uses a byte per gpio/led */
316562b42d3SAndrew Duggan 		rmi_f30_set_ctrl_data(&f30->ctrl[6], &control_address,
317562b42d3SAndrew Duggan 					f30->gpioled_count, &ctrl_reg);
318562b42d3SAndrew Duggan 	}
319562b42d3SAndrew Duggan 
320562b42d3SAndrew Duggan 	if (f30->has_mappable_buttons) {
321562b42d3SAndrew Duggan 		/* control 7 uses a byte per gpio/led */
322562b42d3SAndrew Duggan 		rmi_f30_set_ctrl_data(&f30->ctrl[7], &control_address,
323562b42d3SAndrew Duggan 					f30->gpioled_count, &ctrl_reg);
324562b42d3SAndrew Duggan 	}
325562b42d3SAndrew Duggan 
326562b42d3SAndrew Duggan 	if (f30->has_haptic) {
327562b42d3SAndrew Duggan 		rmi_f30_set_ctrl_data(&f30->ctrl[8], &control_address,
328562b42d3SAndrew Duggan 					f30->register_count, &ctrl_reg);
329562b42d3SAndrew Duggan 
330562b42d3SAndrew Duggan 		rmi_f30_set_ctrl_data(&f30->ctrl[9], &control_address,
331562b42d3SAndrew Duggan 					sizeof(u8), &ctrl_reg);
332562b42d3SAndrew Duggan 	}
333562b42d3SAndrew Duggan 
334562b42d3SAndrew Duggan 	if (f30->has_mech_mouse_btns)
335562b42d3SAndrew Duggan 		rmi_f30_set_ctrl_data(&f30->ctrl[10], &control_address,
336562b42d3SAndrew Duggan 					sizeof(u8), &ctrl_reg);
337562b42d3SAndrew Duggan 
338562b42d3SAndrew Duggan 	f30->ctrl_regs_size = ctrl_reg - f30->ctrl_regs
339562b42d3SAndrew Duggan 				?: RMI_F30_CTRL_REGS_MAX_SIZE;
340562b42d3SAndrew Duggan 
341562b42d3SAndrew Duggan 	retval = rmi_f30_read_control_parameters(fn, f30);
342562b42d3SAndrew Duggan 	if (retval < 0) {
343562b42d3SAndrew Duggan 		dev_err(&fn->dev,
344562b42d3SAndrew Duggan 			"Failed to initialize F19 control params.\n");
345562b42d3SAndrew Duggan 		return retval;
346562b42d3SAndrew Duggan 	}
347562b42d3SAndrew Duggan 
348562b42d3SAndrew Duggan 	map_memory = devm_kzalloc(&fn->dev,
349562b42d3SAndrew Duggan 				  (f30->gpioled_count * (sizeof(u16))),
350562b42d3SAndrew Duggan 				  GFP_KERNEL);
351562b42d3SAndrew Duggan 	if (!map_memory) {
352562b42d3SAndrew Duggan 		dev_err(&fn->dev, "Failed to allocate gpioled map memory.\n");
353562b42d3SAndrew Duggan 		return -ENOMEM;
354562b42d3SAndrew Duggan 	}
355562b42d3SAndrew Duggan 
356562b42d3SAndrew Duggan 	f30->gpioled_key_map = (u16 *)map_memory;
357562b42d3SAndrew Duggan 
358562b42d3SAndrew Duggan 	pdata = rmi_get_platform_data(rmi_dev);
3590a135b88SBenjamin Tissoires 	if (f30->has_gpio) {
360562b42d3SAndrew Duggan 		button = BTN_LEFT;
361562b42d3SAndrew Duggan 		for (i = 0; i < f30->gpioled_count; i++) {
362562b42d3SAndrew Duggan 			if (rmi_f30_is_valid_button(i, f30->ctrl)) {
363562b42d3SAndrew Duggan 				f30->gpioled_key_map[i] = button++;
364562b42d3SAndrew Duggan 
365562b42d3SAndrew Duggan 				/*
366562b42d3SAndrew Duggan 				 * buttonpad might be given by
367562b42d3SAndrew Duggan 				 * f30->has_mech_mouse_btns, but I am
368562b42d3SAndrew Duggan 				 * not sure, so use only the pdata info
369562b42d3SAndrew Duggan 				 */
3700a135b88SBenjamin Tissoires 				if (pdata->f30_data.buttonpad)
371562b42d3SAndrew Duggan 					break;
372562b42d3SAndrew Duggan 			}
373562b42d3SAndrew Duggan 		}
374562b42d3SAndrew Duggan 	}
375562b42d3SAndrew Duggan 
376562b42d3SAndrew Duggan 	return 0;
377562b42d3SAndrew Duggan }
378562b42d3SAndrew Duggan 
379562b42d3SAndrew Duggan static int rmi_f30_probe(struct rmi_function *fn)
380562b42d3SAndrew Duggan {
381562b42d3SAndrew Duggan 	int rc;
382562b42d3SAndrew Duggan 	const struct rmi_device_platform_data *pdata =
383562b42d3SAndrew Duggan 				rmi_get_platform_data(fn->rmi_dev);
384562b42d3SAndrew Duggan 
3850a135b88SBenjamin Tissoires 	if (pdata->f30_data.disable)
386562b42d3SAndrew Duggan 		return 0;
387562b42d3SAndrew Duggan 
388562b42d3SAndrew Duggan 	rc = rmi_f30_initialize(fn);
389562b42d3SAndrew Duggan 	if (rc < 0)
390562b42d3SAndrew Duggan 		goto error_exit;
391562b42d3SAndrew Duggan 
392562b42d3SAndrew Duggan 	rc = rmi_f30_register_device(fn);
393562b42d3SAndrew Duggan 	if (rc < 0)
394562b42d3SAndrew Duggan 		goto error_exit;
395562b42d3SAndrew Duggan 
396562b42d3SAndrew Duggan 	return 0;
397562b42d3SAndrew Duggan 
398562b42d3SAndrew Duggan error_exit:
399562b42d3SAndrew Duggan 	return rc;
400562b42d3SAndrew Duggan 
401562b42d3SAndrew Duggan }
402562b42d3SAndrew Duggan 
403562b42d3SAndrew Duggan struct rmi_function_handler rmi_f30_handler = {
404562b42d3SAndrew Duggan 	.driver = {
405562b42d3SAndrew Duggan 		.name = "rmi4_f30",
406562b42d3SAndrew Duggan 	},
407562b42d3SAndrew Duggan 	.func = 0x30,
408562b42d3SAndrew Duggan 	.probe = rmi_f30_probe,
409562b42d3SAndrew Duggan 	.config = rmi_f30_config,
410562b42d3SAndrew Duggan 	.attention = rmi_f30_attention,
411562b42d3SAndrew Duggan };
412