diff options
Diffstat (limited to 'drivers/hid/hid-mcp2221.c')
| -rw-r--r-- | drivers/hid/hid-mcp2221.c | 533 |
1 files changed, 469 insertions, 64 deletions
diff --git a/drivers/hid/hid-mcp2221.c b/drivers/hid/hid-mcp2221.c index 4211b9839209..33603b019f97 100644 --- a/drivers/hid/hid-mcp2221.c +++ b/drivers/hid/hid-mcp2221.c @@ -10,12 +10,15 @@ #include <linux/module.h> #include <linux/err.h> #include <linux/mutex.h> +#include <linux/bitfield.h> #include <linux/completion.h> #include <linux/delay.h> #include <linux/hid.h> #include <linux/hidraw.h> #include <linux/i2c.h> #include <linux/gpio/driver.h> +#include <linux/iio/iio.h> +#include <linux/minmax.h> #include "hid-ids.h" /* Commands codes in a raw output report */ @@ -30,6 +33,9 @@ enum { MCP2221_I2C_CANCEL = 0x10, MCP2221_GPIO_SET = 0x50, MCP2221_GPIO_GET = 0x51, + MCP2221_SET_SRAM_SETTINGS = 0x60, + MCP2221_GET_SRAM_SETTINGS = 0x61, + MCP2221_READ_FLASH_DATA = 0xb0, }; /* Response codes in a raw input report */ @@ -44,11 +50,33 @@ enum { MCP2221_I2C_MASK_ADDR_NACK = 0x40, MCP2221_I2C_WRADDRL_SEND = 0x21, MCP2221_I2C_ADDR_NACK = 0x25, + MCP2221_I2C_READ_PARTIAL = 0x54, MCP2221_I2C_READ_COMPL = 0x55, MCP2221_ALT_F_NOT_GPIOV = 0xEE, MCP2221_ALT_F_NOT_GPIOD = 0xEF, }; +/* MCP SRAM read offsets cmd: MCP2221_GET_SRAM_SETTINGS */ +enum { + MCP2221_SRAM_RD_GP0 = 22, + MCP2221_SRAM_RD_GP1 = 23, + MCP2221_SRAM_RD_GP2 = 24, + MCP2221_SRAM_RD_GP3 = 25, +}; + +/* MCP SRAM write offsets cmd: MCP2221_SET_SRAM_SETTINGS */ +enum { + MCP2221_SRAM_WR_GP_ENA_ALTER = 7, + MCP2221_SRAM_WR_GP0 = 8, + MCP2221_SRAM_WR_GP1 = 9, + MCP2221_SRAM_WR_GP2 = 10, + MCP2221_SRAM_WR_GP3 = 11, +}; + +#define MCP2221_SRAM_GP_DESIGN_MASK 0x07 +#define MCP2221_SRAM_GP_DIRECTION_MASK 0x08 +#define MCP2221_SRAM_GP_VALUE_MASK 0x10 + /* MCP GPIO direction encoding */ enum { MCP2221_DIR_OUT = 0x00, @@ -74,8 +102,8 @@ struct mcp_get_gpio { u8 cmd; u8 dummy; struct { - u8 direction; u8 value; + u8 direction; } gpio[MCP_NGPIO]; } __packed; @@ -89,6 +117,7 @@ struct mcp2221 { struct i2c_adapter adapter; struct mutex lock; struct completion wait_in_report; + struct delayed_work init_work; u8 *rxbuf; u8 txbuf[64]; int rxbuf_idx; @@ -97,6 +126,18 @@ struct mcp2221 { struct gpio_chip *gc; u8 gp_idx; u8 gpio_dir; + u8 mode[4]; +#if IS_REACHABLE(CONFIG_IIO) + struct iio_chan_spec iio_channels[3]; + u16 adc_values[3]; + u8 adc_scale; + u8 dac_value; + u16 dac_scale; +#endif +}; + +struct mcp2221_iio { + struct mcp2221 *mcp; }; /* @@ -169,6 +210,25 @@ static int mcp_cancel_last_cmd(struct mcp2221 *mcp) return mcp_send_data_req_status(mcp, mcp->txbuf, 8); } +/* Check if the last command succeeded or failed and return the result. + * If the command did fail, cancel that command which will free the i2c bus. + */ +static int mcp_chk_last_cmd_status_free_bus(struct mcp2221 *mcp) +{ + int ret; + + ret = mcp_chk_last_cmd_status(mcp); + if (ret) { + /* The last command was a failure. + * Send a cancel which will also free the bus. + */ + usleep_range(980, 1000); + mcp_cancel_last_cmd(mcp); + } + + return ret; +} + static int mcp_set_i2c_speed(struct mcp2221 *mcp) { int ret; @@ -203,10 +263,7 @@ static int mcp_i2c_write(struct mcp2221 *mcp, idx = 0; sent = 0; - if (msg->len < 60) - len = msg->len; - else - len = 60; + len = min(msg->len, 60); do { mcp->txbuf[0] = type; @@ -223,7 +280,7 @@ static int mcp_i2c_write(struct mcp2221 *mcp, usleep_range(980, 1000); if (last_status) { - ret = mcp_chk_last_cmd_status(mcp); + ret = mcp_chk_last_cmd_status_free_bus(mcp); if (ret) return ret; } @@ -233,10 +290,7 @@ static int mcp_i2c_write(struct mcp2221 *mcp, break; idx = idx + len; - if ((msg->len - sent) < 60) - len = msg->len - sent; - else - len = 60; + len = min(msg->len - sent, 60); /* * Testing shows delay is needed between successive writes @@ -260,6 +314,7 @@ static int mcp_i2c_smbus_read(struct mcp2221 *mcp, { int ret; u16 total_len; + int retries = 0; mcp->txbuf[0] = type; if (msg) { @@ -283,20 +338,31 @@ static int mcp_i2c_smbus_read(struct mcp2221 *mcp, mcp->rxbuf_idx = 0; do { + /* Wait for the data to be read by the device */ + usleep_range(980, 1000); + memset(mcp->txbuf, 0, 4); mcp->txbuf[0] = MCP2221_I2C_GET_DATA; ret = mcp_send_data_req_status(mcp, mcp->txbuf, 1); - if (ret) - return ret; - - ret = mcp_chk_last_cmd_status(mcp); - if (ret) - return ret; - - usleep_range(980, 1000); + if (ret) { + if (retries < 5) { + /* The data wasn't ready to read. + * Wait a bit longer and try again. + */ + usleep_range(90, 100); + retries++; + } else { + return ret; + } + } else { + retries = 0; + } } while (mcp->rxbuf_idx < total_len); + usleep_range(980, 1000); + ret = mcp_chk_last_cmd_status_free_bus(mcp); + return ret; } @@ -310,11 +376,6 @@ static int mcp_i2c_xfer(struct i2c_adapter *adapter, mutex_lock(&mcp->lock); - /* Setting speed before every transaction is required for mcp2221 */ - ret = mcp_set_i2c_speed(mcp); - if (ret) - goto exit; - if (num == 1) { if (msgs->flags & I2C_M_RD) { ret = mcp_i2c_smbus_read(mcp, msgs, MCP2221_I2C_RD_DATA, @@ -385,6 +446,9 @@ static int mcp_smbus_write(struct mcp2221 *mcp, u16 addr, data_len = 7; break; default: + if (len > I2C_SMBUS_BLOCK_MAX) + return -EINVAL; + memcpy(&mcp->txbuf[5], buf, len); data_len = len + 5; } @@ -396,9 +460,7 @@ static int mcp_smbus_write(struct mcp2221 *mcp, u16 addr, if (last_status) { usleep_range(980, 1000); - ret = mcp_chk_last_cmd_status(mcp); - if (ret) - return ret; + ret = mcp_chk_last_cmd_status_free_bus(mcp); } return ret; @@ -416,10 +478,6 @@ static int mcp_smbus_xfer(struct i2c_adapter *adapter, u16 addr, mutex_lock(&mcp->lock); - ret = mcp_set_i2c_speed(mcp); - if (ret) - goto exit; - switch (size) { case I2C_SMBUS_QUICK: @@ -564,6 +622,81 @@ static const struct i2c_algorithm mcp_i2c_algo = { .functionality = mcp_i2c_func, }; +#if IS_REACHABLE(CONFIG_GPIOLIB) +static int mcp_gpio_read_sram(struct mcp2221 *mcp) +{ + int ret; + + memset(mcp->txbuf, 0, 64); + mcp->txbuf[0] = MCP2221_GET_SRAM_SETTINGS; + + mutex_lock(&mcp->lock); + ret = mcp_send_data_req_status(mcp, mcp->txbuf, 64); + mutex_unlock(&mcp->lock); + + return ret; +} + +/* + * If CONFIG_IIO is not enabled, check for the gpio pins + * if they are in gpio mode. For the ones which are not + * in gpio mode, set them into gpio mode. + */ +static int mcp2221_check_gpio_pinfunc(struct mcp2221 *mcp) +{ + int i; + int needgpiofix = 0; + int ret; + + if (IS_ENABLED(CONFIG_IIO)) + return 0; + + ret = mcp_gpio_read_sram(mcp); + if (ret) + return ret; + + for (i = 0; i < MCP_NGPIO; i++) { + if ((mcp->mode[i] & MCP2221_SRAM_GP_DESIGN_MASK) != 0x0) { + dev_warn(&mcp->hdev->dev, + "GPIO %d not in gpio mode\n", i); + needgpiofix = 1; + } + } + + if (!needgpiofix) + return 0; + + /* + * Set all bytes to 0, so Bit 7 is not set. The chip + * only changes content of a register when bit 7 is set. + */ + memset(mcp->txbuf, 0, 64); + mcp->txbuf[0] = MCP2221_SET_SRAM_SETTINGS; + + /* + * Set bit 7 in MCP2221_SRAM_WR_GP_ENA_ALTER to enable + * loading of a new set of gpio settings to GP SRAM + */ + mcp->txbuf[MCP2221_SRAM_WR_GP_ENA_ALTER] = 0x80; + for (i = 0; i < MCP_NGPIO; i++) { + if ((mcp->mode[i] & MCP2221_SRAM_GP_DESIGN_MASK) == 0x0) { + /* write current GPIO mode */ + mcp->txbuf[MCP2221_SRAM_WR_GP0 + i] = mcp->mode[i]; + } else { + /* pin is not in gpio mode, set it to input mode */ + mcp->txbuf[MCP2221_SRAM_WR_GP0 + i] = 0x08; + dev_warn(&mcp->hdev->dev, + "Set GPIO mode for gpio pin %d!\n", i); + } + } + + mutex_lock(&mcp->lock); + ret = mcp_send_data_req_status(mcp, mcp->txbuf, 64); + mutex_unlock(&mcp->lock); + + return ret; +} + static int mcp_gpio_get(struct gpio_chip *gc, unsigned int offset) { @@ -572,7 +705,7 @@ static int mcp_gpio_get(struct gpio_chip *gc, mcp->txbuf[0] = MCP2221_GPIO_GET; - mcp->gp_idx = offsetof(struct mcp_get_gpio, gpio[offset].value); + mcp->gp_idx = offsetof(struct mcp_get_gpio, gpio[offset]); mutex_lock(&mcp->lock); ret = mcp_send_data_req_status(mcp, mcp->txbuf, 1); @@ -581,10 +714,10 @@ static int mcp_gpio_get(struct gpio_chip *gc, return ret; } -static void mcp_gpio_set(struct gpio_chip *gc, - unsigned int offset, int value) +static int mcp_gpio_set(struct gpio_chip *gc, unsigned int offset, int value) { struct mcp2221 *mcp = gpiochip_get_data(gc); + int ret; memset(mcp->txbuf, 0, 18); mcp->txbuf[0] = MCP2221_GPIO_SET; @@ -595,8 +728,10 @@ static void mcp_gpio_set(struct gpio_chip *gc, mcp->txbuf[mcp->gp_idx] = !!value; mutex_lock(&mcp->lock); - mcp_send_data_req_status(mcp, mcp->txbuf, 18); + ret = mcp_send_data_req_status(mcp, mcp->txbuf, 18); mutex_unlock(&mcp->lock); + + return ret; } static int mcp_gpio_dir_set(struct mcp2221 *mcp, @@ -653,7 +788,7 @@ static int mcp_gpio_get_direction(struct gpio_chip *gc, mcp->txbuf[0] = MCP2221_GPIO_GET; - mcp->gp_idx = offsetof(struct mcp_get_gpio, gpio[offset].direction); + mcp->gp_idx = offsetof(struct mcp_get_gpio, gpio[offset]); mutex_lock(&mcp->lock); ret = mcp_send_data_req_status(mcp, mcp->txbuf, 1); @@ -667,6 +802,7 @@ static int mcp_gpio_get_direction(struct gpio_chip *gc, return GPIO_LINE_DIRECTION_OUT; } +#endif /* Gives current state of i2c engine inside mcp2221 */ static int mcp_get_i2c_eng_state(struct mcp2221 *mcp, @@ -742,6 +878,9 @@ static int mcp2221_raw_event(struct hid_device *hdev, break; } mcp->status = mcp_get_i2c_eng_state(mcp, data, 8); +#if IS_REACHABLE(CONFIG_IIO) + memcpy(&mcp->adc_values, &data[50], sizeof(mcp->adc_values)); +#endif break; default: mcp->status = -EIO; @@ -765,7 +904,12 @@ static int mcp2221_raw_event(struct hid_device *hdev, mcp->status = -EIO; break; } - if (data[2] == MCP2221_I2C_READ_COMPL) { + if (data[2] == MCP2221_I2C_READ_COMPL || + data[2] == MCP2221_I2C_READ_PARTIAL) { + if (!mcp->rxbuf || mcp->rxbuf_idx < 0 || data[3] > 60) { + mcp->status = -EINVAL; + break; + } buf = mcp->rxbuf; memcpy(&buf[mcp->rxbuf_idx], &data[4], data[3]); mcp->rxbuf_idx = mcp->rxbuf_idx + data[3]; @@ -813,6 +957,69 @@ static int mcp2221_raw_event(struct hid_device *hdev, complete(&mcp->wait_in_report); break; + case MCP2221_SET_SRAM_SETTINGS: + switch (data[1]) { + case MCP2221_SUCCESS: + mcp->status = 0; + break; + default: + mcp->status = -EAGAIN; + } + complete(&mcp->wait_in_report); + break; + + case MCP2221_GET_SRAM_SETTINGS: + switch (data[1]) { + case MCP2221_SUCCESS: + memcpy(&mcp->mode, &data[22], 4); +#if IS_REACHABLE(CONFIG_IIO) + mcp->dac_value = data[6] & GENMASK(4, 0); +#endif + mcp->status = 0; + break; + default: + mcp->status = -EAGAIN; + } + complete(&mcp->wait_in_report); + break; + + case MCP2221_READ_FLASH_DATA: + switch (data[1]) { + case MCP2221_SUCCESS: + mcp->status = 0; + + /* Only handles CHIP SETTINGS subpage currently */ + if (mcp->txbuf[1] != 0) { + mcp->status = -EIO; + break; + } + +#if IS_REACHABLE(CONFIG_IIO) + { + u8 tmp; + /* DAC scale value */ + tmp = FIELD_GET(GENMASK(7, 6), data[6]); + if ((data[6] & BIT(5)) && tmp) + mcp->dac_scale = tmp + 4; + else + mcp->dac_scale = 5; + + /* ADC scale value */ + tmp = FIELD_GET(GENMASK(4, 3), data[7]); + if ((data[7] & BIT(2)) && tmp) + mcp->adc_scale = tmp - 1; + else + mcp->adc_scale = 0; + } +#endif + + break; + default: + mcp->status = -EAGAIN; + } + complete(&mcp->wait_in_report); + break; + default: mcp->status = -EIO; complete(&mcp->wait_in_report); @@ -821,6 +1028,195 @@ static int mcp2221_raw_event(struct hid_device *hdev, return 1; } +/* Device resource managed function for HID unregistration */ +static void mcp2221_hid_unregister(void *ptr) +{ + struct hid_device *hdev = ptr; + + hid_hw_close(hdev); + hid_hw_stop(hdev); +} + +/* This is needed to be sure hid_hw_stop() isn't called twice by the subsystem */ +static void mcp2221_remove(struct hid_device *hdev) +{ +#if IS_REACHABLE(CONFIG_IIO) + struct mcp2221 *mcp = hid_get_drvdata(hdev); + + cancel_delayed_work_sync(&mcp->init_work); +#endif +} + +#if IS_REACHABLE(CONFIG_IIO) +static int mcp2221_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *channel, int *val, + int *val2, long mask) +{ + struct mcp2221_iio *priv = iio_priv(indio_dev); + struct mcp2221 *mcp = priv->mcp; + int ret; + + if (mask == IIO_CHAN_INFO_SCALE) { + if (channel->output) + *val = 1 << mcp->dac_scale; + else + *val = 1 << mcp->adc_scale; + + return IIO_VAL_INT; + } + + mutex_lock(&mcp->lock); + + if (channel->output) { + *val = mcp->dac_value; + ret = IIO_VAL_INT; + } else { + /* Read ADC values */ + ret = mcp_chk_last_cmd_status(mcp); + + if (!ret) { + *val = le16_to_cpu((__force __le16) mcp->adc_values[channel->address]); + if (*val >= BIT(10)) + ret = -EINVAL; + else + ret = IIO_VAL_INT; + } + } + + mutex_unlock(&mcp->lock); + + return ret; +} + +static int mcp2221_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct mcp2221_iio *priv = iio_priv(indio_dev); + struct mcp2221 *mcp = priv->mcp; + int ret; + + if (val < 0 || val >= BIT(5)) + return -EINVAL; + + mutex_lock(&mcp->lock); + + memset(mcp->txbuf, 0, 12); + mcp->txbuf[0] = MCP2221_SET_SRAM_SETTINGS; + mcp->txbuf[4] = BIT(7) | val; + + ret = mcp_send_data_req_status(mcp, mcp->txbuf, 12); + if (!ret) + mcp->dac_value = val; + + mutex_unlock(&mcp->lock); + + return ret; +} + +static const struct iio_info mcp2221_info = { + .read_raw = &mcp2221_read_raw, + .write_raw = &mcp2221_write_raw, +}; + +static int mcp_iio_channels(struct mcp2221 *mcp) +{ + int idx, cnt = 0; + bool dac_created = false; + + /* GP0 doesn't have ADC/DAC alternative function */ + for (idx = 1; idx < MCP_NGPIO; idx++) { + struct iio_chan_spec *chan = &mcp->iio_channels[cnt]; + + switch (mcp->mode[idx]) { + case 2: + chan->address = idx - 1; + chan->channel = cnt++; + break; + case 3: + /* GP1 doesn't have DAC alternative function */ + if (idx == 1 || dac_created) + continue; + /* DAC1 and DAC2 outputs are connected to the same DAC */ + dac_created = true; + chan->output = 1; + cnt++; + break; + default: + continue; + } + + chan->type = IIO_VOLTAGE; + chan->indexed = 1; + chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW); + chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE); + chan->scan_index = -1; + } + + return cnt; +} + +static void mcp_init_work(struct work_struct *work) +{ + struct iio_dev *indio_dev; + struct mcp2221 *mcp = container_of(work, struct mcp2221, init_work.work); + struct mcp2221_iio *data; + static int retries = 5; + int ret, num_channels; + + hid_hw_power(mcp->hdev, PM_HINT_FULLON); + mutex_lock(&mcp->lock); + + mcp->txbuf[0] = MCP2221_GET_SRAM_SETTINGS; + ret = mcp_send_data_req_status(mcp, mcp->txbuf, 1); + + if (ret == -EAGAIN) + goto reschedule_task; + + num_channels = mcp_iio_channels(mcp); + if (!num_channels) + goto unlock; + + mcp->txbuf[0] = MCP2221_READ_FLASH_DATA; + mcp->txbuf[1] = 0; + ret = mcp_send_data_req_status(mcp, mcp->txbuf, 2); + + if (ret == -EAGAIN) + goto reschedule_task; + + indio_dev = devm_iio_device_alloc(&mcp->hdev->dev, sizeof(*data)); + if (!indio_dev) + goto unlock; + + data = iio_priv(indio_dev); + data->mcp = mcp; + + indio_dev->name = "mcp2221"; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &mcp2221_info; + indio_dev->channels = mcp->iio_channels; + indio_dev->num_channels = num_channels; + + devm_iio_device_register(&mcp->hdev->dev, indio_dev); + +unlock: + mutex_unlock(&mcp->lock); + hid_hw_power(mcp->hdev, PM_HINT_NORMAL); + + return; + +reschedule_task: + mutex_unlock(&mcp->lock); + hid_hw_power(mcp->hdev, PM_HINT_NORMAL); + + if (!retries--) + return; + + /* Device is not ready to read SRAM or FLASH data, try again */ + schedule_delayed_work(&mcp->init_work, msecs_to_jiffies(100)); +} +#endif + static int mcp2221_probe(struct hid_device *hdev, const struct hid_device_id *id) { @@ -837,16 +1233,24 @@ static int mcp2221_probe(struct hid_device *hdev, return ret; } - ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); + /* + * This driver uses the .raw_event callback and therefore does not need any + * HID_CONNECT_xxx flags. + */ + ret = hid_hw_start(hdev, 0); if (ret) { hid_err(hdev, "can't start hardware\n"); return ret; } + hid_info(hdev, "USB HID v%x.%02x Device [%s] on %s\n", hdev->version >> 8, + hdev->version & 0xff, hdev->name, hdev->phys); + ret = hid_hw_open(hdev); if (ret) { hid_err(hdev, "can't open device\n"); - goto err_hstop; + hid_hw_stop(hdev); + return ret; } mutex_init(&mcp->lock); @@ -854,35 +1258,45 @@ static int mcp2221_probe(struct hid_device *hdev, hid_set_drvdata(hdev, mcp); mcp->hdev = hdev; + ret = devm_add_action_or_reset(&hdev->dev, mcp2221_hid_unregister, hdev); + if (ret) + return ret; + + hid_device_io_start(hdev); + /* Set I2C bus clock diviser */ if (i2c_clk_freq > 400) i2c_clk_freq = 400; if (i2c_clk_freq < 50) i2c_clk_freq = 50; mcp->cur_i2c_clk_div = (12000000 / (i2c_clk_freq * 1000)) - 3; + ret = mcp_set_i2c_speed(mcp); + if (ret) { + hid_err(hdev, "can't set i2c speed: %d\n", ret); + return ret; + } mcp->adapter.owner = THIS_MODULE; mcp->adapter.class = I2C_CLASS_HWMON; mcp->adapter.algo = &mcp_i2c_algo; mcp->adapter.retries = 1; mcp->adapter.dev.parent = &hdev->dev; + ACPI_COMPANION_SET(&mcp->adapter.dev, ACPI_COMPANION(hdev->dev.parent)); snprintf(mcp->adapter.name, sizeof(mcp->adapter.name), - "MCP2221 usb-i2c bridge on hidraw%d", - ((struct hidraw *)hdev->hidraw)->minor); + "MCP2221 usb-i2c bridge"); - ret = i2c_add_adapter(&mcp->adapter); + i2c_set_adapdata(&mcp->adapter, mcp); + ret = devm_i2c_add_adapter(&hdev->dev, &mcp->adapter); if (ret) { hid_err(hdev, "can't add usb-i2c adapter: %d\n", ret); - goto err_i2c; + return ret; } - i2c_set_adapdata(&mcp->adapter, mcp); +#if IS_REACHABLE(CONFIG_GPIOLIB) /* Setup GPIO chip */ mcp->gc = devm_kzalloc(&hdev->dev, sizeof(*mcp->gc), GFP_KERNEL); - if (!mcp->gc) { - ret = -ENOMEM; - goto err_gc; - } + if (!mcp->gc) + return -ENOMEM; mcp->gc->label = "mcp2221_gpio"; mcp->gc->direction_input = mcp_gpio_direction_input; @@ -897,26 +1311,17 @@ static int mcp2221_probe(struct hid_device *hdev, ret = devm_gpiochip_add_data(&hdev->dev, mcp->gc, mcp); if (ret) - goto err_gc; - - return 0; + return ret; -err_gc: - i2c_del_adapter(&mcp->adapter); -err_i2c: - hid_hw_close(mcp->hdev); -err_hstop: - hid_hw_stop(mcp->hdev); - return ret; -} + mcp2221_check_gpio_pinfunc(mcp); +#endif -static void mcp2221_remove(struct hid_device *hdev) -{ - struct mcp2221 *mcp = hid_get_drvdata(hdev); +#if IS_REACHABLE(CONFIG_IIO) + INIT_DELAYED_WORK(&mcp->init_work, mcp_init_work); + schedule_delayed_work(&mcp->init_work, msecs_to_jiffies(100)); +#endif - i2c_del_adapter(&mcp->adapter); - hid_hw_close(mcp->hdev); - hid_hw_stop(mcp->hdev); + return 0; } static const struct hid_device_id mcp2221_devices[] = { |
