diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/hwmon/Kconfig | 1 | ||||
-rw-r--r-- | drivers/hwmon/ntc_thermistor.c | 145 |
2 files changed, 127 insertions, 19 deletions
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index aaa14f4a0f7d..47d2176957a0 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -899,6 +899,7 @@ config SENSORS_MCP3021 config SENSORS_NTC_THERMISTOR tristate "NTC thermistor support" + depends on (!OF && !IIO) || (OF && IIO) help This driver supports NTC thermistors sensor reading and its interpretation. The driver can also monitor the temperature and diff --git a/drivers/hwmon/ntc_thermistor.c b/drivers/hwmon/ntc_thermistor.c index b5f63f9c0ce1..d399197655e6 100644 --- a/drivers/hwmon/ntc_thermistor.c +++ b/drivers/hwmon/ntc_thermistor.c @@ -26,9 +26,16 @@ #include <linux/math64.h> #include <linux/platform_device.h> #include <linux/err.h> +#include <linux/of.h> +#include <linux/of_device.h> #include <linux/platform_data/ntc_thermistor.h> +#include <linux/iio/iio.h> +#include <linux/iio/machine.h> +#include <linux/iio/driver.h> +#include <linux/iio/consumer.h> + #include <linux/hwmon.h> #include <linux/hwmon-sysfs.h> @@ -37,6 +44,15 @@ struct ntc_compensation { unsigned int ohm; }; +static const struct platform_device_id ntc_thermistor_id[] = { + { "ncp15wb473", TYPE_NCPXXWB473 }, + { "ncp18wb473", TYPE_NCPXXWB473 }, + { "ncp21wb473", TYPE_NCPXXWB473 }, + { "ncp03wb473", TYPE_NCPXXWB473 }, + { "ncp15wl333", TYPE_NCPXXWL333 }, + { }, +}; + /* * A compensation table should be sorted by the values of .ohm * in descending order. @@ -125,6 +141,92 @@ struct ntc_data { char name[PLATFORM_NAME_SIZE]; }; +#ifdef CONFIG_OF +static int ntc_adc_iio_read(struct ntc_thermistor_platform_data *pdata) +{ + struct iio_channel *channel = pdata->chan; + unsigned int result; + int val, ret; + + ret = iio_read_channel_raw(channel, &val); + if (ret < 0) { + pr_err("read channel() error: %d\n", ret); + return ret; + } + + /* unit: mV */ + result = pdata->pullup_uV * val; + result >>= 12; + + return result; +} + +static const struct of_device_id ntc_match[] = { + { .compatible = "ntc,ncp15wb473", + .data = &ntc_thermistor_id[TYPE_NCPXXWB473] }, + { .compatible = "ntc,ncp18wb473", + .data = &ntc_thermistor_id[TYPE_NCPXXWB473] }, + { .compatible = "ntc,ncp21wb473", + .data = &ntc_thermistor_id[TYPE_NCPXXWB473] }, + { .compatible = "ntc,ncp03wb473", + .data = &ntc_thermistor_id[TYPE_NCPXXWB473] }, + { .compatible = "ntc,ncp15wl333", + .data = &ntc_thermistor_id[TYPE_NCPXXWL333] }, + { }, +}; +MODULE_DEVICE_TABLE(of, ntc_match); + +static struct ntc_thermistor_platform_data * +ntc_thermistor_parse_dt(struct platform_device *pdev) +{ + struct iio_channel *chan; + struct device_node *np = pdev->dev.of_node; + struct ntc_thermistor_platform_data *pdata; + + if (!np) + return NULL; + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return ERR_PTR(-ENOMEM); + + chan = iio_channel_get(&pdev->dev, NULL); + if (IS_ERR(chan)) + return ERR_CAST(chan); + + if (of_property_read_u32(np, "pullup-uv", &pdata->pullup_uV)) + return ERR_PTR(-ENODEV); + if (of_property_read_u32(np, "pullup-ohm", &pdata->pullup_ohm)) + return ERR_PTR(-ENODEV); + if (of_property_read_u32(np, "pulldown-ohm", &pdata->pulldown_ohm)) + return ERR_PTR(-ENODEV); + + if (of_find_property(np, "connected-positive", NULL)) + pdata->connect = NTC_CONNECTED_POSITIVE; + else /* status change should be possible if not always on. */ + pdata->connect = NTC_CONNECTED_GROUND; + + pdata->chan = chan; + pdata->read_uV = ntc_adc_iio_read; + + return pdata; +} +static void ntc_iio_channel_release(struct ntc_thermistor_platform_data *pdata) +{ + if (pdata->chan) + iio_channel_release(pdata->chan); +} +#else +static struct ntc_thermistor_platform_data * +ntc_thermistor_parse_dt(struct platform_device *pdev) +{ + return NULL; +} + +static void ntc_iio_channel_release(struct ntc_thermistor_platform_data *pdata) +{ } +#endif + static inline u64 div64_u64_safe(u64 dividend, u64 divisor) { if (divisor == 0 && dividend == 0) @@ -259,7 +361,7 @@ static int ntc_thermistor_get_ohm(struct ntc_data *data) return data->pdata->read_ohm(); if (data->pdata->read_uV) { - read_uV = data->pdata->read_uV(); + read_uV = data->pdata->read_uV(data->pdata); if (read_uV < 0) return read_uV; return get_ohm_of_thermistor(data, read_uV); @@ -311,9 +413,18 @@ static const struct attribute_group ntc_attr_group = { static int ntc_thermistor_probe(struct platform_device *pdev) { + const struct of_device_id *of_id = + of_match_device(of_match_ptr(ntc_match), &pdev->dev); + const struct platform_device_id *pdev_id; + struct ntc_thermistor_platform_data *pdata; struct ntc_data *data; - struct ntc_thermistor_platform_data *pdata = pdev->dev.platform_data; - int ret = 0; + int ret; + + pdata = ntc_thermistor_parse_dt(pdev); + if (IS_ERR(pdata)) + return PTR_ERR(pdata); + else if (pdata == NULL) + pdata = pdev->dev.platform_data; if (!pdata) { dev_err(&pdev->dev, "No platform init data supplied.\n"); @@ -349,11 +460,13 @@ static int ntc_thermistor_probe(struct platform_device *pdev) if (!data) return -ENOMEM; + pdev_id = of_id ? of_id->data : platform_get_device_id(pdev); + data->dev = &pdev->dev; data->pdata = pdata; - strlcpy(data->name, pdev->id_entry->name, sizeof(data->name)); + strlcpy(data->name, pdev_id->name, sizeof(data->name)); - switch (pdev->id_entry->driver_data) { + switch (pdev_id->driver_data) { case TYPE_NCPXXWB473: data->comp = ncpXXwb473; data->n_comp = ARRAY_SIZE(ncpXXwb473); @@ -364,8 +477,7 @@ static int ntc_thermistor_probe(struct platform_device *pdev) break; default: dev_err(&pdev->dev, "Unknown device type: %lu(%s)\n", - pdev->id_entry->driver_data, - pdev->id_entry->name); + pdev_id->driver_data, pdev_id->name); return -EINVAL; } @@ -384,39 +496,34 @@ static int ntc_thermistor_probe(struct platform_device *pdev) goto err_after_sysfs; } - dev_info(&pdev->dev, "Thermistor %s:%d (type: %s/%lu) successfully probed.\n", - pdev->name, pdev->id, pdev->id_entry->name, - pdev->id_entry->driver_data); + dev_info(&pdev->dev, "Thermistor type: %s successfully probed.\n", + pdev->name); + return 0; err_after_sysfs: sysfs_remove_group(&data->dev->kobj, &ntc_attr_group); + ntc_iio_channel_release(pdata); return ret; } static int ntc_thermistor_remove(struct platform_device *pdev) { struct ntc_data *data = platform_get_drvdata(pdev); + struct ntc_thermistor_platform_data *pdata = data->pdata; hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&data->dev->kobj, &ntc_attr_group); + ntc_iio_channel_release(pdata); platform_set_drvdata(pdev, NULL); return 0; } -static const struct platform_device_id ntc_thermistor_id[] = { - { "ncp15wb473", TYPE_NCPXXWB473 }, - { "ncp18wb473", TYPE_NCPXXWB473 }, - { "ncp21wb473", TYPE_NCPXXWB473 }, - { "ncp03wb473", TYPE_NCPXXWB473 }, - { "ncp15wl333", TYPE_NCPXXWL333 }, - { }, -}; - static struct platform_driver ntc_thermistor_driver = { .driver = { .name = "ntc-thermistor", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(ntc_match), }, .probe = ntc_thermistor_probe, .remove = ntc_thermistor_remove, |