1c46a74ffSMary Strodl // SPDX-License-Identifier: GPL-2.0-only 2c46a74ffSMary Strodl /* 3c46a74ffSMary Strodl * FTDI MPSSE GPIO support 4c46a74ffSMary Strodl * 5c46a74ffSMary Strodl * Based on code by Anatolij Gustschin 6c46a74ffSMary Strodl * 7c46a74ffSMary Strodl * Copyright (C) 2024 Mary Strodl <mstrodl@csh.rit.edu> 8c46a74ffSMary Strodl */ 9c46a74ffSMary Strodl 10c46a74ffSMary Strodl #include <linux/cleanup.h> 11c46a74ffSMary Strodl #include <linux/gpio/driver.h> 12c46a74ffSMary Strodl #include <linux/mutex.h> 13c46a74ffSMary Strodl #include <linux/usb.h> 14c46a74ffSMary Strodl 15c46a74ffSMary Strodl struct mpsse_priv { 16c46a74ffSMary Strodl struct gpio_chip gpio; 17c46a74ffSMary Strodl struct usb_device *udev; /* USB device encompassing all MPSSEs */ 18c46a74ffSMary Strodl struct usb_interface *intf; /* USB interface for this MPSSE */ 19c46a74ffSMary Strodl u8 intf_id; /* USB interface number for this MPSSE */ 20c46a74ffSMary Strodl struct work_struct irq_work; /* polling work thread */ 21c46a74ffSMary Strodl struct mutex irq_mutex; /* lock over irq_data */ 22c46a74ffSMary Strodl atomic_t irq_type[16]; /* pin -> edge detection type */ 23c46a74ffSMary Strodl atomic_t irq_enabled; 24c46a74ffSMary Strodl int id; 25c46a74ffSMary Strodl 26c46a74ffSMary Strodl u8 gpio_outputs[2]; /* Output states for GPIOs [L, H] */ 27c46a74ffSMary Strodl u8 gpio_dir[2]; /* Directions for GPIOs [L, H] */ 28c46a74ffSMary Strodl 29c46a74ffSMary Strodl u8 *bulk_in_buf; /* Extra recv buffer to grab status bytes */ 30c46a74ffSMary Strodl 31c46a74ffSMary Strodl struct usb_endpoint_descriptor *bulk_in; 32c46a74ffSMary Strodl struct usb_endpoint_descriptor *bulk_out; 33c46a74ffSMary Strodl 34c46a74ffSMary Strodl struct mutex io_mutex; /* sync I/O with disconnect */ 35c46a74ffSMary Strodl }; 36c46a74ffSMary Strodl 37c46a74ffSMary Strodl struct bulk_desc { 38c46a74ffSMary Strodl bool tx; /* direction of bulk transfer */ 39c46a74ffSMary Strodl u8 *data; /* input (tx) or output (rx) */ 40c46a74ffSMary Strodl int len; /* Length of `data` if tx, or length of */ 41c46a74ffSMary Strodl /* Data to read if rx */ 42c46a74ffSMary Strodl int len_actual; /* Length successfully transferred */ 43c46a74ffSMary Strodl int timeout; 44c46a74ffSMary Strodl }; 45c46a74ffSMary Strodl 46c46a74ffSMary Strodl static const struct usb_device_id gpio_mpsse_table[] = { 47c46a74ffSMary Strodl { USB_DEVICE(0x0c52, 0xa064) }, /* SeaLevel Systems, Inc. */ 48c46a74ffSMary Strodl { } /* Terminating entry */ 49c46a74ffSMary Strodl }; 50c46a74ffSMary Strodl 51c46a74ffSMary Strodl MODULE_DEVICE_TABLE(usb, gpio_mpsse_table); 52c46a74ffSMary Strodl 53c46a74ffSMary Strodl static DEFINE_IDA(gpio_mpsse_ida); 54c46a74ffSMary Strodl 55c46a74ffSMary Strodl /* MPSSE commands */ 56c46a74ffSMary Strodl #define SET_BITS_CMD 0x80 57c46a74ffSMary Strodl #define GET_BITS_CMD 0x81 58c46a74ffSMary Strodl 59c46a74ffSMary Strodl #define SET_BITMODE_REQUEST 0x0B 60c46a74ffSMary Strodl #define MODE_MPSSE (2 << 8) 61c46a74ffSMary Strodl #define MODE_RESET 0 62c46a74ffSMary Strodl 63c46a74ffSMary Strodl /* Arbitrarily decided. This could probably be much less */ 64c46a74ffSMary Strodl #define MPSSE_WRITE_TIMEOUT 5000 65c46a74ffSMary Strodl #define MPSSE_READ_TIMEOUT 5000 66c46a74ffSMary Strodl 67c46a74ffSMary Strodl /* 1 millisecond, also pretty arbitrary */ 68c46a74ffSMary Strodl #define MPSSE_POLL_INTERVAL 1000 69c46a74ffSMary Strodl 70c46a74ffSMary Strodl static int mpsse_bulk_xfer(struct usb_interface *intf, struct bulk_desc *desc) 71c46a74ffSMary Strodl { 72c46a74ffSMary Strodl struct mpsse_priv *priv = usb_get_intfdata(intf); 73c46a74ffSMary Strodl struct usb_device *udev = priv->udev; 74c46a74ffSMary Strodl unsigned int pipe; 75c46a74ffSMary Strodl int ret; 76c46a74ffSMary Strodl 77c46a74ffSMary Strodl if (desc->tx) 78c46a74ffSMary Strodl pipe = usb_sndbulkpipe(udev, priv->bulk_out->bEndpointAddress); 79c46a74ffSMary Strodl else 80c46a74ffSMary Strodl pipe = usb_rcvbulkpipe(udev, priv->bulk_in->bEndpointAddress); 81c46a74ffSMary Strodl 82c46a74ffSMary Strodl ret = usb_bulk_msg(udev, pipe, desc->data, desc->len, 83c46a74ffSMary Strodl &desc->len_actual, desc->timeout); 84c46a74ffSMary Strodl if (ret) 85c46a74ffSMary Strodl dev_dbg(&udev->dev, "mpsse: bulk transfer failed: %d\n", ret); 86c46a74ffSMary Strodl 87c46a74ffSMary Strodl return ret; 88c46a74ffSMary Strodl } 89c46a74ffSMary Strodl 90c46a74ffSMary Strodl static int mpsse_write(struct usb_interface *intf, 91c46a74ffSMary Strodl u8 *buf, size_t len) 92c46a74ffSMary Strodl { 93c46a74ffSMary Strodl int ret; 94c46a74ffSMary Strodl struct bulk_desc desc; 95c46a74ffSMary Strodl 96c46a74ffSMary Strodl desc.len_actual = 0; 97c46a74ffSMary Strodl desc.tx = true; 98c46a74ffSMary Strodl desc.data = buf; 99c46a74ffSMary Strodl desc.len = len; 100c46a74ffSMary Strodl desc.timeout = MPSSE_WRITE_TIMEOUT; 101c46a74ffSMary Strodl 102c46a74ffSMary Strodl ret = mpsse_bulk_xfer(intf, &desc); 103c46a74ffSMary Strodl 104c46a74ffSMary Strodl return ret; 105c46a74ffSMary Strodl } 106c46a74ffSMary Strodl 107c46a74ffSMary Strodl static int mpsse_read(struct usb_interface *intf, u8 *buf, size_t len) 108c46a74ffSMary Strodl { 109c46a74ffSMary Strodl int ret; 110c46a74ffSMary Strodl struct bulk_desc desc; 111c46a74ffSMary Strodl struct mpsse_priv *priv = usb_get_intfdata(intf); 112c46a74ffSMary Strodl 113c46a74ffSMary Strodl desc.len_actual = 0; 114c46a74ffSMary Strodl desc.tx = false; 115c46a74ffSMary Strodl desc.data = priv->bulk_in_buf; 116c46a74ffSMary Strodl /* Device sends 2 additional status bytes, read len + 2 */ 117c46a74ffSMary Strodl desc.len = min_t(size_t, len + 2, usb_endpoint_maxp(priv->bulk_in)); 118c46a74ffSMary Strodl desc.timeout = MPSSE_READ_TIMEOUT; 119c46a74ffSMary Strodl 120c46a74ffSMary Strodl ret = mpsse_bulk_xfer(intf, &desc); 121c46a74ffSMary Strodl if (ret) 122c46a74ffSMary Strodl return ret; 123c46a74ffSMary Strodl 124c46a74ffSMary Strodl /* Did we get enough data? */ 125c46a74ffSMary Strodl if (desc.len_actual < desc.len) 126c46a74ffSMary Strodl return -EIO; 127c46a74ffSMary Strodl 128c46a74ffSMary Strodl memcpy(buf, desc.data + 2, desc.len_actual - 2); 129c46a74ffSMary Strodl 130c46a74ffSMary Strodl return ret; 131c46a74ffSMary Strodl } 132c46a74ffSMary Strodl 133c46a74ffSMary Strodl static int gpio_mpsse_set_bank(struct mpsse_priv *priv, u8 bank) 134c46a74ffSMary Strodl { 135c46a74ffSMary Strodl int ret; 136c46a74ffSMary Strodl u8 tx_buf[3] = { 137c46a74ffSMary Strodl SET_BITS_CMD | (bank << 1), 138c46a74ffSMary Strodl priv->gpio_outputs[bank], 139c46a74ffSMary Strodl priv->gpio_dir[bank], 140c46a74ffSMary Strodl }; 141c46a74ffSMary Strodl 142c46a74ffSMary Strodl ret = mpsse_write(priv->intf, tx_buf, 3); 143c46a74ffSMary Strodl 144c46a74ffSMary Strodl return ret; 145c46a74ffSMary Strodl } 146c46a74ffSMary Strodl 147c46a74ffSMary Strodl static int gpio_mpsse_get_bank(struct mpsse_priv *priv, u8 bank) 148c46a74ffSMary Strodl { 149c46a74ffSMary Strodl int ret; 150c46a74ffSMary Strodl u8 buf = GET_BITS_CMD | (bank << 1); 151c46a74ffSMary Strodl 152c46a74ffSMary Strodl ret = mpsse_write(priv->intf, &buf, 1); 153c46a74ffSMary Strodl if (ret) 154c46a74ffSMary Strodl return ret; 155c46a74ffSMary Strodl 156c46a74ffSMary Strodl ret = mpsse_read(priv->intf, &buf, 1); 157c46a74ffSMary Strodl if (ret) 158c46a74ffSMary Strodl return ret; 159c46a74ffSMary Strodl 160c46a74ffSMary Strodl return buf; 161c46a74ffSMary Strodl } 162c46a74ffSMary Strodl 163c46a74ffSMary Strodl static void gpio_mpsse_set_multiple(struct gpio_chip *chip, unsigned long *mask, 164c46a74ffSMary Strodl unsigned long *bits) 165c46a74ffSMary Strodl { 166c46a74ffSMary Strodl unsigned long i, bank, bank_mask, bank_bits; 167c46a74ffSMary Strodl int ret; 168c46a74ffSMary Strodl struct mpsse_priv *priv = gpiochip_get_data(chip); 169c46a74ffSMary Strodl 170c46a74ffSMary Strodl guard(mutex)(&priv->io_mutex); 171c46a74ffSMary Strodl for_each_set_clump8(i, bank_mask, mask, chip->ngpio) { 172c46a74ffSMary Strodl bank = i / 8; 173c46a74ffSMary Strodl 174c46a74ffSMary Strodl if (bank_mask) { 175c46a74ffSMary Strodl bank_bits = bitmap_get_value8(bits, i); 176c46a74ffSMary Strodl /* Zero out pins we want to change */ 177c46a74ffSMary Strodl priv->gpio_outputs[bank] &= ~bank_mask; 178c46a74ffSMary Strodl /* Set pins we care about */ 179c46a74ffSMary Strodl priv->gpio_outputs[bank] |= bank_bits & bank_mask; 180c46a74ffSMary Strodl 181c46a74ffSMary Strodl ret = gpio_mpsse_set_bank(priv, bank); 182c46a74ffSMary Strodl if (ret) 183c46a74ffSMary Strodl dev_err(&priv->intf->dev, 184c46a74ffSMary Strodl "Couldn't set values for bank %ld!", 185c46a74ffSMary Strodl bank); 186c46a74ffSMary Strodl } 187c46a74ffSMary Strodl } 188c46a74ffSMary Strodl } 189c46a74ffSMary Strodl 190c46a74ffSMary Strodl static int gpio_mpsse_get_multiple(struct gpio_chip *chip, unsigned long *mask, 191c46a74ffSMary Strodl unsigned long *bits) 192c46a74ffSMary Strodl { 193c46a74ffSMary Strodl unsigned long i, bank, bank_mask; 194c46a74ffSMary Strodl int ret; 195c46a74ffSMary Strodl struct mpsse_priv *priv = gpiochip_get_data(chip); 196c46a74ffSMary Strodl 197c46a74ffSMary Strodl guard(mutex)(&priv->io_mutex); 198c46a74ffSMary Strodl for_each_set_clump8(i, bank_mask, mask, chip->ngpio) { 199c46a74ffSMary Strodl bank = i / 8; 200c46a74ffSMary Strodl 201c46a74ffSMary Strodl if (bank_mask) { 202c46a74ffSMary Strodl ret = gpio_mpsse_get_bank(priv, bank); 203c46a74ffSMary Strodl if (ret < 0) 204c46a74ffSMary Strodl return ret; 205c46a74ffSMary Strodl 206c46a74ffSMary Strodl bitmap_set_value8(bits, ret & bank_mask, i); 207c46a74ffSMary Strodl } 208c46a74ffSMary Strodl } 209c46a74ffSMary Strodl 210c46a74ffSMary Strodl return 0; 211c46a74ffSMary Strodl } 212c46a74ffSMary Strodl 213c46a74ffSMary Strodl static int gpio_mpsse_gpio_get(struct gpio_chip *chip, unsigned int offset) 214c46a74ffSMary Strodl { 215c46a74ffSMary Strodl int err; 216c46a74ffSMary Strodl unsigned long mask = 0, bits = 0; 217c46a74ffSMary Strodl 218c46a74ffSMary Strodl __set_bit(offset, &mask); 219c46a74ffSMary Strodl err = gpio_mpsse_get_multiple(chip, &mask, &bits); 220c46a74ffSMary Strodl if (err) 221c46a74ffSMary Strodl return err; 222c46a74ffSMary Strodl 223c46a74ffSMary Strodl /* == is not guaranteed to give 1 if true */ 224c46a74ffSMary Strodl if (bits) 225c46a74ffSMary Strodl return 1; 226c46a74ffSMary Strodl else 227c46a74ffSMary Strodl return 0; 228c46a74ffSMary Strodl } 229c46a74ffSMary Strodl 230c46a74ffSMary Strodl static void gpio_mpsse_gpio_set(struct gpio_chip *chip, unsigned int offset, 231c46a74ffSMary Strodl int value) 232c46a74ffSMary Strodl { 233c46a74ffSMary Strodl unsigned long mask = 0, bits = 0; 234c46a74ffSMary Strodl 235c46a74ffSMary Strodl __set_bit(offset, &mask); 236c46a74ffSMary Strodl if (value) 237c46a74ffSMary Strodl __set_bit(offset, &bits); 238c46a74ffSMary Strodl 239c46a74ffSMary Strodl gpio_mpsse_set_multiple(chip, &mask, &bits); 240c46a74ffSMary Strodl } 241c46a74ffSMary Strodl 242c46a74ffSMary Strodl static int gpio_mpsse_direction_output(struct gpio_chip *chip, 243c46a74ffSMary Strodl unsigned int offset, int value) 244c46a74ffSMary Strodl { 245c46a74ffSMary Strodl struct mpsse_priv *priv = gpiochip_get_data(chip); 246c46a74ffSMary Strodl int bank = (offset & 8) >> 3; 247c46a74ffSMary Strodl int bank_offset = offset & 7; 248c46a74ffSMary Strodl 249c46a74ffSMary Strodl scoped_guard(mutex, &priv->io_mutex) 250c46a74ffSMary Strodl priv->gpio_dir[bank] |= BIT(bank_offset); 251c46a74ffSMary Strodl 252c46a74ffSMary Strodl gpio_mpsse_gpio_set(chip, offset, value); 253c46a74ffSMary Strodl 254c46a74ffSMary Strodl return 0; 255c46a74ffSMary Strodl } 256c46a74ffSMary Strodl 257c46a74ffSMary Strodl static int gpio_mpsse_direction_input(struct gpio_chip *chip, 258c46a74ffSMary Strodl unsigned int offset) 259c46a74ffSMary Strodl { 260c46a74ffSMary Strodl struct mpsse_priv *priv = gpiochip_get_data(chip); 261c46a74ffSMary Strodl int bank = (offset & 8) >> 3; 262c46a74ffSMary Strodl int bank_offset = offset & 7; 263c46a74ffSMary Strodl 264c46a74ffSMary Strodl guard(mutex)(&priv->io_mutex); 265c46a74ffSMary Strodl priv->gpio_dir[bank] &= ~BIT(bank_offset); 266c46a74ffSMary Strodl gpio_mpsse_set_bank(priv, bank); 267c46a74ffSMary Strodl 268c46a74ffSMary Strodl return 0; 269c46a74ffSMary Strodl } 270c46a74ffSMary Strodl 271c46a74ffSMary Strodl static int gpio_mpsse_get_direction(struct gpio_chip *chip, 272c46a74ffSMary Strodl unsigned int offset) 273c46a74ffSMary Strodl { 274c46a74ffSMary Strodl int ret; 275c46a74ffSMary Strodl int bank = (offset & 8) >> 3; 276c46a74ffSMary Strodl int bank_offset = offset & 7; 277c46a74ffSMary Strodl struct mpsse_priv *priv = gpiochip_get_data(chip); 278c46a74ffSMary Strodl 279c46a74ffSMary Strodl guard(mutex)(&priv->io_mutex); 280c46a74ffSMary Strodl /* MPSSE directions are inverted */ 281c46a74ffSMary Strodl if (priv->gpio_dir[bank] & BIT(bank_offset)) 282c46a74ffSMary Strodl ret = GPIO_LINE_DIRECTION_OUT; 283c46a74ffSMary Strodl else 284c46a74ffSMary Strodl ret = GPIO_LINE_DIRECTION_IN; 285c46a74ffSMary Strodl 286c46a74ffSMary Strodl return ret; 287c46a74ffSMary Strodl } 288c46a74ffSMary Strodl 289c46a74ffSMary Strodl static void gpio_mpsse_poll(struct work_struct *work) 290c46a74ffSMary Strodl { 291c46a74ffSMary Strodl unsigned long pin_mask, pin_states, flags; 292c46a74ffSMary Strodl int irq_enabled, offset, err, value, fire_irq, 293c46a74ffSMary Strodl irq, old_value[16], irq_type[16]; 294c46a74ffSMary Strodl struct mpsse_priv *priv = container_of(work, struct mpsse_priv, 295c46a74ffSMary Strodl irq_work); 296c46a74ffSMary Strodl 297c46a74ffSMary Strodl for (offset = 0; offset < priv->gpio.ngpio; ++offset) 298c46a74ffSMary Strodl old_value[offset] = -1; 299c46a74ffSMary Strodl 300c46a74ffSMary Strodl while ((irq_enabled = atomic_read(&priv->irq_enabled))) { 301c46a74ffSMary Strodl usleep_range(MPSSE_POLL_INTERVAL, MPSSE_POLL_INTERVAL + 1000); 302c46a74ffSMary Strodl /* Cleanup will trigger at the end of the loop */ 303c46a74ffSMary Strodl guard(mutex)(&priv->irq_mutex); 304c46a74ffSMary Strodl 305c46a74ffSMary Strodl pin_mask = 0; 306c46a74ffSMary Strodl pin_states = 0; 307c46a74ffSMary Strodl for (offset = 0; offset < priv->gpio.ngpio; ++offset) { 308c46a74ffSMary Strodl irq_type[offset] = atomic_read(&priv->irq_type[offset]); 309c46a74ffSMary Strodl if (irq_type[offset] != IRQ_TYPE_NONE && 310c46a74ffSMary Strodl irq_enabled & BIT(offset)) 311c46a74ffSMary Strodl pin_mask |= BIT(offset); 312c46a74ffSMary Strodl else 313c46a74ffSMary Strodl old_value[offset] = -1; 314c46a74ffSMary Strodl } 315c46a74ffSMary Strodl 316c46a74ffSMary Strodl err = gpio_mpsse_get_multiple(&priv->gpio, &pin_mask, 317c46a74ffSMary Strodl &pin_states); 318c46a74ffSMary Strodl if (err) { 319c46a74ffSMary Strodl dev_err_ratelimited(&priv->intf->dev, 320c46a74ffSMary Strodl "Error polling!\n"); 321c46a74ffSMary Strodl continue; 322c46a74ffSMary Strodl } 323c46a74ffSMary Strodl 324c46a74ffSMary Strodl /* Check each value */ 325c46a74ffSMary Strodl for (offset = 0; offset < priv->gpio.ngpio; ++offset) { 326c46a74ffSMary Strodl if (old_value[offset] == -1) 327c46a74ffSMary Strodl continue; 328c46a74ffSMary Strodl 329c46a74ffSMary Strodl fire_irq = 0; 330c46a74ffSMary Strodl value = pin_states & BIT(offset); 331c46a74ffSMary Strodl 332c46a74ffSMary Strodl switch (irq_type[offset]) { 333c46a74ffSMary Strodl case IRQ_TYPE_EDGE_RISING: 334c46a74ffSMary Strodl fire_irq = value > old_value[offset]; 335c46a74ffSMary Strodl break; 336c46a74ffSMary Strodl case IRQ_TYPE_EDGE_FALLING: 337c46a74ffSMary Strodl fire_irq = value < old_value[offset]; 338c46a74ffSMary Strodl break; 339c46a74ffSMary Strodl case IRQ_TYPE_EDGE_BOTH: 340c46a74ffSMary Strodl fire_irq = value != old_value[offset]; 341c46a74ffSMary Strodl break; 342c46a74ffSMary Strodl } 343c46a74ffSMary Strodl if (!fire_irq) 344c46a74ffSMary Strodl continue; 345c46a74ffSMary Strodl 346c46a74ffSMary Strodl irq = irq_find_mapping(priv->gpio.irq.domain, 347c46a74ffSMary Strodl offset); 348c46a74ffSMary Strodl local_irq_save(flags); 349c46a74ffSMary Strodl generic_handle_irq(irq); 350c46a74ffSMary Strodl local_irq_disable(); 351c46a74ffSMary Strodl local_irq_restore(flags); 352c46a74ffSMary Strodl } 353c46a74ffSMary Strodl 354c46a74ffSMary Strodl /* Sync back values so we can refer to them next tick */ 355c46a74ffSMary Strodl for (offset = 0; offset < priv->gpio.ngpio; ++offset) 356c46a74ffSMary Strodl if (irq_type[offset] != IRQ_TYPE_NONE && 357c46a74ffSMary Strodl irq_enabled & BIT(offset)) 358c46a74ffSMary Strodl old_value[offset] = pin_states & BIT(offset); 359c46a74ffSMary Strodl } 360c46a74ffSMary Strodl } 361c46a74ffSMary Strodl 362c46a74ffSMary Strodl static int gpio_mpsse_set_irq_type(struct irq_data *irqd, unsigned int type) 363c46a74ffSMary Strodl { 364c46a74ffSMary Strodl int offset; 365c46a74ffSMary Strodl struct mpsse_priv *priv = irq_data_get_irq_chip_data(irqd); 366c46a74ffSMary Strodl 367c46a74ffSMary Strodl offset = irqd->hwirq; 368c46a74ffSMary Strodl atomic_set(&priv->irq_type[offset], type & IRQ_TYPE_EDGE_BOTH); 369c46a74ffSMary Strodl 370c46a74ffSMary Strodl return 0; 371c46a74ffSMary Strodl } 372c46a74ffSMary Strodl 373c46a74ffSMary Strodl static void gpio_mpsse_irq_disable(struct irq_data *irqd) 374c46a74ffSMary Strodl { 375c46a74ffSMary Strodl struct mpsse_priv *priv = irq_data_get_irq_chip_data(irqd); 376c46a74ffSMary Strodl 377c46a74ffSMary Strodl atomic_and(~BIT(irqd->hwirq), &priv->irq_enabled); 378c46a74ffSMary Strodl gpiochip_disable_irq(&priv->gpio, irqd->hwirq); 379c46a74ffSMary Strodl } 380c46a74ffSMary Strodl 381c46a74ffSMary Strodl static void gpio_mpsse_irq_enable(struct irq_data *irqd) 382c46a74ffSMary Strodl { 383c46a74ffSMary Strodl struct mpsse_priv *priv = irq_data_get_irq_chip_data(irqd); 384c46a74ffSMary Strodl 385c46a74ffSMary Strodl gpiochip_enable_irq(&priv->gpio, irqd->hwirq); 386c46a74ffSMary Strodl /* If no-one else was using the IRQ, enable it */ 387c46a74ffSMary Strodl if (!atomic_fetch_or(BIT(irqd->hwirq), &priv->irq_enabled)) { 388c46a74ffSMary Strodl INIT_WORK(&priv->irq_work, gpio_mpsse_poll); 389c46a74ffSMary Strodl schedule_work(&priv->irq_work); 390c46a74ffSMary Strodl } 391c46a74ffSMary Strodl } 392c46a74ffSMary Strodl 393c46a74ffSMary Strodl static const struct irq_chip gpio_mpsse_irq_chip = { 394c46a74ffSMary Strodl .name = "gpio-mpsse-irq", 395c46a74ffSMary Strodl .irq_enable = gpio_mpsse_irq_enable, 396c46a74ffSMary Strodl .irq_disable = gpio_mpsse_irq_disable, 397c46a74ffSMary Strodl .irq_set_type = gpio_mpsse_set_irq_type, 398c46a74ffSMary Strodl .flags = IRQCHIP_IMMUTABLE, 399c46a74ffSMary Strodl GPIOCHIP_IRQ_RESOURCE_HELPERS, 400c46a74ffSMary Strodl }; 401c46a74ffSMary Strodl 402c46a74ffSMary Strodl static void gpio_mpsse_ida_remove(void *data) 403c46a74ffSMary Strodl { 404c46a74ffSMary Strodl struct mpsse_priv *priv = data; 405c46a74ffSMary Strodl 406*f57c0849SChristophe JAILLET ida_free(&gpio_mpsse_ida, priv->id); 407c46a74ffSMary Strodl } 408c46a74ffSMary Strodl 409c46a74ffSMary Strodl static int gpio_mpsse_probe(struct usb_interface *interface, 410c46a74ffSMary Strodl const struct usb_device_id *id) 411c46a74ffSMary Strodl { 412c46a74ffSMary Strodl struct mpsse_priv *priv; 413c46a74ffSMary Strodl struct device *dev; 414c46a74ffSMary Strodl int err; 415c46a74ffSMary Strodl 416c46a74ffSMary Strodl dev = &interface->dev; 417c46a74ffSMary Strodl priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 418c46a74ffSMary Strodl if (!priv) 419c46a74ffSMary Strodl return -ENOMEM; 420c46a74ffSMary Strodl 421c46a74ffSMary Strodl priv->udev = usb_get_dev(interface_to_usbdev(interface)); 422c46a74ffSMary Strodl priv->intf = interface; 423c46a74ffSMary Strodl priv->intf_id = interface->cur_altsetting->desc.bInterfaceNumber; 424c46a74ffSMary Strodl 425*f57c0849SChristophe JAILLET priv->id = ida_alloc(&gpio_mpsse_ida, GFP_KERNEL); 426c46a74ffSMary Strodl if (priv->id < 0) 427c46a74ffSMary Strodl return priv->id; 428c46a74ffSMary Strodl 429c46a74ffSMary Strodl err = devm_add_action_or_reset(dev, gpio_mpsse_ida_remove, priv); 430c46a74ffSMary Strodl if (err) 431c46a74ffSMary Strodl return err; 432c46a74ffSMary Strodl 4335e3eedf5SAndy Shevchenko err = devm_mutex_init(dev, &priv->io_mutex); 4345e3eedf5SAndy Shevchenko if (err) 4355e3eedf5SAndy Shevchenko return err; 4365e3eedf5SAndy Shevchenko 4375e3eedf5SAndy Shevchenko err = devm_mutex_init(dev, &priv->irq_mutex); 4385e3eedf5SAndy Shevchenko if (err) 4395e3eedf5SAndy Shevchenko return err; 440c46a74ffSMary Strodl 441c46a74ffSMary Strodl priv->gpio.label = devm_kasprintf(dev, GFP_KERNEL, 442c46a74ffSMary Strodl "gpio-mpsse.%d.%d", 443c46a74ffSMary Strodl priv->id, priv->intf_id); 444c46a74ffSMary Strodl if (!priv->gpio.label) 445c46a74ffSMary Strodl return -ENOMEM; 446c46a74ffSMary Strodl 447c46a74ffSMary Strodl priv->gpio.owner = THIS_MODULE; 448c46a74ffSMary Strodl priv->gpio.parent = interface->usb_dev; 449c46a74ffSMary Strodl priv->gpio.get_direction = gpio_mpsse_get_direction; 450c46a74ffSMary Strodl priv->gpio.direction_input = gpio_mpsse_direction_input; 451c46a74ffSMary Strodl priv->gpio.direction_output = gpio_mpsse_direction_output; 452c46a74ffSMary Strodl priv->gpio.get = gpio_mpsse_gpio_get; 453c46a74ffSMary Strodl priv->gpio.set = gpio_mpsse_gpio_set; 454c46a74ffSMary Strodl priv->gpio.get_multiple = gpio_mpsse_get_multiple; 455c46a74ffSMary Strodl priv->gpio.set_multiple = gpio_mpsse_set_multiple; 456c46a74ffSMary Strodl priv->gpio.base = -1; 457c46a74ffSMary Strodl priv->gpio.ngpio = 16; 458c46a74ffSMary Strodl priv->gpio.offset = priv->intf_id * priv->gpio.ngpio; 459c46a74ffSMary Strodl priv->gpio.can_sleep = 1; 460c46a74ffSMary Strodl 461c46a74ffSMary Strodl err = usb_find_common_endpoints(interface->cur_altsetting, 462c46a74ffSMary Strodl &priv->bulk_in, &priv->bulk_out, 463c46a74ffSMary Strodl NULL, NULL); 464c46a74ffSMary Strodl if (err) 465c46a74ffSMary Strodl return err; 466c46a74ffSMary Strodl 467c46a74ffSMary Strodl priv->bulk_in_buf = devm_kmalloc(dev, usb_endpoint_maxp(priv->bulk_in), 468c46a74ffSMary Strodl GFP_KERNEL); 469c46a74ffSMary Strodl if (!priv->bulk_in_buf) 470c46a74ffSMary Strodl return -ENOMEM; 471c46a74ffSMary Strodl 472c46a74ffSMary Strodl usb_set_intfdata(interface, priv); 473c46a74ffSMary Strodl 474c46a74ffSMary Strodl /* Reset mode, needed to correctly enter MPSSE mode */ 475c46a74ffSMary Strodl err = usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0), 476c46a74ffSMary Strodl SET_BITMODE_REQUEST, 477c46a74ffSMary Strodl USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, 478c46a74ffSMary Strodl MODE_RESET, priv->intf_id + 1, NULL, 0, 479c46a74ffSMary Strodl USB_CTRL_SET_TIMEOUT); 480c46a74ffSMary Strodl if (err) 481c46a74ffSMary Strodl return err; 482c46a74ffSMary Strodl 483c46a74ffSMary Strodl /* Enter MPSSE mode */ 484c46a74ffSMary Strodl err = usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0), 485c46a74ffSMary Strodl SET_BITMODE_REQUEST, 486c46a74ffSMary Strodl USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, 487c46a74ffSMary Strodl MODE_MPSSE, priv->intf_id + 1, NULL, 0, 488c46a74ffSMary Strodl USB_CTRL_SET_TIMEOUT); 489c46a74ffSMary Strodl if (err) 490c46a74ffSMary Strodl return err; 491c46a74ffSMary Strodl 492c46a74ffSMary Strodl gpio_irq_chip_set_chip(&priv->gpio.irq, &gpio_mpsse_irq_chip); 493c46a74ffSMary Strodl 494c46a74ffSMary Strodl priv->gpio.irq.parent_handler = NULL; 495c46a74ffSMary Strodl priv->gpio.irq.num_parents = 0; 496c46a74ffSMary Strodl priv->gpio.irq.parents = NULL; 497c46a74ffSMary Strodl priv->gpio.irq.default_type = IRQ_TYPE_NONE; 498c46a74ffSMary Strodl priv->gpio.irq.handler = handle_simple_irq; 499c46a74ffSMary Strodl 500c46a74ffSMary Strodl err = devm_gpiochip_add_data(dev, &priv->gpio, priv); 501c46a74ffSMary Strodl if (err) 502c46a74ffSMary Strodl return err; 503c46a74ffSMary Strodl 504c46a74ffSMary Strodl return 0; 505c46a74ffSMary Strodl } 506c46a74ffSMary Strodl 507c46a74ffSMary Strodl static void gpio_mpsse_disconnect(struct usb_interface *intf) 508c46a74ffSMary Strodl { 509c46a74ffSMary Strodl struct mpsse_priv *priv = usb_get_intfdata(intf); 510c46a74ffSMary Strodl 511c46a74ffSMary Strodl priv->intf = NULL; 512c46a74ffSMary Strodl usb_set_intfdata(intf, NULL); 513c46a74ffSMary Strodl usb_put_dev(priv->udev); 514c46a74ffSMary Strodl } 515c46a74ffSMary Strodl 516c46a74ffSMary Strodl static struct usb_driver gpio_mpsse_driver = { 517c46a74ffSMary Strodl .name = "gpio-mpsse", 518c46a74ffSMary Strodl .probe = gpio_mpsse_probe, 519c46a74ffSMary Strodl .disconnect = gpio_mpsse_disconnect, 520c46a74ffSMary Strodl .id_table = gpio_mpsse_table, 521c46a74ffSMary Strodl }; 522c46a74ffSMary Strodl 523c46a74ffSMary Strodl module_usb_driver(gpio_mpsse_driver); 524c46a74ffSMary Strodl 525c46a74ffSMary Strodl MODULE_AUTHOR("Mary Strodl <mstrodl@csh.rit.edu>"); 526c46a74ffSMary Strodl MODULE_DESCRIPTION("MPSSE GPIO driver"); 527c46a74ffSMary Strodl MODULE_LICENSE("GPL"); 528