hwmon: MC13783: Add uid and die temperature sensor inputs
authorAndrey Gusakov <andrey.gusakov@cogentembedded.com>
Tue, 27 Mar 2018 14:19:49 +0000 (17:19 +0300)
committerLee Jones <lee.jones@linaro.org>
Mon, 16 Apr 2018 12:01:36 +0000 (13:01 +0100)
The uid and die temperature can be read out on the ADIN7 using
input mux. Map uid and die temperature sensor to channels 16
and 17.

Signed-off-by: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
Acked-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
drivers/hwmon/mc13783-adc.c
drivers/mfd/mc13xxx-core.c
include/linux/mfd/mc13xxx.h

index 960a1db..67860ad 100644 (file)
@@ -63,6 +63,10 @@ static int mc13783_adc_read(struct device *dev,
        if (ret)
                return ret;
 
+       /* ADIN7 subchannels */
+       if (channel >= 16)
+               channel = 7;
+
        channel &= 0x7;
 
        *val = (sample[channel % 4] >> (channel > 3 ? 14 : 2)) & 0x3ff;
@@ -111,6 +115,57 @@ static ssize_t mc13783_adc_read_gp(struct device *dev,
        return sprintf(buf, "%u\n", val);
 }
 
+static ssize_t mc13783_adc_read_uid(struct device *dev,
+               struct device_attribute *devattr, char *buf)
+{
+       unsigned int val;
+       struct platform_device *pdev = to_platform_device(dev);
+       kernel_ulong_t driver_data = platform_get_device_id(pdev)->driver_data;
+       int ret = mc13783_adc_read(dev, devattr, &val);
+
+       if (ret)
+               return ret;
+
+       if (driver_data & MC13783_ADC_BPDIV2)
+               /* MC13892 have 1/2 divider, input range is [0, 4.800V] */
+               val = DIV_ROUND_CLOSEST(val * 4800, 1024);
+       else
+               /* MC13783 have 0.9 divider, input range is [0, 2.555V] */
+               val = DIV_ROUND_CLOSEST(val * 2555, 1024);
+
+       return sprintf(buf, "%u\n", val);
+}
+
+static ssize_t mc13783_adc_read_temp(struct device *dev,
+               struct device_attribute *devattr, char *buf)
+{
+       unsigned int val;
+       struct platform_device *pdev = to_platform_device(dev);
+       kernel_ulong_t driver_data = platform_get_device_id(pdev)->driver_data;
+       int ret = mc13783_adc_read(dev, devattr, &val);
+
+       if (ret)
+               return ret;
+
+       if (driver_data & MC13783_ADC_BPDIV2) {
+               /*
+                * MC13892:
+                * Die Temperature Read Out Code at 25C 680
+                * Temperature change per LSB +0.4244C
+                */
+               ret = DIV_ROUND_CLOSEST(-2635920 + val * 4244, 10);
+       } else {
+               /*
+                * MC13783:
+                * Die Temperature Read Out Code at 25C 282
+                * Temperature change per LSB -1.14C
+                */
+               ret = 346480 - 1140 * val;
+       }
+
+       return sprintf(buf, "%d\n", ret);
+}
+
 static DEVICE_ATTR_RO(name);
 static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, mc13783_adc_read_bp, NULL, 2);
 static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, mc13783_adc_read_gp, NULL, 5);
@@ -124,6 +179,9 @@ static SENSOR_DEVICE_ATTR(in12_input, S_IRUGO, mc13783_adc_read_gp, NULL, 12);
 static SENSOR_DEVICE_ATTR(in13_input, S_IRUGO, mc13783_adc_read_gp, NULL, 13);
 static SENSOR_DEVICE_ATTR(in14_input, S_IRUGO, mc13783_adc_read_gp, NULL, 14);
 static SENSOR_DEVICE_ATTR(in15_input, S_IRUGO, mc13783_adc_read_gp, NULL, 15);
+static SENSOR_DEVICE_ATTR(in16_input, S_IRUGO, mc13783_adc_read_uid, NULL, 16);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
+                         mc13783_adc_read_temp, NULL, 17);
 
 static struct attribute *mc13783_attr_base[] = {
        &dev_attr_name.attr,
@@ -131,6 +189,8 @@ static struct attribute *mc13783_attr_base[] = {
        &sensor_dev_attr_in5_input.dev_attr.attr,
        &sensor_dev_attr_in6_input.dev_attr.attr,
        &sensor_dev_attr_in7_input.dev_attr.attr,
+       &sensor_dev_attr_in16_input.dev_attr.attr,
+       &sensor_dev_attr_temp1_input.dev_attr.attr,
        NULL
 };
 
index d7f54e4..c63e331 100644 (file)
@@ -279,8 +279,21 @@ int mc13xxx_adc_do_conversion(struct mc13xxx *mc13xxx, unsigned int mode,
        adc0 = MC13XXX_ADC0_ADINC1 | MC13XXX_ADC0_ADINC2;
        adc1 = MC13XXX_ADC1_ADEN | MC13XXX_ADC1_ADTRIGIGN | MC13XXX_ADC1_ASC;
 
-       if (channel > 7)
+       /*
+        * Channels mapped through ADIN7:
+        * 7  - General purpose ADIN7
+        * 16 - UID
+        * 17 - Die temperature
+        */
+       if (channel > 7 && channel < 16) {
                adc1 |= MC13XXX_ADC1_ADSEL;
+       } else if (channel == 16) {
+               adc0 |= MC13XXX_ADC0_ADIN7SEL_UID;
+               channel = 7;
+       } else if (channel == 17) {
+               adc0 |= MC13XXX_ADC0_ADIN7SEL_DIE;
+               channel = 7;
+       }
 
        switch (mode) {
        case MC13XXX_ADC_MODE_TS:
index 638222e..54a3cd8 100644 (file)
@@ -243,6 +243,8 @@ struct mc13xxx_platform_data {
 #define MC13XXX_ADC0_LICELLCON         (1 << 0)
 #define MC13XXX_ADC0_CHRGICON          (1 << 1)
 #define MC13XXX_ADC0_BATICON           (1 << 2)
+#define MC13XXX_ADC0_ADIN7SEL_DIE      (1 << 4)
+#define MC13XXX_ADC0_ADIN7SEL_UID      (2 << 4)
 #define MC13XXX_ADC0_ADREFEN           (1 << 10)
 #define MC13XXX_ADC0_TSMOD0            (1 << 12)
 #define MC13XXX_ADC0_TSMOD1            (1 << 13)