1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2025 Nuvoton Technology Corp. 4 * 5 * Nuvoton NCT6694 core driver using USB interface to provide 6 * access to the NCT6694 hardware monitoring and control features. 7 * 8 * The NCT6694 is an integrated controller that provides GPIO, I2C, 9 * CAN, WDT, HWMON and RTC management. 10 */ 11 12 #include <linux/bits.h> 13 #include <linux/interrupt.h> 14 #include <linux/idr.h> 15 #include <linux/irq.h> 16 #include <linux/irqdomain.h> 17 #include <linux/kernel.h> 18 #include <linux/mfd/core.h> 19 #include <linux/mfd/nct6694.h> 20 #include <linux/module.h> 21 #include <linux/slab.h> 22 #include <linux/spinlock.h> 23 #include <linux/usb.h> 24 25 static const struct mfd_cell nct6694_devs[] = { 26 MFD_CELL_NAME("nct6694-gpio"), 27 MFD_CELL_NAME("nct6694-gpio"), 28 MFD_CELL_NAME("nct6694-gpio"), 29 MFD_CELL_NAME("nct6694-gpio"), 30 MFD_CELL_NAME("nct6694-gpio"), 31 MFD_CELL_NAME("nct6694-gpio"), 32 MFD_CELL_NAME("nct6694-gpio"), 33 MFD_CELL_NAME("nct6694-gpio"), 34 MFD_CELL_NAME("nct6694-gpio"), 35 MFD_CELL_NAME("nct6694-gpio"), 36 MFD_CELL_NAME("nct6694-gpio"), 37 MFD_CELL_NAME("nct6694-gpio"), 38 MFD_CELL_NAME("nct6694-gpio"), 39 MFD_CELL_NAME("nct6694-gpio"), 40 MFD_CELL_NAME("nct6694-gpio"), 41 MFD_CELL_NAME("nct6694-gpio"), 42 43 MFD_CELL_NAME("nct6694-i2c"), 44 MFD_CELL_NAME("nct6694-i2c"), 45 MFD_CELL_NAME("nct6694-i2c"), 46 MFD_CELL_NAME("nct6694-i2c"), 47 MFD_CELL_NAME("nct6694-i2c"), 48 MFD_CELL_NAME("nct6694-i2c"), 49 50 MFD_CELL_NAME("nct6694-canfd"), 51 MFD_CELL_NAME("nct6694-canfd"), 52 53 MFD_CELL_NAME("nct6694-wdt"), 54 MFD_CELL_NAME("nct6694-wdt"), 55 56 MFD_CELL_NAME("nct6694-hwmon"), 57 58 MFD_CELL_NAME("nct6694-rtc"), 59 }; 60 61 static int nct6694_response_err_handling(struct nct6694 *nct6694, unsigned char err_status) 62 { 63 switch (err_status) { 64 case NCT6694_NO_ERROR: 65 return 0; 66 case NCT6694_NOT_SUPPORT_ERROR: 67 dev_err(nct6694->dev, "Command is not supported!\n"); 68 break; 69 case NCT6694_NO_RESPONSE_ERROR: 70 dev_warn(nct6694->dev, "Command received no response!\n"); 71 break; 72 case NCT6694_TIMEOUT_ERROR: 73 dev_warn(nct6694->dev, "Command timed out!\n"); 74 break; 75 case NCT6694_PENDING: 76 dev_err(nct6694->dev, "Command is pending!\n"); 77 break; 78 default: 79 return -EINVAL; 80 } 81 82 return -EIO; 83 } 84 85 /** 86 * nct6694_read_msg() - Read message from NCT6694 device 87 * @nct6694: NCT6694 device pointer 88 * @cmd_hd: command header structure 89 * @buf: buffer to store the response data 90 * 91 * Sends a command to the NCT6694 device and reads the response. 92 * The command header is specified in @cmd_hd, and the response 93 * data is stored in @buf. 94 * 95 * Return: Negative value on error or 0 on success. 96 */ 97 int nct6694_read_msg(struct nct6694 *nct6694, const struct nct6694_cmd_header *cmd_hd, void *buf) 98 { 99 union nct6694_usb_msg *msg = nct6694->usb_msg; 100 struct usb_device *udev = nct6694->udev; 101 int tx_len, rx_len, ret; 102 103 guard(mutex)(&nct6694->access_lock); 104 105 memcpy(&msg->cmd_header, cmd_hd, sizeof(*cmd_hd)); 106 msg->cmd_header.hctrl = NCT6694_HCTRL_GET; 107 108 /* Send command packet to USB device */ 109 ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, NCT6694_BULK_OUT_EP), &msg->cmd_header, 110 sizeof(*msg), &tx_len, NCT6694_URB_TIMEOUT); 111 if (ret) 112 return ret; 113 114 /* Receive response packet from USB device */ 115 ret = usb_bulk_msg(udev, usb_rcvbulkpipe(udev, NCT6694_BULK_IN_EP), &msg->response_header, 116 sizeof(*msg), &rx_len, NCT6694_URB_TIMEOUT); 117 if (ret) 118 return ret; 119 120 /* Receive data packet from USB device */ 121 ret = usb_bulk_msg(udev, usb_rcvbulkpipe(udev, NCT6694_BULK_IN_EP), buf, 122 le16_to_cpu(cmd_hd->len), &rx_len, NCT6694_URB_TIMEOUT); 123 if (ret) 124 return ret; 125 126 if (rx_len != le16_to_cpu(cmd_hd->len)) { 127 dev_err(nct6694->dev, "Expected received length %d, but got %d\n", 128 le16_to_cpu(cmd_hd->len), rx_len); 129 return -EIO; 130 } 131 132 return nct6694_response_err_handling(nct6694, msg->response_header.sts); 133 } 134 EXPORT_SYMBOL_GPL(nct6694_read_msg); 135 136 /** 137 * nct6694_write_msg() - Write message to NCT6694 device 138 * @nct6694: NCT6694 device pointer 139 * @cmd_hd: command header structure 140 * @buf: buffer containing the data to be sent 141 * 142 * Sends a command to the NCT6694 device and writes the data 143 * from @buf. The command header is specified in @cmd_hd. 144 * 145 * Return: Negative value on error or 0 on success. 146 */ 147 int nct6694_write_msg(struct nct6694 *nct6694, const struct nct6694_cmd_header *cmd_hd, void *buf) 148 { 149 union nct6694_usb_msg *msg = nct6694->usb_msg; 150 struct usb_device *udev = nct6694->udev; 151 int tx_len, rx_len, ret; 152 153 guard(mutex)(&nct6694->access_lock); 154 155 memcpy(&msg->cmd_header, cmd_hd, sizeof(*cmd_hd)); 156 msg->cmd_header.hctrl = NCT6694_HCTRL_SET; 157 158 /* Send command packet to USB device */ 159 ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, NCT6694_BULK_OUT_EP), &msg->cmd_header, 160 sizeof(*msg), &tx_len, NCT6694_URB_TIMEOUT); 161 if (ret) 162 return ret; 163 164 /* Send data packet to USB device */ 165 ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, NCT6694_BULK_OUT_EP), buf, 166 le16_to_cpu(cmd_hd->len), &tx_len, NCT6694_URB_TIMEOUT); 167 if (ret) 168 return ret; 169 170 /* Receive response packet from USB device */ 171 ret = usb_bulk_msg(udev, usb_rcvbulkpipe(udev, NCT6694_BULK_IN_EP), &msg->response_header, 172 sizeof(*msg), &rx_len, NCT6694_URB_TIMEOUT); 173 if (ret) 174 return ret; 175 176 /* Receive data packet from USB device */ 177 ret = usb_bulk_msg(udev, usb_rcvbulkpipe(udev, NCT6694_BULK_IN_EP), buf, 178 le16_to_cpu(cmd_hd->len), &rx_len, NCT6694_URB_TIMEOUT); 179 if (ret) 180 return ret; 181 182 if (rx_len != le16_to_cpu(cmd_hd->len)) { 183 dev_err(nct6694->dev, "Expected transmitted length %d, but got %d\n", 184 le16_to_cpu(cmd_hd->len), rx_len); 185 return -EIO; 186 } 187 188 return nct6694_response_err_handling(nct6694, msg->response_header.sts); 189 } 190 EXPORT_SYMBOL_GPL(nct6694_write_msg); 191 192 static void usb_int_callback(struct urb *urb) 193 { 194 struct nct6694 *nct6694 = urb->context; 195 __le32 *status_le = urb->transfer_buffer; 196 u32 int_status; 197 int ret; 198 199 switch (urb->status) { 200 case 0: 201 break; 202 case -ECONNRESET: 203 case -ENOENT: 204 case -ESHUTDOWN: 205 return; 206 default: 207 goto resubmit; 208 } 209 210 int_status = le32_to_cpu(*status_le); 211 212 while (int_status) { 213 int irq = __ffs(int_status); 214 215 generic_handle_irq_safe(irq_find_mapping(nct6694->domain, irq)); 216 int_status &= ~BIT(irq); 217 } 218 219 resubmit: 220 ret = usb_submit_urb(urb, GFP_ATOMIC); 221 if (ret) 222 dev_warn(nct6694->dev, "Failed to resubmit urb, status %pe", ERR_PTR(ret)); 223 } 224 225 static void nct6694_irq_enable(struct irq_data *data) 226 { 227 struct nct6694 *nct6694 = irq_data_get_irq_chip_data(data); 228 irq_hw_number_t hwirq = irqd_to_hwirq(data); 229 230 guard(spinlock_irqsave)(&nct6694->irq_lock); 231 232 nct6694->irq_enable |= BIT(hwirq); 233 } 234 235 static void nct6694_irq_disable(struct irq_data *data) 236 { 237 struct nct6694 *nct6694 = irq_data_get_irq_chip_data(data); 238 irq_hw_number_t hwirq = irqd_to_hwirq(data); 239 240 guard(spinlock_irqsave)(&nct6694->irq_lock); 241 242 nct6694->irq_enable &= ~BIT(hwirq); 243 } 244 245 static const struct irq_chip nct6694_irq_chip = { 246 .name = "nct6694-irq", 247 .flags = IRQCHIP_SKIP_SET_WAKE, 248 .irq_enable = nct6694_irq_enable, 249 .irq_disable = nct6694_irq_disable, 250 }; 251 252 static int nct6694_irq_domain_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) 253 { 254 struct nct6694 *nct6694 = d->host_data; 255 256 irq_set_chip_data(irq, nct6694); 257 irq_set_chip_and_handler(irq, &nct6694_irq_chip, handle_simple_irq); 258 259 return 0; 260 } 261 262 static void nct6694_irq_domain_unmap(struct irq_domain *d, unsigned int irq) 263 { 264 irq_set_chip_and_handler(irq, NULL, NULL); 265 irq_set_chip_data(irq, NULL); 266 } 267 268 static const struct irq_domain_ops nct6694_irq_domain_ops = { 269 .map = nct6694_irq_domain_map, 270 .unmap = nct6694_irq_domain_unmap, 271 }; 272 273 static int nct6694_usb_probe(struct usb_interface *iface, 274 const struct usb_device_id *id) 275 { 276 struct usb_device *udev = interface_to_usbdev(iface); 277 struct usb_endpoint_descriptor *int_endpoint; 278 struct usb_host_interface *interface; 279 struct device *dev = &iface->dev; 280 struct nct6694 *nct6694; 281 int ret; 282 283 nct6694 = devm_kzalloc(dev, sizeof(*nct6694), GFP_KERNEL); 284 if (!nct6694) 285 return -ENOMEM; 286 287 nct6694->usb_msg = devm_kzalloc(dev, sizeof(union nct6694_usb_msg), GFP_KERNEL); 288 if (!nct6694->usb_msg) 289 return -ENOMEM; 290 291 nct6694->int_buffer = devm_kzalloc(dev, sizeof(*nct6694->int_buffer), GFP_KERNEL); 292 if (!nct6694->int_buffer) 293 return -ENOMEM; 294 295 nct6694->int_in_urb = usb_alloc_urb(0, GFP_KERNEL); 296 if (!nct6694->int_in_urb) 297 return -ENOMEM; 298 299 nct6694->domain = irq_domain_create_simple(NULL, NCT6694_NR_IRQS, 0, 300 &nct6694_irq_domain_ops, 301 nct6694); 302 if (!nct6694->domain) { 303 ret = -ENODEV; 304 goto err_urb; 305 } 306 307 nct6694->dev = dev; 308 nct6694->udev = udev; 309 310 ida_init(&nct6694->gpio_ida); 311 ida_init(&nct6694->i2c_ida); 312 ida_init(&nct6694->canfd_ida); 313 ida_init(&nct6694->wdt_ida); 314 315 spin_lock_init(&nct6694->irq_lock); 316 317 ret = devm_mutex_init(dev, &nct6694->access_lock); 318 if (ret) 319 goto err_ida; 320 321 interface = iface->cur_altsetting; 322 323 int_endpoint = &interface->endpoint[0].desc; 324 if (!usb_endpoint_is_int_in(int_endpoint)) { 325 ret = -ENODEV; 326 goto err_ida; 327 } 328 329 usb_fill_int_urb(nct6694->int_in_urb, udev, usb_rcvintpipe(udev, NCT6694_INT_IN_EP), 330 nct6694->int_buffer, sizeof(*nct6694->int_buffer), usb_int_callback, 331 nct6694, int_endpoint->bInterval); 332 333 ret = usb_submit_urb(nct6694->int_in_urb, GFP_KERNEL); 334 if (ret) 335 goto err_ida; 336 337 usb_set_intfdata(iface, nct6694); 338 339 ret = mfd_add_hotplug_devices(dev, nct6694_devs, ARRAY_SIZE(nct6694_devs)); 340 if (ret) 341 goto err_mfd; 342 343 return 0; 344 345 err_mfd: 346 usb_kill_urb(nct6694->int_in_urb); 347 err_ida: 348 ida_destroy(&nct6694->wdt_ida); 349 ida_destroy(&nct6694->canfd_ida); 350 ida_destroy(&nct6694->i2c_ida); 351 ida_destroy(&nct6694->gpio_ida); 352 irq_domain_remove(nct6694->domain); 353 err_urb: 354 usb_free_urb(nct6694->int_in_urb); 355 return ret; 356 } 357 358 static void nct6694_usb_disconnect(struct usb_interface *iface) 359 { 360 struct nct6694 *nct6694 = usb_get_intfdata(iface); 361 362 mfd_remove_devices(nct6694->dev); 363 usb_kill_urb(nct6694->int_in_urb); 364 ida_destroy(&nct6694->wdt_ida); 365 ida_destroy(&nct6694->canfd_ida); 366 ida_destroy(&nct6694->i2c_ida); 367 ida_destroy(&nct6694->gpio_ida); 368 irq_domain_remove(nct6694->domain); 369 usb_free_urb(nct6694->int_in_urb); 370 } 371 372 static const struct usb_device_id nct6694_ids[] = { 373 { USB_DEVICE_AND_INTERFACE_INFO(NCT6694_VENDOR_ID, NCT6694_PRODUCT_ID, 0xFF, 0x00, 0x00) }, 374 { } 375 }; 376 MODULE_DEVICE_TABLE(usb, nct6694_ids); 377 378 static struct usb_driver nct6694_usb_driver = { 379 .name = "nct6694", 380 .id_table = nct6694_ids, 381 .probe = nct6694_usb_probe, 382 .disconnect = nct6694_usb_disconnect, 383 }; 384 module_usb_driver(nct6694_usb_driver); 385 386 MODULE_DESCRIPTION("Nuvoton NCT6694 core driver"); 387 MODULE_AUTHOR("Ming Yu <tmyu0@nuvoton.com>"); 388 MODULE_LICENSE("GPL"); 389