xref: /linux/drivers/hid/hid-mcp2200.c (revision 76f623d2d4283cc36a9c8a5b585df74638f1efa5)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * MCP2200 - Microchip USB to GPIO bridge
4  *
5  * Copyright (c) 2023, Johannes Roith <johannes@gnu-linux.rocks>
6  *
7  * Datasheet: https://ww1.microchip.com/downloads/en/DeviceDoc/22228A.pdf
8  * App Note for HID: https://ww1.microchip.com/downloads/en/DeviceDoc/93066A.pdf
9  */
10 #include <linux/completion.h>
11 #include <linux/delay.h>
12 #include <linux/err.h>
13 #include <linux/gpio/driver.h>
14 #include <linux/hid.h>
15 #include <linux/hidraw.h>
16 #include <linux/module.h>
17 #include <linux/mutex.h>
18 #include "hid-ids.h"
19 
20 /* Commands codes in a raw output report */
21 #define SET_CLEAR_OUTPUTS	0x08
22 #define CONFIGURE		0x10
23 #define READ_EE			0x20
24 #define WRITE_EE		0x40
25 #define READ_ALL		0x80
26 
27 /* MCP GPIO direction encoding */
28 enum MCP_IO_DIR {
29 	MCP2200_DIR_OUT = 0x00,
30 	MCP2200_DIR_IN  = 0x01,
31 };
32 
33 /* Altternative pin assignments */
34 #define TXLED		2
35 #define RXLED		3
36 #define USBCFG		6
37 #define SSPND		7
38 #define MCP_NGPIO	8
39 
40 /* CMD to set or clear a GPIO output */
41 struct mcp_set_clear_outputs {
42 	u8 cmd;
43 	u8 dummys1[10];
44 	u8 set_bmap;
45 	u8 clear_bmap;
46 	u8 dummys2[3];
47 } __packed;
48 
49 /* CMD to configure the IOs */
50 struct mcp_configure {
51 	u8 cmd;
52 	u8 dummys1[3];
53 	u8 io_bmap;
54 	u8 config_alt_pins;
55 	u8 io_default_val_bmap;
56 	u8 config_alt_options;
57 	u8 baud_h;
58 	u8 baud_l;
59 	u8 dummys2[6];
60 } __packed;
61 
62 /* CMD to read all parameters */
63 struct mcp_read_all {
64 	u8 cmd;
65 	u8 dummys[15];
66 } __packed;
67 
68 /* Response to the read all cmd */
69 struct mcp_read_all_resp {
70 	u8 cmd;
71 	u8 eep_addr;
72 	u8 dummy;
73 	u8 eep_val;
74 	u8 io_bmap;
75 	u8 config_alt_pins;
76 	u8 io_default_val_bmap;
77 	u8 config_alt_options;
78 	u8 baud_h;
79 	u8 baud_l;
80 	u8 io_port_val_bmap;
81 	u8 dummys[5];
82 } __packed;
83 
84 struct mcp2200 {
85 	struct hid_device *hdev;
86 	struct mutex lock;
87 	struct completion wait_in_report;
88 	u8 gpio_dir;
89 	u8 gpio_val;
90 	u8 gpio_inval;
91 	u8 baud_h;
92 	u8 baud_l;
93 	u8 config_alt_pins;
94 	u8 gpio_reset_val;
95 	u8 config_alt_options;
96 	int status;
97 	struct gpio_chip gc;
98 	u8 hid_report[16];
99 };
100 
101 /* this executes the READ_ALL cmd */
102 static int mcp_cmd_read_all(struct mcp2200 *mcp)
103 {
104 	struct mcp_read_all *read_all;
105 	int len, t;
106 
107 	reinit_completion(&mcp->wait_in_report);
108 
109 	mutex_lock(&mcp->lock);
110 
111 	read_all = (struct mcp_read_all *) mcp->hid_report;
112 	read_all->cmd = READ_ALL;
113 	len = hid_hw_output_report(mcp->hdev, (u8 *) read_all,
114 				   sizeof(struct mcp_read_all));
115 
116 	mutex_unlock(&mcp->lock);
117 
118 	if (len != sizeof(struct mcp_read_all))
119 		return -EINVAL;
120 
121 	t = wait_for_completion_timeout(&mcp->wait_in_report,
122 					msecs_to_jiffies(4000));
123 	if (!t)
124 		return -ETIMEDOUT;
125 
126 	/* return status, negative value if wrong response was received */
127 	return mcp->status;
128 }
129 
130 static void mcp_set_multiple(struct gpio_chip *gc, unsigned long *mask,
131 			     unsigned long *bits)
132 {
133 	struct mcp2200 *mcp = gpiochip_get_data(gc);
134 	u8 value;
135 	int status;
136 	struct mcp_set_clear_outputs *cmd;
137 
138 	mutex_lock(&mcp->lock);
139 	cmd = (struct mcp_set_clear_outputs *) mcp->hid_report;
140 
141 	value = mcp->gpio_val & ~*mask;
142 	value |= (*mask & *bits);
143 
144 	cmd->cmd = SET_CLEAR_OUTPUTS;
145 	cmd->set_bmap = value;
146 	cmd->clear_bmap = ~(value);
147 
148 	status = hid_hw_output_report(mcp->hdev, (u8 *) cmd,
149 		       sizeof(struct mcp_set_clear_outputs));
150 
151 	if (status == sizeof(struct mcp_set_clear_outputs))
152 		mcp->gpio_val = value;
153 
154 	mutex_unlock(&mcp->lock);
155 }
156 
157 static void mcp_set(struct gpio_chip *gc, unsigned int gpio_nr, int value)
158 {
159 	unsigned long mask = 1 << gpio_nr;
160 	unsigned long bmap_value = value << gpio_nr;
161 
162 	mcp_set_multiple(gc, &mask, &bmap_value);
163 }
164 
165 static int mcp_get_multiple(struct gpio_chip *gc, unsigned long *mask,
166 		unsigned long *bits)
167 {
168 	u32 val;
169 	struct mcp2200 *mcp = gpiochip_get_data(gc);
170 	int status;
171 
172 	status = mcp_cmd_read_all(mcp);
173 	if (status)
174 		return status;
175 
176 	val = mcp->gpio_inval;
177 	*bits = (val & *mask);
178 	return 0;
179 }
180 
181 static int mcp_get(struct gpio_chip *gc, unsigned int gpio_nr)
182 {
183 	unsigned long mask = 0, bits = 0;
184 
185 	mask = (1 << gpio_nr);
186 	mcp_get_multiple(gc, &mask, &bits);
187 	return bits > 0;
188 }
189 
190 static int mcp_get_direction(struct gpio_chip *gc, unsigned int gpio_nr)
191 {
192 	struct mcp2200 *mcp = gpiochip_get_data(gc);
193 
194 	return (mcp->gpio_dir & (MCP2200_DIR_IN << gpio_nr))
195 		? GPIO_LINE_DIRECTION_IN : GPIO_LINE_DIRECTION_OUT;
196 }
197 
198 static int mcp_set_direction(struct gpio_chip *gc, unsigned int gpio_nr,
199 			     enum MCP_IO_DIR io_direction)
200 {
201 	struct mcp2200 *mcp = gpiochip_get_data(gc);
202 	struct mcp_configure *conf;
203 	int status;
204 	/* after the configure cmd we will need to set the outputs again */
205 	unsigned long mask = ~(mcp->gpio_dir); /* only set outputs */
206 	unsigned long bits = mcp->gpio_val;
207 	/* Offsets of alternative pins in config_alt_pins, 0 is not used */
208 	u8 alt_pin_conf[8] = {SSPND, USBCFG, 0, 0, 0, 0, RXLED, TXLED};
209 	u8 config_alt_pins = mcp->config_alt_pins;
210 
211 	/* Read in the reset baudrate first, we need it later */
212 	status = mcp_cmd_read_all(mcp);
213 	if (status != 0)
214 		return status;
215 
216 	mutex_lock(&mcp->lock);
217 	conf = (struct mcp_configure  *) mcp->hid_report;
218 
219 	/* configure will reset the chip! */
220 	conf->cmd = CONFIGURE;
221 	conf->io_bmap = (mcp->gpio_dir & ~(1 << gpio_nr))
222 		| (io_direction << gpio_nr);
223 	/* Don't overwrite the reset parameters */
224 	conf->baud_h = mcp->baud_h;
225 	conf->baud_l = mcp->baud_l;
226 	conf->config_alt_options = mcp->config_alt_options;
227 	conf->io_default_val_bmap = mcp->gpio_reset_val;
228 	/* Adjust alt. func if necessary */
229 	if (alt_pin_conf[gpio_nr])
230 		config_alt_pins &= ~(1 << alt_pin_conf[gpio_nr]);
231 	conf->config_alt_pins = config_alt_pins;
232 
233 	status = hid_hw_output_report(mcp->hdev, (u8 *) conf,
234 				      sizeof(struct mcp_set_clear_outputs));
235 
236 	if (status == sizeof(struct mcp_set_clear_outputs)) {
237 		mcp->gpio_dir = conf->io_bmap;
238 		mcp->config_alt_pins = config_alt_pins;
239 	} else {
240 		mutex_unlock(&mcp->lock);
241 		return -EIO;
242 	}
243 
244 	mutex_unlock(&mcp->lock);
245 
246 	/* Configure CMD will clear all IOs -> rewrite them */
247 	mcp_set_multiple(gc, &mask, &bits);
248 	return 0;
249 }
250 
251 static int mcp_direction_input(struct gpio_chip *gc, unsigned int gpio_nr)
252 {
253 	return mcp_set_direction(gc, gpio_nr, MCP2200_DIR_IN);
254 }
255 
256 static int mcp_direction_output(struct gpio_chip *gc, unsigned int gpio_nr,
257 				int value)
258 {
259 	int ret;
260 	unsigned long mask, bmap_value;
261 
262 	mask = 1 << gpio_nr;
263 	bmap_value = value << gpio_nr;
264 
265 	ret = mcp_set_direction(gc, gpio_nr, MCP2200_DIR_OUT);
266 	if (!ret)
267 		mcp_set_multiple(gc, &mask, &bmap_value);
268 	return ret;
269 }
270 
271 static const struct gpio_chip template_chip = {
272 	.label			= "mcp2200",
273 	.owner			= THIS_MODULE,
274 	.get_direction		= mcp_get_direction,
275 	.direction_input	= mcp_direction_input,
276 	.direction_output	= mcp_direction_output,
277 	.set			= mcp_set,
278 	.set_multiple		= mcp_set_multiple,
279 	.get			= mcp_get,
280 	.get_multiple		= mcp_get_multiple,
281 	.base			= -1,
282 	.ngpio			= MCP_NGPIO,
283 	.can_sleep		= true,
284 };
285 
286 /*
287  * MCP2200 uses interrupt endpoint for input reports. This function
288  * is called by HID layer when it receives i/p report from mcp2200,
289  * which is actually a response to the previously sent command.
290  */
291 static int mcp2200_raw_event(struct hid_device *hdev, struct hid_report *report,
292 		u8 *data, int size)
293 {
294 	struct mcp2200 *mcp = hid_get_drvdata(hdev);
295 	struct mcp_read_all_resp *all_resp;
296 
297 	switch (data[0]) {
298 	case READ_ALL:
299 		all_resp = (struct mcp_read_all_resp *) data;
300 		mcp->status = 0;
301 		mcp->gpio_inval = all_resp->io_port_val_bmap;
302 		mcp->baud_h = all_resp->baud_h;
303 		mcp->baud_l = all_resp->baud_l;
304 		mcp->gpio_reset_val = all_resp->io_default_val_bmap;
305 		mcp->config_alt_pins = all_resp->config_alt_pins;
306 		mcp->config_alt_options = all_resp->config_alt_options;
307 		break;
308 	default:
309 		mcp->status = -EIO;
310 		break;
311 	}
312 
313 	complete(&mcp->wait_in_report);
314 	return 0;
315 }
316 
317 static int mcp2200_probe(struct hid_device *hdev, const struct hid_device_id *id)
318 {
319 	int ret;
320 	struct mcp2200 *mcp;
321 
322 	mcp = devm_kzalloc(&hdev->dev, sizeof(*mcp), GFP_KERNEL);
323 	if (!mcp)
324 		return -ENOMEM;
325 
326 	ret = hid_parse(hdev);
327 	if (ret) {
328 		hid_err(hdev, "can't parse reports\n");
329 		return ret;
330 	}
331 
332 	ret = hid_hw_start(hdev, 0);
333 	if (ret) {
334 		hid_err(hdev, "can't start hardware\n");
335 		return ret;
336 	}
337 
338 	hid_info(hdev, "USB HID v%x.%02x Device [%s] on %s\n", hdev->version >> 8,
339 			hdev->version & 0xff, hdev->name, hdev->phys);
340 
341 	ret = hid_hw_open(hdev);
342 	if (ret) {
343 		hid_err(hdev, "can't open device\n");
344 		hid_hw_stop(hdev);
345 		return ret;
346 	}
347 
348 	mutex_init(&mcp->lock);
349 	init_completion(&mcp->wait_in_report);
350 	hid_set_drvdata(hdev, mcp);
351 	mcp->hdev = hdev;
352 
353 	mcp->gc = template_chip;
354 	mcp->gc.parent = &hdev->dev;
355 
356 	ret = devm_gpiochip_add_data(&hdev->dev, &mcp->gc, mcp);
357 	if (ret < 0) {
358 		hid_err(hdev, "Unable to register gpiochip\n");
359 		hid_hw_close(hdev);
360 		hid_hw_stop(hdev);
361 		return ret;
362 	}
363 
364 	return 0;
365 }
366 
367 static void mcp2200_remove(struct hid_device *hdev)
368 {
369 	hid_hw_close(hdev);
370 	hid_hw_stop(hdev);
371 }
372 
373 static const struct hid_device_id mcp2200_devices[] = {
374 	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_MCP2200) },
375 	{ }
376 };
377 MODULE_DEVICE_TABLE(hid, mcp2200_devices);
378 
379 static struct hid_driver mcp2200_driver = {
380 	.name		= "mcp2200",
381 	.id_table	= mcp2200_devices,
382 	.probe		= mcp2200_probe,
383 	.remove		= mcp2200_remove,
384 	.raw_event	= mcp2200_raw_event,
385 };
386 
387 /* Register with HID core */
388 module_hid_driver(mcp2200_driver);
389 
390 MODULE_AUTHOR("Johannes Roith <johannes@gnu-linux.rocks>");
391 MODULE_DESCRIPTION("MCP2200 Microchip HID USB to GPIO bridge");
392 MODULE_LICENSE("GPL");
393