xref: /openbmc/linux/drivers/input/rmi4/rmi_f30.c (revision 261bfb33)
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 
171261bfb33SVincent Huang 	/* can happen if gpio_data.disable is set */
172b6573da1SBenjamin Tissoires 	if (!f30)
173b6573da1SBenjamin Tissoires 		return 0;
174b6573da1SBenjamin Tissoires 
175261bfb33SVincent 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 
181261bfb33SVincent 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 
248261bfb33SVincent 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++;
251261bfb33SVincent 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 	 */
267261bfb33SVincent 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 
375261bfb33SVincent 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