diff --git a/host/modules/dmj-hwmon.c b/host/modules/dmj-hwmon.c index eae375c..333d75f 100644 --- a/host/modules/dmj-hwmon.c +++ b/host/modules/dmj-hwmon.c @@ -43,6 +43,7 @@ static umode_t dmj_hwmon_is_visible(const void *data, enum hwmon_sensor_types ty uint32_t attr, int ch) { switch (attr) { + case hwmon_temp_type: case hwmon_temp_input: case hwmon_temp_min: case hwmon_temp_max: @@ -112,19 +113,77 @@ static const struct hwmon_chip_info dmj_chip_info = { .info = dmj_hwmon_info }; +static int dmj_hwmon_check_hw(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + uint16_t m1ver; + uint8_t curmode, m1feat; + const int ver_min = 0x0010, ver_max = 0x0010; + int ret = 0, len; + uint8_t *buf = NULL; + + ret = dmj_transfer(pdev, DMJ_CMD_CFG_GET_CUR_MODE, + DMJ_XFER_FLAGS_PARSE_RESP, NULL, 0, (void**)&buf, &len); + ret = dmj_check_retval(ret, len, dev, "hwmon test 1", true, sizeof(curmode), sizeof(curmode)); + if (ret < 0 || !buf) goto out; + + curmode = buf[0]; + kfree(buf); buf = NULL; + if (curmode != 0x1) { + dev_err(dev, "device must be in mode 1 for hwmon to work, but it is in mode %d\n", curmode); + ret = -EIO; + goto out; + } + + ret = dmj_transfer(pdev, (1<<4) | DMJ_CMD_MODE_GET_VERSION, + DMJ_XFER_FLAGS_PARSE_RESP, NULL, 0, (void**)&buf, &len); + ret = dmj_check_retval(ret, len, dev, "hwmon test 2", true, sizeof(m1ver), sizeof(m1ver)); + if (ret < 0 || !buf) goto out; + + m1ver = (uint16_t)buf[0] | ((uint16_t)buf[1] << 8); + kfree(buf); buf = NULL; + if (m1ver > ver_max || m1ver < ver_min) { + dev_err(dev, "bad mode 1 version %04x on device, must be between %04x and %04x\n", + m1ver, ver_min, ver_max); + ret = -EIO; + goto out; + } + + ret = dmj_transfer(pdev, (1<<4) | DMJ_CMD_MODE_GET_FEATURES, + DMJ_XFER_FLAGS_PARSE_RESP, NULL, 0, (void**)&buf, &len); + ret = dmj_check_retval(ret, len, dev, "hwmon test 3", true, sizeof(m1feat), sizeof(m1feat)); + if (ret < 0 || !buf) goto out; + m1feat = buf[0]; + kfree(buf); buf = NULL; + if (!(m1feat & DMJ_FEATURE_MODE1_I2C)) { + dev_err(dev, "device's mode 1 does not support hwmon tempsensor\n"); + ret = -EIO; + goto out; + } + + ret = 0; + +out: + return ret; +} + static int dmj_hwmon_probe(struct platform_device *pdev) { struct dmj_hwmon *dmjh; struct device *dev = &pdev->dev; int ret; + ret = dmj_hwmon_check_hw(pdev); + if (ret) { + dev_err(dev, "hw check failed: %d\n", ret); + return -ENODEV; + } + dmjh = devm_kzalloc(dev, sizeof(*dmjh), GFP_KERNEL); if (!dmjh) return -ENOMEM; dmjh->pdev = pdev; - /* TODO: check usb stuff? (mode1, tempsensor feature) */ - platform_set_drvdata(pdev, dmjh); dmjh->hwmon_dev = hwmon_device_register_with_info(dev, HWMON_NAME, dmjh, diff --git a/host/modules/i2c-dmj.c b/host/modules/i2c-dmj.c index 924a69a..0bdc866 100644 --- a/host/modules/i2c-dmj.c +++ b/host/modules/i2c-dmj.c @@ -224,7 +224,7 @@ static int dmj_i2c_check_hw(struct platform_device *pdev) curmode = buf[0]; kfree(buf); buf = NULL; if (curmode != 0x1) { - dev_err(dev, "device must be in mode 1 for ICD to work, but it is in mode %d\n", curmode); + dev_err(dev, "device must be in mode 1 for I2C to work, but it is in mode %d\n", curmode); ret = -EIO; goto out; } diff --git a/host/modules/spi-dmj.c b/host/modules/spi-dmj.c index 5ded6df..e96e05d 100644 --- a/host/modules/spi-dmj.c +++ b/host/modules/spi-dmj.c @@ -118,6 +118,8 @@ struct dmj_spi { uint8_t cmdmap[32]; spinlock_t csmap_lock; + + struct spi_board_info binfo[8]; }; static int dmj_check_retval_sp(int ret, int len, struct device *dev, @@ -169,6 +171,19 @@ static int devcaps_to_kernmode(uint16_t caps) return ret; } +static void caps_to_binfo(struct dmj_spi *dmjs, int busnum) +{ + int i; + + for (i = 0; i < dmjs->caps.num_cs; ++i) { + snprintf(dmjs->binfo[i].modalias, SPI_NAME_SIZE, "spidev"); + dmjs->binfo[i].controller_data = dmjs; + dmjs->binfo[i].max_speed_hz = dmjs->caps.freq_max; + dmjs->binfo[i].bus_num = busnum; + dmjs->binfo[i].chip_select = i; + dmjs->binfo[i].mode = 0; /* shrug */ + } +} static void bufconv_to_le(void *dst, const void *src, size_t len_bytes, uint8_t bpw) { @@ -867,6 +882,15 @@ static int dmj_spi_probe(struct platform_device *pdev) goto err_dereg; } + dev_info(dev, "SPI bus number is %d\n", spictl->bus_num); + + caps_to_binfo(dmjs, spictl->bus_num); + for (i = 0; i < dmjs->caps.num_cs; ++i) { + if (!spi_new_device(spictl, &dmjs->binfo[i])) { + dev_warn(dev, "failed to create %s device %d\n", dmjs->binfo[i].modalias, i); + } + } + return dmj_spi_set_pinstate(dmjs, true); err_dereg: