18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (c) 2012-2016 Synaptics Incorporated
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/kernel.h>
78c2ecf20Sopenharmony_ci#include <linux/rmi.h>
88c2ecf20Sopenharmony_ci#include <linux/input.h>
98c2ecf20Sopenharmony_ci#include <linux/slab.h>
108c2ecf20Sopenharmony_ci#include "rmi_driver.h"
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#define RMI_F30_QUERY_SIZE			2
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci/* Defs for Query 0 */
158c2ecf20Sopenharmony_ci#define RMI_F30_EXTENDED_PATTERNS		0x01
168c2ecf20Sopenharmony_ci#define RMI_F30_HAS_MAPPABLE_BUTTONS		BIT(1)
178c2ecf20Sopenharmony_ci#define RMI_F30_HAS_LED				BIT(2)
188c2ecf20Sopenharmony_ci#define RMI_F30_HAS_GPIO			BIT(3)
198c2ecf20Sopenharmony_ci#define RMI_F30_HAS_HAPTIC			BIT(4)
208c2ecf20Sopenharmony_ci#define RMI_F30_HAS_GPIO_DRV_CTL		BIT(5)
218c2ecf20Sopenharmony_ci#define RMI_F30_HAS_MECH_MOUSE_BTNS		BIT(6)
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci/* Defs for Query 1 */
248c2ecf20Sopenharmony_ci#define RMI_F30_GPIO_LED_COUNT			0x1F
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci/* Defs for Control Registers */
278c2ecf20Sopenharmony_ci#define RMI_F30_CTRL_1_GPIO_DEBOUNCE		0x01
288c2ecf20Sopenharmony_ci#define RMI_F30_CTRL_1_HALT			BIT(4)
298c2ecf20Sopenharmony_ci#define RMI_F30_CTRL_1_HALTED			BIT(5)
308c2ecf20Sopenharmony_ci#define RMI_F30_CTRL_10_NUM_MECH_MOUSE_BTNS	0x03
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#define RMI_F30_CTRL_MAX_REGS		32
338c2ecf20Sopenharmony_ci#define RMI_F30_CTRL_MAX_BYTES		DIV_ROUND_UP(RMI_F30_CTRL_MAX_REGS, 8)
348c2ecf20Sopenharmony_ci#define RMI_F30_CTRL_MAX_REG_BLOCKS	11
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci#define RMI_F30_CTRL_REGS_MAX_SIZE (RMI_F30_CTRL_MAX_BYTES		\
378c2ecf20Sopenharmony_ci					+ 1				\
388c2ecf20Sopenharmony_ci					+ RMI_F30_CTRL_MAX_BYTES	\
398c2ecf20Sopenharmony_ci					+ RMI_F30_CTRL_MAX_BYTES	\
408c2ecf20Sopenharmony_ci					+ RMI_F30_CTRL_MAX_BYTES	\
418c2ecf20Sopenharmony_ci					+ 6				\
428c2ecf20Sopenharmony_ci					+ RMI_F30_CTRL_MAX_REGS		\
438c2ecf20Sopenharmony_ci					+ RMI_F30_CTRL_MAX_REGS		\
448c2ecf20Sopenharmony_ci					+ RMI_F30_CTRL_MAX_BYTES	\
458c2ecf20Sopenharmony_ci					+ 1				\
468c2ecf20Sopenharmony_ci					+ 1)
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci#define TRACKSTICK_RANGE_START		3
498c2ecf20Sopenharmony_ci#define TRACKSTICK_RANGE_END		6
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_cistruct rmi_f30_ctrl_data {
528c2ecf20Sopenharmony_ci	int address;
538c2ecf20Sopenharmony_ci	int length;
548c2ecf20Sopenharmony_ci	u8 *regs;
558c2ecf20Sopenharmony_ci};
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cistruct f30_data {
588c2ecf20Sopenharmony_ci	/* Query Data */
598c2ecf20Sopenharmony_ci	bool has_extended_pattern;
608c2ecf20Sopenharmony_ci	bool has_mappable_buttons;
618c2ecf20Sopenharmony_ci	bool has_led;
628c2ecf20Sopenharmony_ci	bool has_gpio;
638c2ecf20Sopenharmony_ci	bool has_haptic;
648c2ecf20Sopenharmony_ci	bool has_gpio_driver_control;
658c2ecf20Sopenharmony_ci	bool has_mech_mouse_btns;
668c2ecf20Sopenharmony_ci	u8 gpioled_count;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	u8 register_count;
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	/* Control Register Data */
718c2ecf20Sopenharmony_ci	struct rmi_f30_ctrl_data ctrl[RMI_F30_CTRL_MAX_REG_BLOCKS];
728c2ecf20Sopenharmony_ci	u8 ctrl_regs[RMI_F30_CTRL_REGS_MAX_SIZE];
738c2ecf20Sopenharmony_ci	u32 ctrl_regs_size;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	u8 data_regs[RMI_F30_CTRL_MAX_BYTES];
768c2ecf20Sopenharmony_ci	u16 *gpioled_key_map;
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	struct input_dev *input;
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	struct rmi_function *f03;
818c2ecf20Sopenharmony_ci	bool trackstick_buttons;
828c2ecf20Sopenharmony_ci};
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_cistatic int rmi_f30_read_control_parameters(struct rmi_function *fn,
858c2ecf20Sopenharmony_ci						struct f30_data *f30)
868c2ecf20Sopenharmony_ci{
878c2ecf20Sopenharmony_ci	int error;
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	error = rmi_read_block(fn->rmi_dev, fn->fd.control_base_addr,
908c2ecf20Sopenharmony_ci			       f30->ctrl_regs, f30->ctrl_regs_size);
918c2ecf20Sopenharmony_ci	if (error) {
928c2ecf20Sopenharmony_ci		dev_err(&fn->dev,
938c2ecf20Sopenharmony_ci			"%s: Could not read control registers at 0x%x: %d\n",
948c2ecf20Sopenharmony_ci			__func__, fn->fd.control_base_addr, error);
958c2ecf20Sopenharmony_ci		return error;
968c2ecf20Sopenharmony_ci	}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	return 0;
998c2ecf20Sopenharmony_ci}
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_cistatic void rmi_f30_report_button(struct rmi_function *fn,
1028c2ecf20Sopenharmony_ci				  struct f30_data *f30, unsigned int button)
1038c2ecf20Sopenharmony_ci{
1048c2ecf20Sopenharmony_ci	unsigned int reg_num = button >> 3;
1058c2ecf20Sopenharmony_ci	unsigned int bit_num = button & 0x07;
1068c2ecf20Sopenharmony_ci	u16 key_code = f30->gpioled_key_map[button];
1078c2ecf20Sopenharmony_ci	bool key_down = !(f30->data_regs[reg_num] & BIT(bit_num));
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	if (f30->trackstick_buttons &&
1108c2ecf20Sopenharmony_ci	    button >= TRACKSTICK_RANGE_START &&
1118c2ecf20Sopenharmony_ci	    button <= TRACKSTICK_RANGE_END) {
1128c2ecf20Sopenharmony_ci		rmi_f03_overwrite_button(f30->f03, key_code, key_down);
1138c2ecf20Sopenharmony_ci	} else {
1148c2ecf20Sopenharmony_ci		rmi_dbg(RMI_DEBUG_FN, &fn->dev,
1158c2ecf20Sopenharmony_ci			"%s: call input report key (0x%04x) value (0x%02x)",
1168c2ecf20Sopenharmony_ci			__func__, key_code, key_down);
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci		input_report_key(f30->input, key_code, key_down);
1198c2ecf20Sopenharmony_ci	}
1208c2ecf20Sopenharmony_ci}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_cistatic irqreturn_t rmi_f30_attention(int irq, void *ctx)
1238c2ecf20Sopenharmony_ci{
1248c2ecf20Sopenharmony_ci	struct rmi_function *fn = ctx;
1258c2ecf20Sopenharmony_ci	struct f30_data *f30 = dev_get_drvdata(&fn->dev);
1268c2ecf20Sopenharmony_ci	struct rmi_driver_data *drvdata = dev_get_drvdata(&fn->rmi_dev->dev);
1278c2ecf20Sopenharmony_ci	int error;
1288c2ecf20Sopenharmony_ci	int i;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	/* Read the gpi led data. */
1318c2ecf20Sopenharmony_ci	if (drvdata->attn_data.data) {
1328c2ecf20Sopenharmony_ci		if (drvdata->attn_data.size < f30->register_count) {
1338c2ecf20Sopenharmony_ci			dev_warn(&fn->dev,
1348c2ecf20Sopenharmony_ci				 "F30 interrupted, but data is missing\n");
1358c2ecf20Sopenharmony_ci			return IRQ_HANDLED;
1368c2ecf20Sopenharmony_ci		}
1378c2ecf20Sopenharmony_ci		memcpy(f30->data_regs, drvdata->attn_data.data,
1388c2ecf20Sopenharmony_ci			f30->register_count);
1398c2ecf20Sopenharmony_ci		drvdata->attn_data.data += f30->register_count;
1408c2ecf20Sopenharmony_ci		drvdata->attn_data.size -= f30->register_count;
1418c2ecf20Sopenharmony_ci	} else {
1428c2ecf20Sopenharmony_ci		error = rmi_read_block(fn->rmi_dev, fn->fd.data_base_addr,
1438c2ecf20Sopenharmony_ci				       f30->data_regs, f30->register_count);
1448c2ecf20Sopenharmony_ci		if (error) {
1458c2ecf20Sopenharmony_ci			dev_err(&fn->dev,
1468c2ecf20Sopenharmony_ci				"%s: Failed to read F30 data registers: %d\n",
1478c2ecf20Sopenharmony_ci				__func__, error);
1488c2ecf20Sopenharmony_ci			return IRQ_RETVAL(error);
1498c2ecf20Sopenharmony_ci		}
1508c2ecf20Sopenharmony_ci	}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	if (f30->has_gpio) {
1538c2ecf20Sopenharmony_ci		for (i = 0; i < f30->gpioled_count; i++)
1548c2ecf20Sopenharmony_ci			if (f30->gpioled_key_map[i] != KEY_RESERVED)
1558c2ecf20Sopenharmony_ci				rmi_f30_report_button(fn, f30, i);
1568c2ecf20Sopenharmony_ci		if (f30->trackstick_buttons)
1578c2ecf20Sopenharmony_ci			rmi_f03_commit_buttons(f30->f03);
1588c2ecf20Sopenharmony_ci	}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
1618c2ecf20Sopenharmony_ci}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_cistatic int rmi_f30_config(struct rmi_function *fn)
1648c2ecf20Sopenharmony_ci{
1658c2ecf20Sopenharmony_ci	struct f30_data *f30 = dev_get_drvdata(&fn->dev);
1668c2ecf20Sopenharmony_ci	struct rmi_driver *drv = fn->rmi_dev->driver;
1678c2ecf20Sopenharmony_ci	const struct rmi_device_platform_data *pdata =
1688c2ecf20Sopenharmony_ci				rmi_get_platform_data(fn->rmi_dev);
1698c2ecf20Sopenharmony_ci	int error;
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	/* can happen if gpio_data.disable is set */
1728c2ecf20Sopenharmony_ci	if (!f30)
1738c2ecf20Sopenharmony_ci		return 0;
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	if (pdata->gpio_data.trackstick_buttons) {
1768c2ecf20Sopenharmony_ci		/* Try [re-]establish link to F03. */
1778c2ecf20Sopenharmony_ci		f30->f03 = rmi_find_function(fn->rmi_dev, 0x03);
1788c2ecf20Sopenharmony_ci		f30->trackstick_buttons = f30->f03 != NULL;
1798c2ecf20Sopenharmony_ci	}
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	if (pdata->gpio_data.disable) {
1828c2ecf20Sopenharmony_ci		drv->clear_irq_bits(fn->rmi_dev, fn->irq_mask);
1838c2ecf20Sopenharmony_ci	} else {
1848c2ecf20Sopenharmony_ci		/* Write Control Register values back to device */
1858c2ecf20Sopenharmony_ci		error = rmi_write_block(fn->rmi_dev, fn->fd.control_base_addr,
1868c2ecf20Sopenharmony_ci					f30->ctrl_regs, f30->ctrl_regs_size);
1878c2ecf20Sopenharmony_ci		if (error) {
1888c2ecf20Sopenharmony_ci			dev_err(&fn->dev,
1898c2ecf20Sopenharmony_ci				"%s: Could not write control registers at 0x%x: %d\n",
1908c2ecf20Sopenharmony_ci				__func__, fn->fd.control_base_addr, error);
1918c2ecf20Sopenharmony_ci			return error;
1928c2ecf20Sopenharmony_ci		}
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci		drv->set_irq_bits(fn->rmi_dev, fn->irq_mask);
1958c2ecf20Sopenharmony_ci	}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	return 0;
1988c2ecf20Sopenharmony_ci}
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_cistatic void rmi_f30_set_ctrl_data(struct rmi_f30_ctrl_data *ctrl,
2018c2ecf20Sopenharmony_ci				  int *ctrl_addr, int len, u8 **reg)
2028c2ecf20Sopenharmony_ci{
2038c2ecf20Sopenharmony_ci	ctrl->address = *ctrl_addr;
2048c2ecf20Sopenharmony_ci	ctrl->length = len;
2058c2ecf20Sopenharmony_ci	ctrl->regs = *reg;
2068c2ecf20Sopenharmony_ci	*ctrl_addr += len;
2078c2ecf20Sopenharmony_ci	*reg += len;
2088c2ecf20Sopenharmony_ci}
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_cistatic bool rmi_f30_is_valid_button(int button, struct rmi_f30_ctrl_data *ctrl)
2118c2ecf20Sopenharmony_ci{
2128c2ecf20Sopenharmony_ci	int byte_position = button >> 3;
2138c2ecf20Sopenharmony_ci	int bit_position = button & 0x07;
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	/*
2168c2ecf20Sopenharmony_ci	 * ctrl2 -> dir == 0 -> input mode
2178c2ecf20Sopenharmony_ci	 * ctrl3 -> data == 1 -> actual button
2188c2ecf20Sopenharmony_ci	 */
2198c2ecf20Sopenharmony_ci	return !(ctrl[2].regs[byte_position] & BIT(bit_position)) &&
2208c2ecf20Sopenharmony_ci		(ctrl[3].regs[byte_position] & BIT(bit_position));
2218c2ecf20Sopenharmony_ci}
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_cistatic int rmi_f30_map_gpios(struct rmi_function *fn,
2248c2ecf20Sopenharmony_ci			     struct f30_data *f30)
2258c2ecf20Sopenharmony_ci{
2268c2ecf20Sopenharmony_ci	const struct rmi_device_platform_data *pdata =
2278c2ecf20Sopenharmony_ci					rmi_get_platform_data(fn->rmi_dev);
2288c2ecf20Sopenharmony_ci	struct input_dev *input = f30->input;
2298c2ecf20Sopenharmony_ci	unsigned int button = BTN_LEFT;
2308c2ecf20Sopenharmony_ci	unsigned int trackstick_button = BTN_LEFT;
2318c2ecf20Sopenharmony_ci	bool button_mapped = false;
2328c2ecf20Sopenharmony_ci	int i;
2338c2ecf20Sopenharmony_ci	int button_count = min_t(u8, f30->gpioled_count, TRACKSTICK_RANGE_END);
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	f30->gpioled_key_map = devm_kcalloc(&fn->dev,
2368c2ecf20Sopenharmony_ci					    button_count,
2378c2ecf20Sopenharmony_ci					    sizeof(f30->gpioled_key_map[0]),
2388c2ecf20Sopenharmony_ci					    GFP_KERNEL);
2398c2ecf20Sopenharmony_ci	if (!f30->gpioled_key_map) {
2408c2ecf20Sopenharmony_ci		dev_err(&fn->dev, "Failed to allocate gpioled map memory.\n");
2418c2ecf20Sopenharmony_ci		return -ENOMEM;
2428c2ecf20Sopenharmony_ci	}
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	for (i = 0; i < button_count; i++) {
2458c2ecf20Sopenharmony_ci		if (!rmi_f30_is_valid_button(i, f30->ctrl))
2468c2ecf20Sopenharmony_ci			continue;
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci		if (pdata->gpio_data.trackstick_buttons &&
2498c2ecf20Sopenharmony_ci		    i >= TRACKSTICK_RANGE_START && i < TRACKSTICK_RANGE_END) {
2508c2ecf20Sopenharmony_ci			f30->gpioled_key_map[i] = trackstick_button++;
2518c2ecf20Sopenharmony_ci		} else if (!pdata->gpio_data.buttonpad || !button_mapped) {
2528c2ecf20Sopenharmony_ci			f30->gpioled_key_map[i] = button;
2538c2ecf20Sopenharmony_ci			input_set_capability(input, EV_KEY, button++);
2548c2ecf20Sopenharmony_ci			button_mapped = true;
2558c2ecf20Sopenharmony_ci		}
2568c2ecf20Sopenharmony_ci	}
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	input->keycode = f30->gpioled_key_map;
2598c2ecf20Sopenharmony_ci	input->keycodesize = sizeof(f30->gpioled_key_map[0]);
2608c2ecf20Sopenharmony_ci	input->keycodemax = f30->gpioled_count;
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	/*
2638c2ecf20Sopenharmony_ci	 * Buttonpad could be also inferred from f30->has_mech_mouse_btns,
2648c2ecf20Sopenharmony_ci	 * but I am not sure, so use only the pdata info and the number of
2658c2ecf20Sopenharmony_ci	 * mapped buttons.
2668c2ecf20Sopenharmony_ci	 */
2678c2ecf20Sopenharmony_ci	if (pdata->gpio_data.buttonpad || (button - BTN_LEFT == 1))
2688c2ecf20Sopenharmony_ci		__set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	return 0;
2718c2ecf20Sopenharmony_ci}
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_cistatic int rmi_f30_initialize(struct rmi_function *fn, struct f30_data *f30)
2748c2ecf20Sopenharmony_ci{
2758c2ecf20Sopenharmony_ci	u8 *ctrl_reg = f30->ctrl_regs;
2768c2ecf20Sopenharmony_ci	int control_address = fn->fd.control_base_addr;
2778c2ecf20Sopenharmony_ci	u8 buf[RMI_F30_QUERY_SIZE];
2788c2ecf20Sopenharmony_ci	int error;
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	error = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr,
2818c2ecf20Sopenharmony_ci			       buf, RMI_F30_QUERY_SIZE);
2828c2ecf20Sopenharmony_ci	if (error) {
2838c2ecf20Sopenharmony_ci		dev_err(&fn->dev, "Failed to read query register\n");
2848c2ecf20Sopenharmony_ci		return error;
2858c2ecf20Sopenharmony_ci	}
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	f30->has_extended_pattern = buf[0] & RMI_F30_EXTENDED_PATTERNS;
2888c2ecf20Sopenharmony_ci	f30->has_mappable_buttons = buf[0] & RMI_F30_HAS_MAPPABLE_BUTTONS;
2898c2ecf20Sopenharmony_ci	f30->has_led = buf[0] & RMI_F30_HAS_LED;
2908c2ecf20Sopenharmony_ci	f30->has_gpio = buf[0] & RMI_F30_HAS_GPIO;
2918c2ecf20Sopenharmony_ci	f30->has_haptic = buf[0] & RMI_F30_HAS_HAPTIC;
2928c2ecf20Sopenharmony_ci	f30->has_gpio_driver_control = buf[0] & RMI_F30_HAS_GPIO_DRV_CTL;
2938c2ecf20Sopenharmony_ci	f30->has_mech_mouse_btns = buf[0] & RMI_F30_HAS_MECH_MOUSE_BTNS;
2948c2ecf20Sopenharmony_ci	f30->gpioled_count = buf[1] & RMI_F30_GPIO_LED_COUNT;
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	f30->register_count = DIV_ROUND_UP(f30->gpioled_count, 8);
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	if (f30->has_gpio && f30->has_led)
2998c2ecf20Sopenharmony_ci		rmi_f30_set_ctrl_data(&f30->ctrl[0], &control_address,
3008c2ecf20Sopenharmony_ci				      f30->register_count, &ctrl_reg);
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	rmi_f30_set_ctrl_data(&f30->ctrl[1], &control_address,
3038c2ecf20Sopenharmony_ci			      sizeof(u8), &ctrl_reg);
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	if (f30->has_gpio) {
3068c2ecf20Sopenharmony_ci		rmi_f30_set_ctrl_data(&f30->ctrl[2], &control_address,
3078c2ecf20Sopenharmony_ci				      f30->register_count, &ctrl_reg);
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci		rmi_f30_set_ctrl_data(&f30->ctrl[3], &control_address,
3108c2ecf20Sopenharmony_ci				      f30->register_count, &ctrl_reg);
3118c2ecf20Sopenharmony_ci	}
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	if (f30->has_led) {
3148c2ecf20Sopenharmony_ci		rmi_f30_set_ctrl_data(&f30->ctrl[4], &control_address,
3158c2ecf20Sopenharmony_ci				      f30->register_count, &ctrl_reg);
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci		rmi_f30_set_ctrl_data(&f30->ctrl[5], &control_address,
3188c2ecf20Sopenharmony_ci				      f30->has_extended_pattern ? 6 : 2,
3198c2ecf20Sopenharmony_ci				      &ctrl_reg);
3208c2ecf20Sopenharmony_ci	}
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	if (f30->has_led || f30->has_gpio_driver_control) {
3238c2ecf20Sopenharmony_ci		/* control 6 uses a byte per gpio/led */
3248c2ecf20Sopenharmony_ci		rmi_f30_set_ctrl_data(&f30->ctrl[6], &control_address,
3258c2ecf20Sopenharmony_ci				      f30->gpioled_count, &ctrl_reg);
3268c2ecf20Sopenharmony_ci	}
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	if (f30->has_mappable_buttons) {
3298c2ecf20Sopenharmony_ci		/* control 7 uses a byte per gpio/led */
3308c2ecf20Sopenharmony_ci		rmi_f30_set_ctrl_data(&f30->ctrl[7], &control_address,
3318c2ecf20Sopenharmony_ci				      f30->gpioled_count, &ctrl_reg);
3328c2ecf20Sopenharmony_ci	}
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	if (f30->has_haptic) {
3358c2ecf20Sopenharmony_ci		rmi_f30_set_ctrl_data(&f30->ctrl[8], &control_address,
3368c2ecf20Sopenharmony_ci				      f30->register_count, &ctrl_reg);
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci		rmi_f30_set_ctrl_data(&f30->ctrl[9], &control_address,
3398c2ecf20Sopenharmony_ci				      sizeof(u8), &ctrl_reg);
3408c2ecf20Sopenharmony_ci	}
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	if (f30->has_mech_mouse_btns)
3438c2ecf20Sopenharmony_ci		rmi_f30_set_ctrl_data(&f30->ctrl[10], &control_address,
3448c2ecf20Sopenharmony_ci				      sizeof(u8), &ctrl_reg);
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	f30->ctrl_regs_size = ctrl_reg -
3478c2ecf20Sopenharmony_ci				f30->ctrl_regs ?: RMI_F30_CTRL_REGS_MAX_SIZE;
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	error = rmi_f30_read_control_parameters(fn, f30);
3508c2ecf20Sopenharmony_ci	if (error) {
3518c2ecf20Sopenharmony_ci		dev_err(&fn->dev,
3528c2ecf20Sopenharmony_ci			"Failed to initialize F30 control params: %d\n",
3538c2ecf20Sopenharmony_ci			error);
3548c2ecf20Sopenharmony_ci		return error;
3558c2ecf20Sopenharmony_ci	}
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	if (f30->has_gpio) {
3588c2ecf20Sopenharmony_ci		error = rmi_f30_map_gpios(fn, f30);
3598c2ecf20Sopenharmony_ci		if (error)
3608c2ecf20Sopenharmony_ci			return error;
3618c2ecf20Sopenharmony_ci	}
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	return 0;
3648c2ecf20Sopenharmony_ci}
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_cistatic int rmi_f30_probe(struct rmi_function *fn)
3678c2ecf20Sopenharmony_ci{
3688c2ecf20Sopenharmony_ci	struct rmi_device *rmi_dev = fn->rmi_dev;
3698c2ecf20Sopenharmony_ci	const struct rmi_device_platform_data *pdata =
3708c2ecf20Sopenharmony_ci					rmi_get_platform_data(rmi_dev);
3718c2ecf20Sopenharmony_ci	struct rmi_driver_data *drv_data = dev_get_drvdata(&rmi_dev->dev);
3728c2ecf20Sopenharmony_ci	struct f30_data *f30;
3738c2ecf20Sopenharmony_ci	int error;
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	if (pdata->gpio_data.disable)
3768c2ecf20Sopenharmony_ci		return 0;
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	if (!drv_data->input) {
3798c2ecf20Sopenharmony_ci		dev_info(&fn->dev, "F30: no input device found, ignoring\n");
3808c2ecf20Sopenharmony_ci		return -ENXIO;
3818c2ecf20Sopenharmony_ci	}
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	f30 = devm_kzalloc(&fn->dev, sizeof(*f30), GFP_KERNEL);
3848c2ecf20Sopenharmony_ci	if (!f30)
3858c2ecf20Sopenharmony_ci		return -ENOMEM;
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	f30->input = drv_data->input;
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	error = rmi_f30_initialize(fn, f30);
3908c2ecf20Sopenharmony_ci	if (error)
3918c2ecf20Sopenharmony_ci		return error;
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	dev_set_drvdata(&fn->dev, f30);
3948c2ecf20Sopenharmony_ci	return 0;
3958c2ecf20Sopenharmony_ci}
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_cistruct rmi_function_handler rmi_f30_handler = {
3988c2ecf20Sopenharmony_ci	.driver = {
3998c2ecf20Sopenharmony_ci		.name = "rmi4_f30",
4008c2ecf20Sopenharmony_ci	},
4018c2ecf20Sopenharmony_ci	.func = 0x30,
4028c2ecf20Sopenharmony_ci	.probe = rmi_f30_probe,
4038c2ecf20Sopenharmony_ci	.config = rmi_f30_config,
4048c2ecf20Sopenharmony_ci	.attention = rmi_f30_attention,
4058c2ecf20Sopenharmony_ci};
406