Skip to content

Commit 960f9df

Browse files
mranostayJiri Kosina
authored andcommitted
HID: mcp2221: add ADC/DAC support via iio subsystem
Add support for 3x 10-bit ADC and 1x DAC channels registered via the iio subsystem. To prevent breakage and unexpected dependencies this support only is only built if CONFIG_IIO is enabled, and is only weakly referenced by 'imply IIO' within the respective Kconfig. Additionally the iio device only gets registered if at least one channel is enabled in the power-on configuration read from SRAM. Signed-off-by: Matt Ranostay <[email protected]> Reviewed-by: Jonathan Cameron <[email protected]> Signed-off-by: Jiri Kosina <[email protected]>
1 parent ea418b3 commit 960f9df

File tree

2 files changed

+258
-1
lines changed

2 files changed

+258
-1
lines changed

drivers/hid/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1253,6 +1253,7 @@ config HID_MCP2221
12531253
tristate "Microchip MCP2221 HID USB-to-I2C/SMbus host support"
12541254
depends on USB_HID && I2C
12551255
imply GPIOLIB
1256+
imply IIO
12561257
help
12571258
Provides I2C and SMBUS host adapter functionality over USB-HID
12581259
through MCP2221 device.

drivers/hid/hid-mcp2221.c

Lines changed: 257 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,14 @@
1010
#include <linux/module.h>
1111
#include <linux/err.h>
1212
#include <linux/mutex.h>
13+
#include <linux/bitfield.h>
1314
#include <linux/completion.h>
1415
#include <linux/delay.h>
1516
#include <linux/hid.h>
1617
#include <linux/hidraw.h>
1718
#include <linux/i2c.h>
1819
#include <linux/gpio/driver.h>
20+
#include <linux/iio/iio.h>
1921
#include "hid-ids.h"
2022

2123
/* Commands codes in a raw output report */
@@ -30,6 +32,9 @@ enum {
3032
MCP2221_I2C_CANCEL = 0x10,
3133
MCP2221_GPIO_SET = 0x50,
3234
MCP2221_GPIO_GET = 0x51,
35+
MCP2221_SET_SRAM_SETTINGS = 0x60,
36+
MCP2221_GET_SRAM_SETTINGS = 0x61,
37+
MCP2221_READ_FLASH_DATA = 0xb0,
3338
};
3439

3540
/* Response codes in a raw input report */
@@ -89,6 +94,7 @@ struct mcp2221 {
8994
struct i2c_adapter adapter;
9095
struct mutex lock;
9196
struct completion wait_in_report;
97+
struct delayed_work init_work;
9298
u8 *rxbuf;
9399
u8 txbuf[64];
94100
int rxbuf_idx;
@@ -97,6 +103,18 @@ struct mcp2221 {
97103
struct gpio_chip *gc;
98104
u8 gp_idx;
99105
u8 gpio_dir;
106+
u8 mode[4];
107+
#if IS_REACHABLE(CONFIG_IIO)
108+
struct iio_chan_spec iio_channels[3];
109+
u16 adc_values[3];
110+
u8 adc_scale;
111+
u8 dac_value;
112+
u16 dac_scale;
113+
#endif
114+
};
115+
116+
struct mcp2221_iio {
117+
struct mcp2221 *mcp;
100118
};
101119

102120
/*
@@ -713,7 +731,7 @@ static int mcp_get_i2c_eng_state(struct mcp2221 *mcp,
713731
static int mcp2221_raw_event(struct hid_device *hdev,
714732
struct hid_report *report, u8 *data, int size)
715733
{
716-
u8 *buf;
734+
u8 *buf, tmp;
717735
struct mcp2221 *mcp = hid_get_drvdata(hdev);
718736

719737
switch (data[0]) {
@@ -745,6 +763,9 @@ static int mcp2221_raw_event(struct hid_device *hdev,
745763
break;
746764
}
747765
mcp->status = mcp_get_i2c_eng_state(mcp, data, 8);
766+
#if IS_REACHABLE(CONFIG_IIO)
767+
memcpy(&mcp->adc_values, &data[50], sizeof(mcp->adc_values));
768+
#endif
748769
break;
749770
default:
750771
mcp->status = -EIO;
@@ -816,6 +837,66 @@ static int mcp2221_raw_event(struct hid_device *hdev,
816837
complete(&mcp->wait_in_report);
817838
break;
818839

840+
case MCP2221_SET_SRAM_SETTINGS:
841+
switch (data[1]) {
842+
case MCP2221_SUCCESS:
843+
mcp->status = 0;
844+
break;
845+
default:
846+
mcp->status = -EAGAIN;
847+
}
848+
complete(&mcp->wait_in_report);
849+
break;
850+
851+
case MCP2221_GET_SRAM_SETTINGS:
852+
switch (data[1]) {
853+
case MCP2221_SUCCESS:
854+
memcpy(&mcp->mode, &data[22], 4);
855+
#if IS_REACHABLE(CONFIG_IIO)
856+
mcp->dac_value = data[6] & GENMASK(4, 0);
857+
#endif
858+
mcp->status = 0;
859+
break;
860+
default:
861+
mcp->status = -EAGAIN;
862+
}
863+
complete(&mcp->wait_in_report);
864+
break;
865+
866+
case MCP2221_READ_FLASH_DATA:
867+
switch (data[1]) {
868+
case MCP2221_SUCCESS:
869+
mcp->status = 0;
870+
871+
/* Only handles CHIP SETTINGS subpage currently */
872+
if (mcp->txbuf[1] != 0) {
873+
mcp->status = -EIO;
874+
break;
875+
}
876+
877+
#if IS_REACHABLE(CONFIG_IIO)
878+
/* DAC scale value */
879+
tmp = FIELD_GET(GENMASK(7, 6), data[6]);
880+
if ((data[6] & BIT(5)) && tmp)
881+
mcp->dac_scale = tmp + 4;
882+
else
883+
mcp->dac_scale = 5;
884+
885+
/* ADC scale value */
886+
tmp = FIELD_GET(GENMASK(4, 3), data[7]);
887+
if ((data[7] & BIT(2)) && tmp)
888+
mcp->adc_scale = tmp - 1;
889+
else
890+
mcp->adc_scale = 0;
891+
#endif
892+
893+
break;
894+
default:
895+
mcp->status = -EAGAIN;
896+
}
897+
complete(&mcp->wait_in_report);
898+
break;
899+
819900
default:
820901
mcp->status = -EIO;
821902
complete(&mcp->wait_in_report);
@@ -838,6 +919,176 @@ static void mcp2221_remove(struct hid_device *hdev)
838919
{
839920
}
840921

922+
#if IS_REACHABLE(CONFIG_IIO)
923+
static int mcp2221_read_raw(struct iio_dev *indio_dev,
924+
struct iio_chan_spec const *channel, int *val,
925+
int *val2, long mask)
926+
{
927+
struct mcp2221_iio *priv = iio_priv(indio_dev);
928+
struct mcp2221 *mcp = priv->mcp;
929+
int ret;
930+
931+
if (mask == IIO_CHAN_INFO_SCALE) {
932+
if (channel->output)
933+
*val = 1 << mcp->dac_scale;
934+
else
935+
*val = 1 << mcp->adc_scale;
936+
937+
return IIO_VAL_INT;
938+
}
939+
940+
mutex_lock(&mcp->lock);
941+
942+
if (channel->output) {
943+
*val = mcp->dac_value;
944+
ret = IIO_VAL_INT;
945+
} else {
946+
/* Read ADC values */
947+
ret = mcp_chk_last_cmd_status(mcp);
948+
949+
if (!ret) {
950+
*val = le16_to_cpu(mcp->adc_values[channel->address]);
951+
if (*val >= BIT(10))
952+
ret = -EINVAL;
953+
else
954+
ret = IIO_VAL_INT;
955+
}
956+
}
957+
958+
mutex_unlock(&mcp->lock);
959+
960+
return ret;
961+
}
962+
963+
static int mcp2221_write_raw(struct iio_dev *indio_dev,
964+
struct iio_chan_spec const *chan,
965+
int val, int val2, long mask)
966+
{
967+
struct mcp2221_iio *priv = iio_priv(indio_dev);
968+
struct mcp2221 *mcp = priv->mcp;
969+
int ret;
970+
971+
if (val < 0 || val >= BIT(5))
972+
return -EINVAL;
973+
974+
mutex_lock(&mcp->lock);
975+
976+
memset(mcp->txbuf, 0, 12);
977+
mcp->txbuf[0] = MCP2221_SET_SRAM_SETTINGS;
978+
mcp->txbuf[4] = BIT(7) | val;
979+
980+
ret = mcp_send_data_req_status(mcp, mcp->txbuf, 12);
981+
if (!ret)
982+
mcp->dac_value = val;
983+
984+
mutex_unlock(&mcp->lock);
985+
986+
return ret;
987+
}
988+
989+
static const struct iio_info mcp2221_info = {
990+
.read_raw = &mcp2221_read_raw,
991+
.write_raw = &mcp2221_write_raw,
992+
};
993+
994+
static int mcp_iio_channels(struct mcp2221 *mcp)
995+
{
996+
int idx, cnt = 0;
997+
bool dac_created = false;
998+
999+
/* GP0 doesn't have ADC/DAC alternative function */
1000+
for (idx = 1; idx < MCP_NGPIO; idx++) {
1001+
struct iio_chan_spec *chan = &mcp->iio_channels[cnt];
1002+
1003+
switch (mcp->mode[idx]) {
1004+
case 2:
1005+
chan->address = idx - 1;
1006+
chan->channel = cnt++;
1007+
break;
1008+
case 3:
1009+
/* GP1 doesn't have DAC alternative function */
1010+
if (idx == 1 || dac_created)
1011+
continue;
1012+
/* DAC1 and DAC2 outputs are connected to the same DAC */
1013+
dac_created = true;
1014+
chan->output = 1;
1015+
cnt++;
1016+
break;
1017+
default:
1018+
continue;
1019+
};
1020+
1021+
chan->type = IIO_VOLTAGE;
1022+
chan->indexed = 1;
1023+
chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
1024+
chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE);
1025+
chan->scan_index = -1;
1026+
}
1027+
1028+
return cnt;
1029+
}
1030+
1031+
static void mcp_init_work(struct work_struct *work)
1032+
{
1033+
struct iio_dev *indio_dev;
1034+
struct mcp2221 *mcp = container_of(work, struct mcp2221, init_work.work);
1035+
struct mcp2221_iio *data;
1036+
static int retries = 5;
1037+
int ret, num_channels;
1038+
1039+
hid_hw_power(mcp->hdev, PM_HINT_FULLON);
1040+
mutex_lock(&mcp->lock);
1041+
1042+
mcp->txbuf[0] = MCP2221_GET_SRAM_SETTINGS;
1043+
ret = mcp_send_data_req_status(mcp, mcp->txbuf, 1);
1044+
1045+
if (ret == -EAGAIN)
1046+
goto reschedule_task;
1047+
1048+
num_channels = mcp_iio_channels(mcp);
1049+
if (!num_channels)
1050+
goto unlock;
1051+
1052+
mcp->txbuf[0] = MCP2221_READ_FLASH_DATA;
1053+
mcp->txbuf[1] = 0;
1054+
ret = mcp_send_data_req_status(mcp, mcp->txbuf, 2);
1055+
1056+
if (ret == -EAGAIN)
1057+
goto reschedule_task;
1058+
1059+
indio_dev = devm_iio_device_alloc(&mcp->hdev->dev, sizeof(*data));
1060+
if (!indio_dev)
1061+
goto unlock;
1062+
1063+
data = iio_priv(indio_dev);
1064+
data->mcp = mcp;
1065+
1066+
indio_dev->name = "mcp2221";
1067+
indio_dev->modes = INDIO_DIRECT_MODE;
1068+
indio_dev->info = &mcp2221_info;
1069+
indio_dev->channels = mcp->iio_channels;
1070+
indio_dev->num_channels = num_channels;
1071+
1072+
devm_iio_device_register(&mcp->hdev->dev, indio_dev);
1073+
1074+
unlock:
1075+
mutex_unlock(&mcp->lock);
1076+
hid_hw_power(mcp->hdev, PM_HINT_NORMAL);
1077+
1078+
return;
1079+
1080+
reschedule_task:
1081+
mutex_unlock(&mcp->lock);
1082+
hid_hw_power(mcp->hdev, PM_HINT_NORMAL);
1083+
1084+
if (!retries--)
1085+
return;
1086+
1087+
/* Device is not ready to read SRAM or FLASH data, try again */
1088+
schedule_delayed_work(&mcp->init_work, msecs_to_jiffies(100));
1089+
}
1090+
#endif
1091+
8411092
static int mcp2221_probe(struct hid_device *hdev,
8421093
const struct hid_device_id *id)
8431094
{
@@ -921,6 +1172,11 @@ static int mcp2221_probe(struct hid_device *hdev,
9211172
return ret;
9221173
#endif
9231174

1175+
#if IS_REACHABLE(CONFIG_IIO)
1176+
INIT_DELAYED_WORK(&mcp->init_work, mcp_init_work);
1177+
schedule_delayed_work(&mcp->init_work, msecs_to_jiffies(100));
1178+
#endif
1179+
9241180
return 0;
9251181
}
9261182

0 commit comments

Comments
 (0)