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