[thermal PATCH v15 8/9] drivers: thermal: tsens: Add support for ipq8064-tsens

2021-04-20 Thread Ansuel Smith
Add support for tsens present in ipq806x SoCs based on generic msm8960
tsens driver.

Signed-off-by: Ansuel Smith 
Reviewed-by: Thara Gopinath 
---
 drivers/thermal/qcom/tsens.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
index be0c5931f..56b505f35 100644
--- a/drivers/thermal/qcom/tsens.c
+++ b/drivers/thermal/qcom/tsens.c
@@ -966,6 +966,9 @@ static SIMPLE_DEV_PM_OPS(tsens_pm_ops, tsens_suspend, 
tsens_resume);
 
 static const struct of_device_id tsens_table[] = {
{
+   .compatible = "qcom,ipq8064-tsens",
+   .data = _8960,
+   }, {
.compatible = "qcom,msm8916-tsens",
.data = _8916,
}, {
-- 
2.30.2



[thermal PATCH v15 9/9] dt-bindings: thermal: tsens: Document ipq8064 bindings

2021-04-20 Thread Ansuel Smith
Document the use of bindings used for msm8960 tsens based devices.
msm8960 use the same gcc regs and is set as a child of the qcom gcc.

Signed-off-by: Ansuel Smith 
Reviewed-by: Rob Herring 
---
 .../bindings/thermal/qcom-tsens.yaml  | 56 ---
 1 file changed, 48 insertions(+), 8 deletions(-)

diff --git a/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml 
b/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml
index d7be931b4..2e762596b 100644
--- a/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml
+++ b/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml
@@ -19,6 +19,11 @@ description: |
 properties:
   compatible:
 oneOf:
+  - description: msm9860 TSENS based
+items:
+  - enum:
+  - qcom,ipq8064-tsens
+
   - description: v0.1 of TSENS
 items:
   - enum:
@@ -70,7 +75,9 @@ properties:
 maxItems: 2
 items:
   - const: calib
-  - const: calib_sel
+  - enum:
+  - calib_backup
+  - calib_sel
 
   "#qcom,sensors":
 description:
@@ -85,12 +92,20 @@ properties:
   Number of cells required to uniquely identify the thermal sensors. Since
   we have multiple sensors this is set to 1
 
+required:
+  - compatible
+  - interrupts
+  - interrupt-names
+  - "#thermal-sensor-cells"
+  - "#qcom,sensors"
+
 allOf:
   - if:
   properties:
 compatible:
   contains:
 enum:
+  - qcom,ipq8064-tsens
   - qcom,msm8916-tsens
   - qcom,msm8974-tsens
   - qcom,msm8976-tsens
@@ -111,17 +126,42 @@ allOf:
 interrupt-names:
   minItems: 2
 
-required:
-  - compatible
-  - reg
-  - "#qcom,sensors"
-  - interrupts
-  - interrupt-names
-  - "#thermal-sensor-cells"
+  - if:
+  properties:
+compatible:
+  contains:
+enum:
+  - qcom,tsens-v0_1
+  - qcom,tsens-v1
+  - qcom,tsens-v2
+
+then:
+  required:
+- reg
 
 additionalProperties: false
 
 examples:
+  - |
+#include 
+// Example msm9860 based SoC (ipq8064):
+gcc: clock-controller {
+
+   /* ... */
+
+   tsens: thermal-sensor {
+compatible = "qcom,ipq8064-tsens";
+
+ nvmem-cells = <_calib>, <_calib_backup>;
+ nvmem-cell-names = "calib", "calib_backup";
+ interrupts = ;
+ interrupt-names = "uplow";
+
+ #qcom,sensors = <11>;
+ #thermal-sensor-cells = <1>;
+  };
+};
+
   - |
 #include 
 // Example 1 (legacy: for pre v1 IP):
-- 
2.30.2



[thermal PATCH v15 7/9] drivers: thermal: tsens: Drop unused define for msm8960

2021-04-20 Thread Ansuel Smith
Drop unused define for msm8960 replaced by generic api and reg_field.

Signed-off-by: Ansuel Smith 
Reviewed-by: Thara Gopinath 
---
 drivers/thermal/qcom/tsens-8960.c | 24 +---
 1 file changed, 1 insertion(+), 23 deletions(-)

diff --git a/drivers/thermal/qcom/tsens-8960.c 
b/drivers/thermal/qcom/tsens-8960.c
index 58112f0df..67c1748cd 100644
--- a/drivers/thermal/qcom/tsens-8960.c
+++ b/drivers/thermal/qcom/tsens-8960.c
@@ -10,8 +10,6 @@
 #include 
 #include "tsens.h"
 
-#define CAL_MDEGC  3
-
 #define CONFIG_ADDR0x3640
 #define CONFIG_ADDR_8660   0x3620
 /* CONFIG_ADDR bitmasks */
@@ -21,39 +19,19 @@
 #define CONFIG_SHIFT_8660  28
 #define CONFIG_MASK_8660   (3 << CONFIG_SHIFT_8660)
 
-#define STATUS_CNTL_ADDR_8064  0x3660
 #define CNTL_ADDR  0x3620
 /* CNTL_ADDR bitmasks */
 #define EN BIT(0)
 #define SW_RST BIT(1)
-#define SENSOR0_EN BIT(3)
+
 #define MEASURE_PERIOD BIT(18)
 #define SLP_CLK_ENABIT(26)
 #define SLP_CLK_ENA_8660   BIT(24)
 #define SENSOR0_SHIFT  3
 
-/* INT_STATUS_ADDR bitmasks */
-#define MIN_STATUS_MASKBIT(0)
-#define LOWER_STATUS_CLR   BIT(1)
-#define UPPER_STATUS_CLR   BIT(2)
-#define MAX_STATUS_MASKBIT(3)
-
 #define THRESHOLD_ADDR 0x3624
-/* THRESHOLD_ADDR bitmasks */
-#define THRESHOLD_MAX_LIMIT_SHIFT  24
-#define THRESHOLD_MIN_LIMIT_SHIFT  16
-#define THRESHOLD_UPPER_LIMIT_SHIFT8
-#define THRESHOLD_LOWER_LIMIT_SHIFT0
-
-/* Initial temperature threshold values */
-#define LOWER_LIMIT_TH 0x50
-#define UPPER_LIMIT_TH 0xdf
-#define MIN_LIMIT_TH   0x0
-#define MAX_LIMIT_TH   0xff
 
 #define INT_STATUS_ADDR0x363c
-#define TRDY_MASK  BIT(7)
-#define TIMEOUT_US 100
 
 #define S0_STATUS_OFF  0x3628
 #define S1_STATUS_OFF  0x362c
-- 
2.30.2



[thermal PATCH v15 5/9] drivers: thermal: tsens: Fix bug in sensor enable for msm8960

2021-04-20 Thread Ansuel Smith
Device based on tsens VER_0 contains a hardware bug that results in some
problem with sensor enablement. Sensor id 6-11 can't be enabled
selectively and all of them must be enabled in one step.

Signed-off-by: Ansuel Smith 
Acked-by: Thara Gopinath 
---
 drivers/thermal/qcom/tsens-8960.c | 23 ---
 1 file changed, 20 insertions(+), 3 deletions(-)

diff --git a/drivers/thermal/qcom/tsens-8960.c 
b/drivers/thermal/qcom/tsens-8960.c
index 83746ee3f..a96d37c2b 100644
--- a/drivers/thermal/qcom/tsens-8960.c
+++ b/drivers/thermal/qcom/tsens-8960.c
@@ -27,9 +27,9 @@
 #define EN BIT(0)
 #define SW_RST BIT(1)
 #define SENSOR0_EN BIT(3)
+#define MEASURE_PERIOD BIT(18)
 #define SLP_CLK_ENABIT(26)
 #define SLP_CLK_ENA_8660   BIT(24)
-#define MEASURE_PERIOD 1
 #define SENSOR0_SHIFT  3
 
 /* INT_STATUS_ADDR bitmasks */
@@ -126,17 +126,34 @@ static int resume_8960(struct tsens_priv *priv)
 static int enable_8960(struct tsens_priv *priv, int id)
 {
int ret;
-   u32 reg, mask;
+   u32 reg, mask = BIT(id);
 
ret = regmap_read(priv->tm_map, CNTL_ADDR, );
if (ret)
return ret;
 
-   mask = BIT(id + SENSOR0_SHIFT);
+   /* HARDWARE BUG:
+* On platforms with more than 6 sensors, all remaining sensors
+* must be enabled together, otherwise undefined results are expected.
+* (Sensor 6-7 disabled, Sensor 3 disabled...) In the original driver,
+* all the sensors are enabled in one step hence this bug is not
+* triggered.
+*/
+   if (id > 5)
+   mask = GENMASK(10, 6);
+
+   mask <<= SENSOR0_SHIFT;
+
+   /* Sensors already enabled. Skip. */
+   if ((reg & mask) == mask)
+   return 0;
+
ret = regmap_write(priv->tm_map, CNTL_ADDR, reg | SW_RST);
if (ret)
return ret;
 
+   reg |= MEASURE_PERIOD;
+
if (priv->num_sensors > 1)
reg |= mask | SLP_CLK_ENA | EN;
else
-- 
2.30.2



[thermal PATCH v15 3/9] drivers: thermal: tsens: Add VER_0 tsens version

2021-04-20 Thread Ansuel Smith
VER_0 is used to describe device based on tsens version before v0.1.
These device are devices based on msm8960 for example apq8064 or
ipq806x. Add support for VER_0 in tsens.c and set the right tsens feat
in tsens-8960.c file.

Signed-off-by: Ansuel Smith 
Reviewed-by: Thara Gopinath 
Reported-by: kernel test robot 
Reported-by: Dan Carpenter 
---
 drivers/thermal/qcom/tsens-8960.c |   9 ++
 drivers/thermal/qcom/tsens.c  | 150 --
 drivers/thermal/qcom/tsens.h  |   4 +-
 3 files changed, 133 insertions(+), 30 deletions(-)

diff --git a/drivers/thermal/qcom/tsens-8960.c 
b/drivers/thermal/qcom/tsens-8960.c
index 0d0c2647d..0dd15e812 100644
--- a/drivers/thermal/qcom/tsens-8960.c
+++ b/drivers/thermal/qcom/tsens-8960.c
@@ -347,8 +347,17 @@ static const struct tsens_ops ops_8960 = {
.resume = resume_8960,
 };
 
+static struct tsens_features tsens_8960_feat = {
+   .ver_major  = VER_0,
+   .crit_int   = 0,
+   .adc= 1,
+   .srot_split = 0,
+   .max_sensors= 11,
+};
+
 struct tsens_plat_data data_8960 = {
.num_sensors= 11,
.ops= _8960,
+   .feat   = _8960_feat,
.fields = tsens_8960_regfields,
 };
diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
index 562c438ff..be0c5931f 100644
--- a/drivers/thermal/qcom/tsens.c
+++ b/drivers/thermal/qcom/tsens.c
@@ -12,6 +12,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -516,6 +517,15 @@ irqreturn_t tsens_irq_thread(int irq, void *data)
dev_dbg(priv->dev, "[%u] %s: no violation:  %d\n",
hw_id, __func__, temp);
}
+
+   if (tsens_version(priv) < VER_0_1) {
+   /* Constraint: There is only 1 interrupt control 
register for all
+* 11 temperature sensor. So monitoring more than 1 
sensor based
+* on interrupts will yield inconsistent result. To 
overcome this
+* issue we will monitor only sensor 0 which is the 
master sensor.
+*/
+   break;
+   }
}
 
return IRQ_HANDLED;
@@ -531,6 +541,13 @@ int tsens_set_trips(void *_sensor, int low, int high)
int high_val, low_val, cl_high, cl_low;
u32 hw_id = s->hw_id;
 
+   if (tsens_version(priv) < VER_0_1) {
+   /* Pre v0.1 IP had a single register for each type of interrupt
+* and thresholds
+*/
+   hw_id = 0;
+   }
+
dev_dbg(dev, "[%u] %s: proposed thresholds: (%d:%d)\n",
hw_id, __func__, low, high);
 
@@ -585,18 +602,21 @@ int get_temp_tsens_valid(const struct tsens_sensor *s, 
int *temp)
u32 valid;
int ret;
 
-   ret = regmap_field_read(priv->rf[valid_idx], );
-   if (ret)
-   return ret;
-   while (!valid) {
-   /* Valid bit is 0 for 6 AHB clock cycles.
-* At 19.2MHz, 1 AHB clock is ~60ns.
-* We should enter this loop very, very rarely.
-*/
-   ndelay(400);
+   /* VER_0 doesn't have VALID bit */
+   if (tsens_version(priv) >= VER_0_1) {
ret = regmap_field_read(priv->rf[valid_idx], );
if (ret)
return ret;
+   while (!valid) {
+   /* Valid bit is 0 for 6 AHB clock cycles.
+* At 19.2MHz, 1 AHB clock is ~60ns.
+* We should enter this loop very, very rarely.
+*/
+   ndelay(400);
+   ret = regmap_field_read(priv->rf[valid_idx], );
+   if (ret)
+   return ret;
+   }
}
 
/* Valid bit is set, OK to read the temperature */
@@ -609,15 +629,29 @@ int get_temp_common(const struct tsens_sensor *s, int 
*temp)
 {
struct tsens_priv *priv = s->priv;
int hw_id = s->hw_id;
-   int last_temp = 0, ret;
+   int last_temp = 0, ret, trdy;
+   unsigned long timeout;
 
-   ret = regmap_field_read(priv->rf[LAST_TEMP_0 + hw_id], _temp);
-   if (ret)
-   return ret;
+   timeout = jiffies + usecs_to_jiffies(TIMEOUT_US);
+   do {
+   if (tsens_version(priv) == VER_0) {
+   ret = regmap_field_read(priv->rf[TRDY], );
+   if (ret)
+   return ret;
+   if (!trdy)
+   continue;
+   }
 
-   *temp = code_to_degc(last_temp, s) * 1000;
+   ret = regmap_field_read(priv->rf[LAST_TEMP_0 + hw_id], 
_temp);
+   if (ret)
+   return re

[thermal PATCH v15 6/9] drivers: thermal: tsens: Replace custom 8960 apis with generic apis

2021-04-20 Thread Ansuel Smith
Rework calibrate function to use common function. Derive the offset from
a missing hardcoded slope table and the data from the nvmem calib
efuses.
Drop custom get_temp function and use generic api.

Signed-off-by: Ansuel Smith 
Acked-by: Thara Gopinath 
---
 drivers/thermal/qcom/tsens-8960.c | 56 +--
 1 file changed, 15 insertions(+), 41 deletions(-)

diff --git a/drivers/thermal/qcom/tsens-8960.c 
b/drivers/thermal/qcom/tsens-8960.c
index a96d37c2b..58112f0df 100644
--- a/drivers/thermal/qcom/tsens-8960.c
+++ b/drivers/thermal/qcom/tsens-8960.c
@@ -67,6 +67,13 @@
 #define S9_STATUS_OFF  0x3674
 #define S10_STATUS_OFF 0x3678
 
+/* Original slope - 350 to compensate mC to C inaccuracy */
+static u32 tsens_msm8960_slope[] = {
+   826, 826, 804, 826,
+   761, 782, 782, 849,
+   782, 849, 782
+   };
+
 static int suspend_8960(struct tsens_priv *priv)
 {
int ret;
@@ -194,9 +201,7 @@ static int calibrate_8960(struct tsens_priv *priv)
 {
int i;
char *data;
-
-   ssize_t num_read = priv->num_sensors;
-   struct tsens_sensor *s = priv->sensor;
+   u32 p1[11];
 
data = qfprom_read(priv->dev, "calib");
if (IS_ERR(data))
@@ -204,49 +209,18 @@ static int calibrate_8960(struct tsens_priv *priv)
if (IS_ERR(data))
return PTR_ERR(data);
 
-   for (i = 0; i < num_read; i++, s++)
-   s->offset = data[i];
+   for (i = 0; i < priv->num_sensors; i++) {
+   p1[i] = data[i];
+   priv->sensor[i].slope = tsens_msm8960_slope[i];
+   }
+
+   compute_intercept_slope(priv, p1, NULL, ONE_PT_CALIB);
 
kfree(data);
 
return 0;
 }
 
-/* Temperature on y axis and ADC-code on x-axis */
-static inline int code_to_mdegC(u32 adc_code, const struct tsens_sensor *s)
-{
-   int slope, offset;
-
-   slope = thermal_zone_get_slope(s->tzd);
-   offset = CAL_MDEGC - slope * s->offset;
-
-   return adc_code * slope + offset;
-}
-
-static int get_temp_8960(const struct tsens_sensor *s, int *temp)
-{
-   int ret;
-   u32 code, trdy;
-   struct tsens_priv *priv = s->priv;
-   unsigned long timeout;
-
-   timeout = jiffies + usecs_to_jiffies(TIMEOUT_US);
-   do {
-   ret = regmap_read(priv->tm_map, INT_STATUS_ADDR, );
-   if (ret)
-   return ret;
-   if (!(trdy & TRDY_MASK))
-   continue;
-   ret = regmap_read(priv->tm_map, s->status, );
-   if (ret)
-   return ret;
-   *temp = code_to_mdegC(code, s);
-   return 0;
-   } while (time_before(jiffies, timeout));
-
-   return -ETIMEDOUT;
-}
-
 static const struct reg_field tsens_8960_regfields[MAX_REGFIELDS] = {
/* - SROT -- */
/* No VERSION information */
@@ -307,7 +281,7 @@ static const struct reg_field 
tsens_8960_regfields[MAX_REGFIELDS] = {
 static const struct tsens_ops ops_8960 = {
.init   = init_common,
.calibrate  = calibrate_8960,
-   .get_temp   = get_temp_8960,
+   .get_temp   = get_temp_common,
.enable = enable_8960,
.disable= disable_8960,
.suspend= suspend_8960,
-- 
2.30.2



[thermal PATCH v15 4/9] drivers: thermal: tsens: Use init_common for msm8960

2021-04-20 Thread Ansuel Smith
Use init_common and drop custom init for msm8960.

Signed-off-by: Ansuel Smith 
Reviewed-by: Thara Gopinath 
---
 drivers/thermal/qcom/tsens-8960.c | 52 +--
 1 file changed, 1 insertion(+), 51 deletions(-)

diff --git a/drivers/thermal/qcom/tsens-8960.c 
b/drivers/thermal/qcom/tsens-8960.c
index 0dd15e812..83746ee3f 100644
--- a/drivers/thermal/qcom/tsens-8960.c
+++ b/drivers/thermal/qcom/tsens-8960.c
@@ -173,56 +173,6 @@ static void disable_8960(struct tsens_priv *priv)
regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
 }
 
-static int init_8960(struct tsens_priv *priv)
-{
-   int ret, i;
-   u32 reg_cntl;
-
-   priv->tm_map = dev_get_regmap(priv->dev, NULL);
-   if (!priv->tm_map)
-   return -ENODEV;
-
-   /*
-* The status registers for each sensor are discontiguous
-* because some SoCs have 5 sensors while others have more
-* but the control registers stay in the same place, i.e
-* directly after the first 5 status registers.
-*/
-   for (i = 0; i < priv->num_sensors; i++) {
-   if (i >= 5)
-   priv->sensor[i].status = S0_STATUS_OFF + 40;
-   priv->sensor[i].status += i * 4;
-   }
-
-   reg_cntl = SW_RST;
-   ret = regmap_update_bits(priv->tm_map, CNTL_ADDR, SW_RST, reg_cntl);
-   if (ret)
-   return ret;
-
-   if (priv->num_sensors > 1) {
-   reg_cntl |= SLP_CLK_ENA | (MEASURE_PERIOD << 18);
-   reg_cntl &= ~SW_RST;
-   ret = regmap_update_bits(priv->tm_map, CONFIG_ADDR,
-CONFIG_MASK, CONFIG);
-   } else {
-   reg_cntl |= SLP_CLK_ENA_8660 | (MEASURE_PERIOD << 16);
-   reg_cntl &= ~CONFIG_MASK_8660;
-   reg_cntl |= CONFIG_8660 << CONFIG_SHIFT_8660;
-   }
-
-   reg_cntl |= GENMASK(priv->num_sensors - 1, 0) << SENSOR0_SHIFT;
-   ret = regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
-   if (ret)
-   return ret;
-
-   reg_cntl |= EN;
-   ret = regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
-   if (ret)
-   return ret;
-
-   return 0;
-}
-
 static int calibrate_8960(struct tsens_priv *priv)
 {
int i;
@@ -338,7 +288,7 @@ static const struct reg_field 
tsens_8960_regfields[MAX_REGFIELDS] = {
 };
 
 static const struct tsens_ops ops_8960 = {
-   .init   = init_8960,
+   .init   = init_common,
.calibrate  = calibrate_8960,
.get_temp   = get_temp_8960,
.enable = enable_8960,
-- 
2.30.2



[thermal PATCH v15 2/9] drivers: thermal: tsens: Convert msm8960 to reg_field

2021-04-20 Thread Ansuel Smith
Convert msm9860 driver to reg_field to use the init_common
function.

Signed-off-by: Ansuel Smith 
Acked-by: Thara Gopinath 
---
 drivers/thermal/qcom/tsens-8960.c | 73 ++-
 1 file changed, 71 insertions(+), 2 deletions(-)

diff --git a/drivers/thermal/qcom/tsens-8960.c 
b/drivers/thermal/qcom/tsens-8960.c
index 2a28a5af2..0d0c2647d 100644
--- a/drivers/thermal/qcom/tsens-8960.c
+++ b/drivers/thermal/qcom/tsens-8960.c
@@ -51,11 +51,22 @@
 #define MIN_LIMIT_TH   0x0
 #define MAX_LIMIT_TH   0xff
 
-#define S0_STATUS_ADDR 0x3628
 #define INT_STATUS_ADDR0x363c
 #define TRDY_MASK  BIT(7)
 #define TIMEOUT_US 100
 
+#define S0_STATUS_OFF  0x3628
+#define S1_STATUS_OFF  0x362c
+#define S2_STATUS_OFF  0x3630
+#define S3_STATUS_OFF  0x3634
+#define S4_STATUS_OFF  0x3638
+#define S5_STATUS_OFF  0x3664  /* Sensors 5-10 found on 
apq8064/msm8960 */
+#define S6_STATUS_OFF  0x3668
+#define S7_STATUS_OFF  0x366c
+#define S8_STATUS_OFF  0x3670
+#define S9_STATUS_OFF  0x3674
+#define S10_STATUS_OFF 0x3678
+
 static int suspend_8960(struct tsens_priv *priv)
 {
int ret;
@@ -179,7 +190,7 @@ static int init_8960(struct tsens_priv *priv)
 */
for (i = 0; i < priv->num_sensors; i++) {
if (i >= 5)
-   priv->sensor[i].status = S0_STATUS_ADDR + 40;
+   priv->sensor[i].status = S0_STATUS_OFF + 40;
priv->sensor[i].status += i * 4;
}
 
@@ -269,6 +280,63 @@ static int get_temp_8960(const struct tsens_sensor *s, int 
*temp)
return -ETIMEDOUT;
 }
 
+static const struct reg_field tsens_8960_regfields[MAX_REGFIELDS] = {
+   /* - SROT -- */
+   /* No VERSION information */
+
+   /* CNTL */
+   [TSENS_EN] = REG_FIELD(CNTL_ADDR,  0, 0),
+   [TSENS_SW_RST] = REG_FIELD(CNTL_ADDR,  1, 1),
+   /* 8960 has 5 sensors, 8660 has 11, we only handle 5 */
+   [SENSOR_EN]= REG_FIELD(CNTL_ADDR,  3, 7),
+
+   /* - TM -- */
+   /* INTERRUPT ENABLE */
+   /* NO INTERRUPT ENABLE */
+
+   /* Single UPPER/LOWER TEMPERATURE THRESHOLD for all sensors */
+   [LOW_THRESH_0]   = REG_FIELD(THRESHOLD_ADDR,  0,  7),
+   [UP_THRESH_0]= REG_FIELD(THRESHOLD_ADDR,  8, 15),
+   /* MIN_THRESH_0 and MAX_THRESH_0 are not present in the regfield
+* Recycle CRIT_THRESH_0 and 1 to set the required regs to hardcoded 
temp
+* MIN_THRESH_0 -> CRIT_THRESH_1
+* MAX_THRESH_0 -> CRIT_THRESH_0
+*/
+   [CRIT_THRESH_1]   = REG_FIELD(THRESHOLD_ADDR, 16, 23),
+   [CRIT_THRESH_0]   = REG_FIELD(THRESHOLD_ADDR, 24, 31),
+
+   /* UPPER/LOWER INTERRUPT [CLEAR/STATUS] */
+   /* 1 == clear, 0 == normal operation */
+   [LOW_INT_CLEAR_0]   = REG_FIELD(CNTL_ADDR,  9,  9),
+   [UP_INT_CLEAR_0]= REG_FIELD(CNTL_ADDR, 10, 10),
+
+   /* NO CRITICAL INTERRUPT SUPPORT on 8960 */
+
+   /* Sn_STATUS */
+   [LAST_TEMP_0]  = REG_FIELD(S0_STATUS_OFF,  0,  7),
+   [LAST_TEMP_1]  = REG_FIELD(S1_STATUS_OFF,  0,  7),
+   [LAST_TEMP_2]  = REG_FIELD(S2_STATUS_OFF,  0,  7),
+   [LAST_TEMP_3]  = REG_FIELD(S3_STATUS_OFF,  0,  7),
+   [LAST_TEMP_4]  = REG_FIELD(S4_STATUS_OFF,  0,  7),
+   [LAST_TEMP_5]  = REG_FIELD(S5_STATUS_OFF,  0,  7),
+   [LAST_TEMP_6]  = REG_FIELD(S6_STATUS_OFF,  0,  7),
+   [LAST_TEMP_7]  = REG_FIELD(S7_STATUS_OFF,  0,  7),
+   [LAST_TEMP_8]  = REG_FIELD(S8_STATUS_OFF,  0,  7),
+   [LAST_TEMP_9]  = REG_FIELD(S9_STATUS_OFF,  0,  7),
+   [LAST_TEMP_10] = REG_FIELD(S10_STATUS_OFF, 0,  7),
+
+   /* No VALID field on 8960 */
+   /* TSENS_INT_STATUS bits: 1 == threshold violated */
+   [MIN_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 0, 0),
+   [LOWER_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 1, 1),
+   [UPPER_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 2, 2),
+   /* No CRITICAL field on 8960 */
+   [MAX_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 3, 3),
+
+   /* TRDY: 1=ready, 0=in progress */
+   [TRDY] = REG_FIELD(INT_STATUS_ADDR, 7, 7),
+};
+
 static const struct tsens_ops ops_8960 = {
.init   = init_8960,
.calibrate  = calibrate_8960,
@@ -282,4 +350,5 @@ static const struct tsens_ops ops_8960 = {
 struct tsens_plat_data data_8960 = {
.num_sensors= 11,
.ops= _8960,
+   .fields = tsens_8960_regfields,
 };
-- 
2.30.2



[thermal PATCH v15 1/9] drivers: thermal: tsens: Don't hardcode sensor slope

2021-04-20 Thread Ansuel Smith
Function compute_intercept_slope hardcode the sensor slope to
SLOPE_DEFAULT. Change this and use the default value only if a slope is
not defined. This is needed for tsens VER_0 that has a hardcoded slope
table.

Signed-off-by: Ansuel Smith 
Reviewed-by: Thara Gopinath 
---
 drivers/thermal/qcom/tsens.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
index 8d3e94d2a..562c438ff 100644
--- a/drivers/thermal/qcom/tsens.c
+++ b/drivers/thermal/qcom/tsens.c
@@ -85,7 +85,8 @@ void compute_intercept_slope(struct tsens_priv *priv, u32 *p1,
"%s: sensor%d - data_point1:%#x data_point2:%#x\n",
__func__, i, p1[i], p2[i]);
 
-   priv->sensor[i].slope = SLOPE_DEFAULT;
+   if (!priv->sensor[i].slope)
+   priv->sensor[i].slope = SLOPE_DEFAULT;
if (mode == TWO_PT_CALIB) {
/*
 * slope (m) = adc_code2 - adc_code1 (y2 - y1)/
-- 
2.30.2



[thermal PATCH v15 0/9] Add support for ipq8064 tsens

2021-04-20 Thread Ansuel Smith
This patchset convert msm8960 to reg_filed, use int_common instead 
of a custom function and fix wrong tsens get_temp function for msm8960.
Ipq8064 SoCs tsens driver is based on 8960 tsens driver. Ipq8064 needs
to be registered as a gcc child as the tsens regs on this platform are
shared with the controller.
This is based on work and code here
https://git.linaro.org/people/amit.kucheria/kernel.git/log/?h=wrk3/tsens-8960-breakage

This series has already been approved but the "kernel test robot" reported
some bisect error.

v15:
* Fix bisect error reported by bot (add feat define in the VER_0 patch)
* Fix static slope table (offset -350 instead of -200 to have a more accurate 
temp)
v14:
* Fix warning reported by Dan Carpenter
v13:
* Simple reword
v12:
* Even more fix reported by Thara
v11:
* Address comments from Thara (thx)
v10:
* Fix wrong tsens init for ver_0 (crit_trips needs to be set in tsens_register)
v9:
* Fix warning from Documentation bot
v8:
* Drop MIN and MAX THRESH and use CRIT_THRESH instead
* Fix broken documentation patch
v7:
* Rework calibrate function to use get_temp_common
* Fix wrong required in the Documentation for ipq8064
* Fix hardware bug in sensor enable function
v6:
* Fix spelling error (can't find the problem with variable misallignment)
* Rework big if-else
* Remove extra comments
* Add description about different interrupts
v5:
* Conver driver to use reg_fiedl
* Use init_common 
* Drop custom set_trip and set_interrupt
* Use common set_trip and set_interrupt
* Fix bad get_temp function
* Add missing hardcoded slope
v4:
* Fix compilation error and warning reported by the bot
v3:
* Change driver to register as child instead of use phandle
v2:
* Fix dt-bindings problems

Ansuel Smith (9):
  drivers: thermal: tsens: Don't hardcode sensor slope
  drivers: thermal: tsens: Convert msm8960 to reg_field
  drivers: thermal: tsens: Add VER_0 tsens version
  drivers: thermal: tsens: Use init_common for msm8960
  drivers: thermal: tsens: Fix bug in sensor enable for msm8960
  drivers: thermal: tsens: Replace custom 8960 apis with generic apis
  drivers: thermal: tsens: Drop unused define for msm8960
  drivers: thermal: tsens: Add support for ipq8064-tsens
  dt-bindings: thermal: tsens: Document ipq8064 bindings

 .../bindings/thermal/qcom-tsens.yaml  |  56 -
 drivers/thermal/qcom/tsens-8960.c | 235 +-
 drivers/thermal/qcom/tsens.c  | 156 +---
 drivers/thermal/qcom/tsens.h  |   4 +-
 4 files changed, 293 insertions(+), 158 deletions(-)

-- 
2.30.2



[thermal-next PATCH 1/2] thermal: qcom: tsens: init debugfs only with successful probe

2021-04-18 Thread Ansuel Smith
calibrate and tsens_register can fail or PROBE_DEFER. This will cause a
double or a wrong init of the debugfs information. Init debugfs only
with successful probe fixing warning about directory already present.

Signed-off-by: Ansuel Smith 
---
 drivers/thermal/qcom/tsens.c | 9 ++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
index 4c7ebd1d3..f9d50a67e 100644
--- a/drivers/thermal/qcom/tsens.c
+++ b/drivers/thermal/qcom/tsens.c
@@ -918,8 +918,6 @@ int __init init_common(struct tsens_priv *priv)
if (tsens_version(priv) >= VER_0_1)
tsens_enable_irq(priv);
 
-   tsens_debug_init(op);
-
 err_put_device:
put_device(>dev);
return ret;
@@ -1158,7 +1156,12 @@ static int tsens_probe(struct platform_device *pdev)
}
}
 
-   return tsens_register(priv);
+   ret = tsens_register(priv);
+
+   if (!ret)
+   tsens_debug_init(pdev);
+
+   return ret;
 }
 
 static int tsens_remove(struct platform_device *pdev)
-- 
2.30.2



[thermal-next PATCH 2/2] thermal: qcom: tsens: simplify debugfs init function

2021-04-18 Thread Ansuel Smith
Simplify debugfs init function.
- Drop useless variables
- Add check for existing dev directory.
- Fix wrong version in dbg_version_show (with version 0.0.0, 0.1.0 was
  incorrectly reported)

Signed-off-by: Ansuel Smith 
---
 drivers/thermal/qcom/tsens.c | 16 +++-
 1 file changed, 7 insertions(+), 9 deletions(-)

diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
index f9d50a67e..b086d1496 100644
--- a/drivers/thermal/qcom/tsens.c
+++ b/drivers/thermal/qcom/tsens.c
@@ -692,7 +692,7 @@ static int dbg_version_show(struct seq_file *s, void *data)
return ret;
seq_printf(s, "%d.%d.%d\n", maj_ver, min_ver, step_ver);
} else {
-   seq_puts(s, "0.1.0\n");
+   seq_printf(s, "0.%d.0\n", priv->feat->ver_major);
}
 
return 0;
@@ -704,21 +704,19 @@ DEFINE_SHOW_ATTRIBUTE(dbg_sensors);
 static void tsens_debug_init(struct platform_device *pdev)
 {
struct tsens_priv *priv = platform_get_drvdata(pdev);
-   struct dentry *root, *file;
 
-   root = debugfs_lookup("tsens", NULL);
-   if (!root)
+   priv->debug_root = debugfs_lookup("tsens", NULL);
+   if (!priv->debug_root)
priv->debug_root = debugfs_create_dir("tsens", NULL);
-   else
-   priv->debug_root = root;
 
-   file = debugfs_lookup("version", priv->debug_root);
-   if (!file)
+   if (!debugfs_lookup("version", priv->debug_root))
debugfs_create_file("version", 0444, priv->debug_root,
pdev, _version_fops);
 
/* A directory for each instance of the TSENS IP */
-   priv->debug = debugfs_create_dir(dev_name(>dev), 
priv->debug_root);
+   priv->debug = debugfs_lookup(dev_name(>dev), priv->debug_root);
+   if (!priv->debug)
+   priv->debug = debugfs_create_dir(dev_name(>dev), 
priv->debug_root);
debugfs_create_file("sensors", 0444, priv->debug, pdev, 
_sensors_fops);
 }
 #else
-- 
2.30.2



Re: [PATCH RFC net-next 0/3] Multi-CPU DSA support

2021-04-12 Thread Ansuel Smith
On Sun, Apr 11, 2021 at 09:50:17PM +0300, Vladimir Oltean wrote:
> On Sun, Apr 11, 2021 at 08:01:35PM +0200, Marek Behun wrote:
> > On Sat, 10 Apr 2021 15:34:46 +0200
> > Ansuel Smith  wrote:
> > 
> > > Hi,
> > > this is a respin of the Marek series in hope that this time we can
> > > finally make some progress with dsa supporting multi-cpu port.
> > > 
> > > This implementation is similar to the Marek series but with some tweaks.
> > > This adds support for multiple-cpu port but leave the driver the
> > > decision of the type of logic to use about assigning a CPU port to the
> > > various port. The driver can also provide no preference and the CPU port
> > > is decided using a round-robin way.
> > 
> > In the last couple of months I have been giving some thought to this
> > problem, and came up with one important thing: if there are multiple
> > upstream ports, it would make a lot of sense to dynamically reallocate
> > them to each user port, based on which user port is actually used, and
> > at what speed.
> > 
> > For example on Turris Omnia we have 2 CPU ports and 5 user ports. All
> > ports support at most 1 Gbps. Round-robin would assign:
> >   CPU port 0 - Port 0
> >   CPU port 1 - Port 1
> >   CPU port 0 - Port 2
> >   CPU port 1 - Port 3
> >   CPU port 0 - Port 4
> > 
> > Now suppose that the user plugs ethernet cables only into ports 0 and 2,
> > with 1, 3 and 4 free:
> >   CPU port 0 - Port 0 (plugged)
> >   CPU port 1 - Port 1 (free)
> >   CPU port 0 - Port 2 (plugged)
> >   CPU port 1 - Port 3 (free)
> >   CPU port 0 - Port 4 (free)
> > 
> > We end up in a situation where ports 0 and 2 share 1 Gbps bandwidth to
> > CPU, and the second CPU port is not used at all.
> > 
> > A mechanism for automatic reassignment of CPU ports would be ideal here.
> > 
> > What do you guys think?
> 
> The reason why I don't think this is such a great idea is because the
> CPU port assignment is a major reconfiguration step which should at the
> very least be done while the network is down, to avoid races with the
> data path (something which this series does not appear to handle).
> And if you allow the static user-port-to-CPU-port assignment to change
> every time a link goes up/down, I don't think you really want to force
> the network down through the entire switch basically.
> 
> So I'd be tempted to say 'tough luck' if all your ports are not up, and
> the ones that are are assigned statically to the same CPU port. It's a
> compromise between flexibility and simplicity, and I would go for
> simplicity here. That's the most you can achieve with static assignment,
> just put the CPU ports in a LAG if you want better dynamic load balancing
> (for details read on below).
> 
> But this brings us to another topic, which I've been discussing with
> Florian. I am also interested in the multi CPU ports topic for the
> NXP LS1028A SoC, which uses the felix driver for its embedded switch.
> I need to explain some of the complexities there, in order to lay out
> what are the aspects which should ideally be supported.
> 
> The Ocelot switch family (which Felix is a part of) doesn't actually
> support more than one "NPI" port as it's called (when the CPU port
> module's queues are linked to an Ethernet port, which is what DSA calls
> the "CPU port"). So you'd be tempted to say that a DSA setup with
> multiple CPU ports is not realizable for this SoC.
> 
> But in fact, there are 2 Ethernet ports connecting the embedded switch
> and the CPU, one port is at 2.5Gbps and the other is at 1Gbps. We can
> dynamically choose which one is the NPI port through device tree
> (arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi), and at the moment, we
> choose the 2.5Gbps port as DSA CPU port, and we disable the 1Gbps
> internal port. If we wanted to, we could enable the second internal port
> as an internally-facing user port, but that's a bit awkward due to
> multi-homing. Nonetheless, this is all that's achievable using the NPI
> port functionality.
> 
> However, due to some unrelated issues, the Felix switch has ended up
> supporting two tagging protocols in fact. So there is now an option
> through which the user can run this command:
> 
>   echo ocelot-8021q > /sys/class/net/eno2/dsa/tagging
> 
> (where eno2 is the DSA master)
> and the switch will disable the NPI port and set up some VLAN
> pushing/popping rules through which DSA gets everything it needs to
> offer absolutely the same services towards the upper network stack
> layer, but without enabling the hardware functionality for a CP

Re: [PATCH RFC net-next 0/3] Multi-CPU DSA support

2021-04-12 Thread Ansuel Smith
On Sun, Apr 11, 2021 at 08:39:12PM +0200, Andrew Lunn wrote:
> On Sun, Apr 11, 2021 at 08:01:35PM +0200, Marek Behun wrote:
> > On Sat, 10 Apr 2021 15:34:46 +0200
> > Ansuel Smith  wrote:
> > 
> > > Hi,
> > > this is a respin of the Marek series in hope that this time we can
> > > finally make some progress with dsa supporting multi-cpu port.
> > > 
> > > This implementation is similar to the Marek series but with some tweaks.
> > > This adds support for multiple-cpu port but leave the driver the
> > > decision of the type of logic to use about assigning a CPU port to the
> > > various port. The driver can also provide no preference and the CPU port
> > > is decided using a round-robin way.
> > 
> > In the last couple of months I have been giving some thought to this
> > problem, and came up with one important thing: if there are multiple
> > upstream ports, it would make a lot of sense to dynamically reallocate
> > them to each user port, based on which user port is actually used, and
> > at what speed.
> > 
> > For example on Turris Omnia we have 2 CPU ports and 5 user ports. All
> > ports support at most 1 Gbps. Round-robin would assign:
> >   CPU port 0 - Port 0
> >   CPU port 1 - Port 1
> >   CPU port 0 - Port 2
> >   CPU port 1 - Port 3
> >   CPU port 0 - Port 4
> > 
> > Now suppose that the user plugs ethernet cables only into ports 0 and 2,
> > with 1, 3 and 4 free:
> >   CPU port 0 - Port 0 (plugged)
> >   CPU port 1 - Port 1 (free)
> >   CPU port 0 - Port 2 (plugged)
> >   CPU port 1 - Port 3 (free)
> >   CPU port 0 - Port 4 (free)
> > 
> > We end up in a situation where ports 0 and 2 share 1 Gbps bandwidth to
> > CPU, and the second CPU port is not used at all.
> > 
> > A mechanism for automatic reassignment of CPU ports would be ideal here.
> 
> One thing you need to watch out for here source MAC addresses. I've
> not looked at the details, so this is more a heads up, it needs to be
> thought about.
>
> DSA slaves get there MAC address from the master interface. For a
> single CPU port, all the slaves have the same MAC address. What
> happens when you have multiple CPU ports? Does the slave interface get
> the MAC address from its CPU port? What happens when a slave moves
> from one CPU interface to another CPU interface? Does its MAC address
> change. ARP is going to be unhappy for a while? Also, how is the
> switch deciding on which CPU port to use? Some switches are probably
> learning the MAC address being used by the interface and doing
> forwarding based on that. So you might need unique slave MAC
> addresses, and when a slave moves, it takes it MAC address with it,
> and you hope the switch learns about the move. But considered trapped
> frames as opposed to forwarded frames. So BPDU, IGMP, etc. Generally,
> you only have the choice to send such trapped frames to one CPU
> port. So potentially, such frames are going to ingress on the wrong
> port. Does this matter? What about multicast? How do you control what
> port that ingresses on? What about RX filters on the master
> interfaces? Could it be we added it to the wrong master?
> 

I think that MAC adress should be changed accordingly. If the port
doesn't have a custom mac set, it should follow the master mac and be
changed on port change. (Since this is an RFC I didn't add any lock but
I think it's needed to change also the cpu_dp and the xmit path)

> For this series to make progress, we need to know what has been
> tested, and if all the more complex functionality works, not just
> basic pings.

About testing, I'm currently using this with a qca8k switch. It looks
like all works correctly but I agree that this needs better testing of
the more complex funcionality. Anyway this series just adds the
possibility of support and change cpu port but by default keeps the
old default bheaviour. (so in theory no regression in that part)

> 
>   Andrew


Re: [PATCH RFC net-next 1/3] net: dsa: allow for multiple CPU ports

2021-04-12 Thread Ansuel Smith
On Mon, Apr 12, 2021 at 11:35:25AM +0800, DENG Qingfang wrote:
> On Sat, Apr 10, 2021 at 03:34:47PM +0200, Ansuel Smith wrote:
> > Allow for multiple CPU ports in a DSA switch tree. By default the first
> > CPU port is assigned mimic the original assignement logic. A DSA driver
> > can define a function to declare a preferred CPU port based on the
> > provided port. If the function doesn't have a preferred port the CPU
> > port is assigned using a round-robin way starting from the last assigned
> > CPU port.
> > Examples:
> > There are two CPU port but no port_get_preferred_cpu is provided:
> > - The old logic is used. Every port is assigned to the first cpu port.
> > There are two CPU port but the port_get_preferred_cpu return -1:
> > - The port is assigned using a round-robin way since no preference is
> >   provided.
> > There are two CPU port and the port_get_preferred_cpu define only one
> > port and the rest with -1: (wan port with CPU1 and the rest no
> > preference)
> >   lan1 <-> eth0
> >   lan2 <-> eth1
> >   lan3 <-> eth0
> >   lan4 <-> eth1
> >   wan  <-> eth1
> > There are two CPU port and the port_get_preferred assign a preference
> > for every port: (wan port with CPU1 everything else CPU0)
> >   lan1 <-> eth0
> >   lan2 <-> eth0
> >   lan3 <-> eth0
> >   lan4 <-> eth0
> >   wan  <-> eth1
> 
> So, drivers will read the name of every port and decide which CPU port
> does it use?
>

Yes, this seems to be an acceptable path to follow. The driver can
provide a preferred CPU port or just tell DSA that every cpu is equal
and assign them in a round-robin.

> > 
> > Signed-off-by: Marek Beh?n 
> > Signed-off-by: Ansuel Smith 


Re: [PATCH RFC net-next 0/3] Multi-CPU DSA support

2021-04-11 Thread Ansuel Smith
On Sun, Apr 11, 2021 at 08:01:35PM +0200, Marek Behun wrote:
> On Sat, 10 Apr 2021 15:34:46 +0200
> Ansuel Smith  wrote:
> 
> > Hi,
> > this is a respin of the Marek series in hope that this time we can
> > finally make some progress with dsa supporting multi-cpu port.
> > 
> > This implementation is similar to the Marek series but with some tweaks.
> > This adds support for multiple-cpu port but leave the driver the
> > decision of the type of logic to use about assigning a CPU port to the
> > various port. The driver can also provide no preference and the CPU port
> > is decided using a round-robin way.
> 
> In the last couple of months I have been giving some thought to this
> problem, and came up with one important thing: if there are multiple
> upstream ports, it would make a lot of sense to dynamically reallocate
> them to each user port, based on which user port is actually used, and
> at what speed.
> 
> For example on Turris Omnia we have 2 CPU ports and 5 user ports. All
> ports support at most 1 Gbps. Round-robin would assign:
>   CPU port 0 - Port 0
>   CPU port 1 - Port 1
>   CPU port 0 - Port 2
>   CPU port 1 - Port 3
>   CPU port 0 - Port 4
> 
> Now suppose that the user plugs ethernet cables only into ports 0 and 2,
> with 1, 3 and 4 free:
>   CPU port 0 - Port 0 (plugged)
>   CPU port 1 - Port 1 (free)
>   CPU port 0 - Port 2 (plugged)
>   CPU port 1 - Port 3 (free)
>   CPU port 0 - Port 4 (free)
> 
> We end up in a situation where ports 0 and 2 share 1 Gbps bandwidth to
> CPU, and the second CPU port is not used at all.
> 
> A mechanism for automatic reassignment of CPU ports would be ideal here.
> 
> What do you guys think?
> 
> Marek

A function called on every port change that checks the connected ports and
reassign the CPU based on that. Fact is that most of the time devices
have at least 2 ethernet port connected, one for the wan traffic and
other for some LAN device, so some type of preference from the switch
driver is needed, to also try to skip some problematic switch that have
CPU port with different supported features. A good idea but could be
overkill since we have seen at most devices with max 2 CPU port.


[PATCH RFC net-next 2/3] net: add ndo for setting the iflink property

2021-04-11 Thread Ansuel Smith
From: Marek Behún 

In DSA the iflink value is used to report to which CPU port a given
switch port is connected to. Since we want to support multi-CPU DSA, we
want the user to be able to change this value.

Add ndo_set_iflink method into the ndo strucutre to be a pair to
ndo_get_iflink. Also create dev_set_iflink and call this from the
netlink code, so that userspace can change the iflink value.

Signed-off-by: Marek Behún 
---
 include/linux/netdevice.h |  5 +
 net/core/dev.c| 15 +++
 net/core/rtnetlink.c  |  7 +++
 3 files changed, 27 insertions(+)

diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 87a5d186faff..76054182c288 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1225,6 +1225,8 @@ struct netdev_net_notifier {
  * TX queue.
  * int (*ndo_get_iflink)(const struct net_device *dev);
  * Called to get the iflink value of this device.
+ * int (*ndo_set_iflink)(struct net_device *dev, int iflink);
+ * Called to set the iflink value of this device.
  * void (*ndo_change_proto_down)(struct net_device *dev,
  *  bool proto_down);
  * This function is used to pass protocol port error state information
@@ -1456,6 +1458,8 @@ struct net_device_ops {
  int queue_index,
  u32 maxrate);
int (*ndo_get_iflink)(const struct net_device *dev);
+   int (*ndo_set_iflink)(struct net_device *dev,
+ int iflink);
int (*ndo_change_proto_down)(struct net_device *dev,
 bool proto_down);
int (*ndo_fill_metadata_dst)(struct net_device *dev,
@@ -2845,6 +2849,7 @@ void dev_add_offload(struct packet_offload *po);
 void dev_remove_offload(struct packet_offload *po);
 
 int dev_get_iflink(const struct net_device *dev);
+int dev_set_iflink(struct net_device *dev, int iflink);
 int dev_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb);
 struct net_device *__dev_get_by_flags(struct net *net, unsigned short flags,
  unsigned short mask);
diff --git a/net/core/dev.c b/net/core/dev.c
index 0f72ff5d34ba..9e5ddcf6d401 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -822,6 +822,21 @@ int dev_get_iflink(const struct net_device *dev)
 }
 EXPORT_SYMBOL(dev_get_iflink);
 
+/**
+ * dev_set_iflink - set 'iflink' value of an interface
+ * @dev: target interface
+ * @iflink: new value
+ *
+ * Change the interface to which this interface is linked to.
+ */
+int dev_set_iflink(struct net_device *dev, int iflink)
+{
+   if (dev->netdev_ops && dev->netdev_ops->ndo_set_iflink)
+   return dev->netdev_ops->ndo_set_iflink(dev, iflink);
+
+   return -EOPNOTSUPP;
+}
+
 /**
  * dev_fill_metadata_dst - Retrieve tunnel egress information.
  * @dev: targeted interface
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 1bdcb33fb561..629b7685f942 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -2718,6 +2718,13 @@ static int do_setlink(const struct sk_buff *skb,
status |= DO_SETLINK_MODIFIED;
}
 
+   if (tb[IFLA_LINK]) {
+   err = dev_set_iflink(dev, nla_get_u32(tb[IFLA_LINK]));
+   if (err)
+   goto errout;
+   status |= DO_SETLINK_MODIFIED;
+   }
+
if (tb[IFLA_CARRIER]) {
err = dev_change_carrier(dev, nla_get_u8(tb[IFLA_CARRIER]));
if (err)
-- 
2.30.2



[PATCH RFC net-next 3/3] net: dsa: implement ndo_set_netlink for chaning port's CPU port

2021-04-11 Thread Ansuel Smith
Implement ndo_set_iflink for DSA slave device. In multi-CPU port setup
this should be used to change to which CPU destination port a given port
should be connected. On CPU port change, the mac address is updated with
the new value, if not set to a custom value.

Signed-off-by: Marek Behún 
Signed-off-by: Ansuel Smith 
---
 net/dsa/slave.c | 31 +++
 1 file changed, 31 insertions(+)

diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 992fcab4b552..c68dbd3ab21a 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -63,6 +63,36 @@ static int dsa_slave_get_iflink(const struct net_device *dev)
return dsa_slave_to_master(dev)->ifindex;
 }
 
+static int dsa_slave_set_iflink(struct net_device *dev, int iflink)
+{
+   struct net_device *master = dsa_slave_to_master(dev);
+   struct dsa_port *dp = dsa_slave_to_port(dev);
+   struct dsa_slave_priv *p = netdev_priv(dev);
+   struct net_device *cpu_dev;
+   struct dsa_port *cpu_dp;
+
+   cpu_dev = dev_get_by_index(dev_net(dev), iflink);
+   if (!cpu_dev)
+   return -ENODEV;
+
+   cpu_dp = cpu_dev->dsa_ptr;
+   if (!cpu_dp)
+   return -EINVAL;
+
+   /* new CPU port has to be on the same switch tree */
+   if (cpu_dp->dst != dp->cpu_dp->dst)
+   return -EINVAL;
+
+   if (ether_addr_equal(dev->dev_addr, master->dev_addr))
+   eth_hw_addr_inherit(dev, cpu_dev);
+
+   /* should this be done atomically? */
+   dp->cpu_dp = cpu_dp;
+   p->xmit = cpu_dp->tag_ops->xmit;
+
+   return 0;
+}
+
 static int dsa_slave_open(struct net_device *dev)
 {
struct net_device *master = dsa_slave_to_master(dev);
@@ -1666,6 +1696,7 @@ static const struct net_device_ops dsa_slave_netdev_ops = 
{
.ndo_fdb_dump   = dsa_slave_fdb_dump,
.ndo_do_ioctl   = dsa_slave_ioctl,
.ndo_get_iflink = dsa_slave_get_iflink,
+   .ndo_set_iflink = dsa_slave_set_iflink,
 #ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_netpoll_setup  = dsa_slave_netpoll_setup,
.ndo_netpoll_cleanup= dsa_slave_netpoll_cleanup,
-- 
2.30.2



[PATCH RFC iproute2-next] iplink: allow to change iplink value

2021-04-11 Thread Ansuel Smith
Allow to change the interface to which a given interface is linked to.
This is useful in the case of multi-CPU port DSA, for changing the CPU
port of a given user port.

Signed-off-by: Marek Behún 
Cc: David Ahern 
Cc: Stephen Hemminger 
---
 ip/iplink.c   | 16 +---
 man/man8/ip-link.8.in |  7 +++
 2 files changed, 12 insertions(+), 11 deletions(-)

diff --git a/ip/iplink.c b/ip/iplink.c
index 212a0885..d52c0aaf 100644
--- a/ip/iplink.c
+++ b/ip/iplink.c
@@ -579,7 +579,6 @@ int iplink_parse(int argc, char **argv, struct iplink_req 
*req, char **type)
 {
char *name = NULL;
char *dev = NULL;
-   char *link = NULL;
int ret, len;
char abuf[32];
int qlen = -1;
@@ -590,6 +589,7 @@ int iplink_parse(int argc, char **argv, struct iplink_req 
*req, char **type)
int numrxqueues = -1;
int link_netnsid = -1;
int index = 0;
+   int link = -1;
int group = -1;
int addr_len = 0;
 
@@ -620,7 +620,10 @@ int iplink_parse(int argc, char **argv, struct iplink_req 
*req, char **type)
invarg("Invalid \"index\" value", *argv);
} else if (matches(*argv, "link") == 0) {
NEXT_ARG();
-   link = *argv;
+   link = ll_name_to_index(*argv);
+   if (!link)
+   return nodev(*argv);
+   addattr32(>n, sizeof(*req), IFLA_LINK, link);
} else if (matches(*argv, "address") == 0) {
NEXT_ARG();
addr_len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
@@ -1004,15 +1007,6 @@ int iplink_parse(int argc, char **argv, struct 
iplink_req *req, char **type)
exit(-1);
}
 
-   if (link) {
-   int ifindex;
-
-   ifindex = ll_name_to_index(link);
-   if (!ifindex)
-   return nodev(link);
-   addattr32(>n, sizeof(*req), IFLA_LINK, ifindex);
-   }
-
req->i.ifi_index = index;
}
 
diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in
index a8ae72d2..800aed05 100644
--- a/man/man8/ip-link.8.in
+++ b/man/man8/ip-link.8.in
@@ -149,6 +149,9 @@ ip-link \- network device configuration
 .br
 .RB "[ " nomaster " ]"
 .br
+.RB "[ " link
+.IR DEVICE " ]"
+.br
 .RB "[ " vrf
 .IR NAME " ]"
 .br
@@ -2131,6 +2134,10 @@ set master device of the device (enslave device).
 .BI nomaster
 unset master device of the device (release device).
 
+.TP
+.BI link " DEVICE"
+set device to which this device is linked to.
+
 .TP
 .BI addrgenmode " eui64|none|stable_secret|random"
 set the IPv6 address generation mode
-- 
2.21.0




[PATCH RFC net-next 1/3] net: dsa: allow for multiple CPU ports

2021-04-11 Thread Ansuel Smith
Allow for multiple CPU ports in a DSA switch tree. By default the first
CPU port is assigned mimic the original assignement logic. A DSA driver
can define a function to declare a preferred CPU port based on the
provided port. If the function doesn't have a preferred port the CPU
port is assigned using a round-robin way starting from the last assigned
CPU port.
Examples:
There are two CPU port but no port_get_preferred_cpu is provided:
- The old logic is used. Every port is assigned to the first cpu port.
There are two CPU port but the port_get_preferred_cpu return -1:
- The port is assigned using a round-robin way since no preference is
  provided.
There are two CPU port and the port_get_preferred_cpu define only one
port and the rest with -1: (wan port with CPU1 and the rest no
preference)
  lan1 <-> eth0
  lan2 <-> eth1
  lan3 <-> eth0
  lan4 <-> eth1
  wan  <-> eth1
There are two CPU port and the port_get_preferred assign a preference
for every port: (wan port with CPU1 everything else CPU0)
  lan1 <-> eth0
  lan2 <-> eth0
  lan3 <-> eth0
  lan4 <-> eth0
  wan  <-> eth1

Signed-off-by: Marek Behún 
Signed-off-by: Ansuel Smith 
---
 include/net/dsa.h |  7 +
 net/dsa/dsa2.c| 66 +--
 2 files changed, 54 insertions(+), 19 deletions(-)

diff --git a/include/net/dsa.h b/include/net/dsa.h
index d71b1acd9c3e..3d3e936bda4c 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -523,6 +523,13 @@ struct dsa_switch_ops {
void(*teardown)(struct dsa_switch *ds);
u32 (*get_phy_flags)(struct dsa_switch *ds, int port);
 
+   /*
+* Get preferred CPU port for the provided port.
+* Return -1 if there isn't a preferred CPU port, a round-robin logic
+* is used to chose the CPU port to link to the provided port.
+*/
+   int (*port_get_preferred_cpu)(struct dsa_switch *ds, int port);
+
/*
 * Access to the switch's PHY registers.
 */
diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c
index d142eb2b288b..d3b92499f006 100644
--- a/net/dsa/dsa2.c
+++ b/net/dsa/dsa2.c
@@ -315,10 +315,17 @@ static bool dsa_tree_setup_routing_table(struct 
dsa_switch_tree *dst)
return complete;
 }
 
-static struct dsa_port *dsa_tree_find_first_cpu(struct dsa_switch_tree *dst)
+static struct dsa_port *dsa_tree_find_next_cpu_port(struct dsa_switch_tree 
*dst,
+   struct dsa_port *cpu_dp)
 {
-   struct dsa_port *dp;
+   struct dsa_port *dp = cpu_dp;
+
+   if (dp)
+   list_for_each_entry_from(dp, >ports, list)
+   if (dsa_port_is_cpu(dp))
+   return dp;
 
+   /* If another CPU port can't be found, try from the start */
list_for_each_entry(dp, >ports, list)
if (dsa_port_is_cpu(dp))
return dp;
@@ -326,25 +333,40 @@ static struct dsa_port *dsa_tree_find_first_cpu(struct 
dsa_switch_tree *dst)
return NULL;
 }
 
-static int dsa_tree_setup_default_cpu(struct dsa_switch_tree *dst)
+static int dsa_tree_setup_default_cpus(struct dsa_switch_tree *dst)
 {
-   struct dsa_port *cpu_dp, *dp;
+   struct dsa_port *dp, *cpu_dp = NULL, *first_cpu_dp;
+   int cpu_port;
 
-   cpu_dp = dsa_tree_find_first_cpu(dst);
-   if (!cpu_dp) {
+   first_cpu_dp = dsa_tree_find_next_cpu_port(dst, NULL);
+   if (!first_cpu_dp) {
pr_err("DSA: tree %d has no CPU port\n", dst->index);
return -EINVAL;
}
 
-   /* Assign the default CPU port to all ports of the fabric */
list_for_each_entry(dp, >ports, list)
-   if (dsa_port_is_user(dp) || dsa_port_is_dsa(dp))
-   dp->cpu_dp = cpu_dp;
+   if (dsa_port_is_user(dp) || dsa_port_is_dsa(dp)) {
+   /* Check if the driver advice a CPU port for the 
current port */
+   if (dp->ds->ops->port_get_preferred_cpu) {
+   cpu_port = 
dp->ds->ops->port_get_preferred_cpu(dp->ds, dp->index);
+
+   /* If the driver doesn't have a preferred port,
+* assing in round-robin way.
+*/
+   if (cpu_port < 0)
+   cpu_dp = 
dsa_tree_find_next_cpu_port(dst, cpu_dp);
+   else
+   cpu_dp = dsa_to_port(dp->ds, cpu_port);
+   }
+
+   /* If a cpu port is not chosen, assign the first one by 
default */
+   dp->cpu_dp = cpu_dp ? cpu_dp : first_cpu_dp;
+   }
 
return 0;
 }
 
-static void dsa_tree_teardown_default_cpu(struct dsa_switch_tree *dst)
+stat

[PATCH RFC net-next 0/3] Multi-CPU DSA support

2021-04-11 Thread Ansuel Smith
Hi,
this is a respin of the Marek series in hope that this time we can
finally make some progress with dsa supporting multi-cpu port.

This implementation is similar to the Marek series but with some tweaks.
This adds support for multiple-cpu port but leave the driver the
decision of the type of logic to use about assigning a CPU port to the
various port. The driver can also provide no preference and the CPU port
is decided using a round-robin way.

(copying the Marek cover letter)
Patch 2 adds a new operation to the net device operations structure.
Currently we use the iflink property of a net device to report to which
CPU port a given switch port si connected to. The ip link utility from
iproute2 reports this as "lan1@eth0". We add a new net device operation,
ndo_set_iflink, which can be used to set this property. We call this
function from the netlink handlers.

Patch 3 implements this new ndo_set_iflink operation for DSA slave
device. Thus the userspace can request a change of CPU port of a given
port. The mac address is changed accordingly following the CPU port mac
address.

There are at least 2 driver that would benefit from this and currently
now works using half their capabilities. (qca8k and mv88e6xxx)
This current series is tested with qca8k. 

Ansuel Smith (1):
  net: dsa: allow for multiple CPU ports

Marek Behún (2):
  net: add ndo for setting the iflink property
  net: dsa: implement ndo_set_netlink for chaning port's CPU port

 include/linux/netdevice.h |  5 +++
 include/net/dsa.h |  7 +
 net/core/dev.c| 15 +
 net/core/rtnetlink.c  |  7 +
 net/dsa/dsa2.c| 66 ---
 net/dsa/slave.c   | 31 ++
 6 files changed, 112 insertions(+), 19 deletions(-)

-- 
2.30.2



Re: [PATCH v2 2/2] drivers: net: dsa: qca8k: add support for multiple cpu port

2021-04-09 Thread Ansuel Smith
On Fri, Apr 09, 2021 at 11:15:37AM -0700, Florian Fainelli wrote:
> 
> 
> On 4/5/2021 10:16 PM, Ansuel Smith wrote:
> > On Wed, Apr 07, 2021 at 02:41:02AM +0200, Andrew Lunn wrote:
> >> On Tue, Apr 06, 2021 at 06:50:40AM +0200, Ansuel Smith wrote:
> >>> qca8k 83xx switch have 2 cpu ports. Rework the driver to support
> >>> multiple cpu port. All ports can access both cpu ports by default as
> >>> they support the same features.
> >>
> >> Do you have more information about how this actually works. How does
> >> the switch decide which port to use when sending a frame towards the
> >> CPU? Is there some sort of load balancing?
> >>
> >> How does Linux decide which CPU port to use towards the switch?
> >>
> >> Andrew
> > 
> > I could be very wrong, but in the current dsa code, only the very first
> > cpu port is used and linux use only that to send data.
> 
> That is correct, the first CPU port that is detected by the parsing
> logic gets used.
> 
> > In theory the switch send the frame to both CPU, I'm currently testing a
> > multi-cpu patch for dsa and I can confirm that with the proposed code
> > the packets are transmitted correctly and the 2 cpu ports are used.
> > (The original code has one cpu dedicated to LAN ports and one cpu
> > dedicated to the unique WAN port.) Anyway in the current implementation
> > nothing will change. DSA code still supports one cpu and this change
> > would only allow packet to be received and trasmitted from the second
> > cpu.
> 
> That use case seems to be the most common which makes sense since it
> allows for true Gigabit routing between WAN and LAN by utilizing both
> CPUs's Ethernet controllers.
> 
> How do you currently assign a port of a switch with a particular CPU
> port this is presumably done through a separate patch that you have not
> submitted?
> -- 
> Florian

I reworked an old patch that added multi-cpu support to dsa.
CPUs are assigned in a round-robin way and they can be set with an
additional iproute command. (I read some of the comments in that RFC
series and I'm planning to introduce some type of function where the
switch driver can declare a preferred CPU port). Anyway this series is
just to try to upstream the changes that doesn't require major revision,
since they can be included even without the multi-cpu patch.



Re: [PATCH v2 2/2] drivers: net: dsa: qca8k: add support for multiple cpu port

2021-04-06 Thread Ansuel Smith
On Wed, Apr 07, 2021 at 02:41:02AM +0200, Andrew Lunn wrote:
> On Tue, Apr 06, 2021 at 06:50:40AM +0200, Ansuel Smith wrote:
> > qca8k 83xx switch have 2 cpu ports. Rework the driver to support
> > multiple cpu port. All ports can access both cpu ports by default as
> > they support the same features.
> 
> Do you have more information about how this actually works. How does
> the switch decide which port to use when sending a frame towards the
> CPU? Is there some sort of load balancing?
> 
> How does Linux decide which CPU port to use towards the switch?
> 
> Andrew

I could be very wrong, but in the current dsa code, only the very first
cpu port is used and linux use only that to send data.
In theory the switch send the frame to both CPU, I'm currently testing a
multi-cpu patch for dsa and I can confirm that with the proposed code
the packets are transmitted correctly and the 2 cpu ports are used.
(The original code has one cpu dedicated to LAN ports and one cpu
dedicated to the unique WAN port.) Anyway in the current implementation
nothing will change. DSA code still supports one cpu and this change
would only allow packet to be received and trasmitted from the second
cpu.



[PATCH v2 2/2] drivers: net: dsa: qca8k: add support for multiple cpu port

2021-04-06 Thread Ansuel Smith
qca8k 83xx switch have 2 cpu ports. Rework the driver to support
multiple cpu port. All ports can access both cpu ports by default as
they support the same features.

Signed-off-by: Ansuel Smith 
---
 drivers/net/dsa/qca8k.c | 18 +-
 drivers/net/dsa/qca8k.h |  2 --
 2 files changed, 9 insertions(+), 11 deletions(-)

diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c
index cdaf9f85a2cb..942d2a75f709 100644
--- a/drivers/net/dsa/qca8k.c
+++ b/drivers/net/dsa/qca8k.c
@@ -724,11 +724,6 @@ qca8k_setup(struct dsa_switch *ds)
/* Enable MIB counters */
qca8k_mib_init(priv);
 
-   /* Enable QCA header mode on the cpu port */
-   qca8k_write(priv, QCA8K_REG_PORT_HDR_CTRL(QCA8K_CPU_PORT),
-   QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_TX_S |
-   QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_RX_S);
-
/* Disable forwarding by default on all ports */
for (i = 0; i < QCA8K_NUM_PORTS; i++)
qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i),
@@ -749,7 +744,12 @@ qca8k_setup(struct dsa_switch *ds)
for (i = 0; i < QCA8K_NUM_PORTS; i++) {
/* CPU port gets connected to all user ports of the switch */
if (dsa_is_cpu_port(ds, i)) {
-   qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(QCA8K_CPU_PORT),
+   /* Enable QCA header mode on the cpu port */
+   qca8k_write(priv, QCA8K_REG_PORT_HDR_CTRL(i),
+   QCA8K_PORT_HDR_CTRL_ALL << 
QCA8K_PORT_HDR_CTRL_TX_S |
+   QCA8K_PORT_HDR_CTRL_ALL << 
QCA8K_PORT_HDR_CTRL_RX_S);
+
+   qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i),
  QCA8K_PORT_LOOKUP_MEMBER, dsa_user_ports(ds));
}
 
@@ -759,7 +759,7 @@ qca8k_setup(struct dsa_switch *ds)
 
qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i),
  QCA8K_PORT_LOOKUP_MEMBER,
- BIT(QCA8K_CPU_PORT));
+ dsa_cpu_ports(ds));
 
/* Enable ARP Auto-learning by default */
qca8k_reg_set(priv, QCA8K_PORT_LOOKUP_CTRL(i),
@@ -1140,7 +1140,7 @@ static int
 qca8k_port_bridge_join(struct dsa_switch *ds, int port, struct net_device *br)
 {
struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
-   int port_mask = BIT(QCA8K_CPU_PORT);
+   int port_mask = dsa_cpu_ports(ds);
int i;
 
for (i = 1; i < QCA8K_NUM_PORTS; i++) {
@@ -1183,7 +1183,7 @@ qca8k_port_bridge_leave(struct dsa_switch *ds, int port, 
struct net_device *br)
 * this port
 */
qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
- QCA8K_PORT_LOOKUP_MEMBER, BIT(QCA8K_CPU_PORT));
+ QCA8K_PORT_LOOKUP_MEMBER, dsa_cpu_ports(ds));
 }
 
 static int
diff --git a/drivers/net/dsa/qca8k.h b/drivers/net/dsa/qca8k.h
index 7ca4b93e0bb5..17bc643231c3 100644
--- a/drivers/net/dsa/qca8k.h
+++ b/drivers/net/dsa/qca8k.h
@@ -20,8 +20,6 @@
 
 #define QCA8K_NUM_FDB_RECORDS  2048
 
-#define QCA8K_CPU_PORT 0
-
 #define QCA8K_PORT_VID_DEF 1
 
 /* Global control registers */
-- 
2.30.2



[PATCH v2 1/2] include: net: add dsa_cpu_ports function

2021-04-06 Thread Ansuel Smith
In preparation for the future when dsa will support multi cpu port,
dsa_cpu_ports can be useful for switch that has multiple cpu port to
retrieve the cpu mask for ACL and bridge table.

Signed-off-by: Ansuel Smith 
---
 include/net/dsa.h | 12 
 1 file changed, 12 insertions(+)

diff --git a/include/net/dsa.h b/include/net/dsa.h
index d71b1acd9c3e..6d70a722d63f 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -458,6 +458,18 @@ static inline u32 dsa_cpu_ports(struct dsa_switch *ds)
return mask;
 }
 
+static inline u32 dsa_cpu_ports(struct dsa_switch *ds)
+{
+   u32 mask = 0;
+   int p;
+
+   for (p = 0; p < ds->num_ports; p++)
+   if (dsa_is_cpu_port(ds, p))
+   mask |= BIT(p);
+
+   return mask;
+}
+
 /* Return the local port used to reach an arbitrary switch device */
 static inline unsigned int dsa_routing_port(struct dsa_switch *ds, int device)
 {
-- 
2.30.2



[PATCH] include: net: add dsa_cpu_ports function

2021-04-06 Thread Ansuel Smith
In preparation for the future when dsa will support multi cpu port,
dsa_cpu_ports can be useful for switch that has multiple cpu port to
retrieve the cpu mask for ACL and bridge table.

Signed-off-by: Ansuel Smith 
---
 include/net/dsa.h | 12 
 1 file changed, 12 insertions(+)

diff --git a/include/net/dsa.h b/include/net/dsa.h
index 83a933e563fe..d71b1acd9c3e 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -446,6 +446,18 @@ static inline u32 dsa_user_ports(struct dsa_switch *ds)
return mask;
 }
 
+static inline u32 dsa_cpu_ports(struct dsa_switch *ds)
+{
+   u32 mask = 0;
+   int p;
+
+   for (p = 0; p < ds->num_ports; p++)
+   if (dsa_is_cpu_port(ds, p))
+   mask |= BIT(p);
+
+   return mask;
+}
+
 /* Return the local port used to reach an arbitrary switch device */
 static inline unsigned int dsa_routing_port(struct dsa_switch *ds, int device)
 {
-- 
2.30.2



[PATCH v14 9/9] dt-bindings: thermal: tsens: Document ipq8064 bindings

2021-04-04 Thread Ansuel Smith
Document the use of bindings used for msm8960 tsens based devices.
msm8960 use the same gcc regs and is set as a child of the qcom gcc.

Signed-off-by: Ansuel Smith 
Reviewed-by: Rob Herring 
---
 .../bindings/thermal/qcom-tsens.yaml  | 56 ---
 1 file changed, 48 insertions(+), 8 deletions(-)

diff --git a/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml 
b/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml
index 95462e071ab4..1785b1c75a3c 100644
--- a/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml
+++ b/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml
@@ -19,6 +19,11 @@ description: |
 properties:
   compatible:
 oneOf:
+  - description: msm9860 TSENS based
+items:
+  - enum:
+  - qcom,ipq8064-tsens
+
   - description: v0.1 of TSENS
 items:
   - enum:
@@ -73,7 +78,9 @@ properties:
 maxItems: 2
 items:
   - const: calib
-  - const: calib_sel
+  - enum:
+  - calib_backup
+  - calib_sel
 
   "#qcom,sensors":
 description:
@@ -88,12 +95,20 @@ properties:
   Number of cells required to uniquely identify the thermal sensors. Since
   we have multiple sensors this is set to 1
 
+required:
+  - compatible
+  - interrupts
+  - interrupt-names
+  - "#thermal-sensor-cells"
+  - "#qcom,sensors"
+
 allOf:
   - if:
   properties:
 compatible:
   contains:
 enum:
+  - qcom,ipq8064-tsens
   - qcom,msm8916-tsens
   - qcom,msm8974-tsens
   - qcom,msm8976-tsens
@@ -114,17 +129,42 @@ allOf:
 interrupt-names:
   minItems: 2
 
-required:
-  - compatible
-  - reg
-  - "#qcom,sensors"
-  - interrupts
-  - interrupt-names
-  - "#thermal-sensor-cells"
+  - if:
+  properties:
+compatible:
+  contains:
+enum:
+  - qcom,tsens-v0_1
+  - qcom,tsens-v1
+  - qcom,tsens-v2
+
+then:
+  required:
+- reg
 
 additionalProperties: false
 
 examples:
+  - |
+#include 
+// Example msm9860 based SoC (ipq8064):
+gcc: clock-controller {
+
+   /* ... */
+
+   tsens: thermal-sensor {
+compatible = "qcom,ipq8064-tsens";
+
+ nvmem-cells = <_calib>, <_calib_backup>;
+ nvmem-cell-names = "calib", "calib_backup";
+ interrupts = ;
+ interrupt-names = "uplow";
+
+ #qcom,sensors = <11>;
+ #thermal-sensor-cells = <1>;
+  };
+};
+
   - |
 #include 
 // Example 1 (legacy: for pre v1 IP):
-- 
2.30.2



[PATCH v14 7/9] drivers: thermal: tsens: Drop unused define for msm8960

2021-04-04 Thread Ansuel Smith
Drop unused define for msm8960 replaced by generic api and reg_field.

Signed-off-by: Ansuel Smith 
Reviewed-by: Thara Gopinath 
---
 drivers/thermal/qcom/tsens-8960.c | 24 +---
 1 file changed, 1 insertion(+), 23 deletions(-)

diff --git a/drivers/thermal/qcom/tsens-8960.c 
b/drivers/thermal/qcom/tsens-8960.c
index 9cc8a7dd23ae..58d09e927383 100644
--- a/drivers/thermal/qcom/tsens-8960.c
+++ b/drivers/thermal/qcom/tsens-8960.c
@@ -10,8 +10,6 @@
 #include 
 #include "tsens.h"
 
-#define CAL_MDEGC  3
-
 #define CONFIG_ADDR0x3640
 #define CONFIG_ADDR_8660   0x3620
 /* CONFIG_ADDR bitmasks */
@@ -21,39 +19,19 @@
 #define CONFIG_SHIFT_8660  28
 #define CONFIG_MASK_8660   (3 << CONFIG_SHIFT_8660)
 
-#define STATUS_CNTL_ADDR_8064  0x3660
 #define CNTL_ADDR  0x3620
 /* CNTL_ADDR bitmasks */
 #define EN BIT(0)
 #define SW_RST BIT(1)
-#define SENSOR0_EN BIT(3)
+
 #define MEASURE_PERIOD BIT(18)
 #define SLP_CLK_ENABIT(26)
 #define SLP_CLK_ENA_8660   BIT(24)
 #define SENSOR0_SHIFT  3
 
-/* INT_STATUS_ADDR bitmasks */
-#define MIN_STATUS_MASKBIT(0)
-#define LOWER_STATUS_CLR   BIT(1)
-#define UPPER_STATUS_CLR   BIT(2)
-#define MAX_STATUS_MASKBIT(3)
-
 #define THRESHOLD_ADDR 0x3624
-/* THRESHOLD_ADDR bitmasks */
-#define THRESHOLD_MAX_LIMIT_SHIFT  24
-#define THRESHOLD_MIN_LIMIT_SHIFT  16
-#define THRESHOLD_UPPER_LIMIT_SHIFT8
-#define THRESHOLD_LOWER_LIMIT_SHIFT0
-
-/* Initial temperature threshold values */
-#define LOWER_LIMIT_TH 0x50
-#define UPPER_LIMIT_TH 0xdf
-#define MIN_LIMIT_TH   0x0
-#define MAX_LIMIT_TH   0xff
 
 #define INT_STATUS_ADDR0x363c
-#define TRDY_MASK  BIT(7)
-#define TIMEOUT_US 100
 
 #define S0_STATUS_OFF  0x3628
 #define S1_STATUS_OFF  0x362c
-- 
2.30.2



[PATCH v14 8/9] drivers: thermal: tsens: Add support for ipq8064-tsens

2021-04-04 Thread Ansuel Smith
Add support for tsens present in ipq806x SoCs based on generic msm8960
tsens driver.

Signed-off-by: Ansuel Smith 
Reviewed-by: Thara Gopinath 
---
 drivers/thermal/qcom/tsens.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
index 38b9936def1a..58073dc5d30b 100644
--- a/drivers/thermal/qcom/tsens.c
+++ b/drivers/thermal/qcom/tsens.c
@@ -966,6 +966,9 @@ static SIMPLE_DEV_PM_OPS(tsens_pm_ops, tsens_suspend, 
tsens_resume);
 
 static const struct of_device_id tsens_table[] = {
{
+   .compatible = "qcom,ipq8064-tsens",
+   .data = _8960,
+   }, {
.compatible = "qcom,msm8916-tsens",
.data = _8916,
}, {
-- 
2.30.2



[PATCH v14 6/9] drivers: thermal: tsens: Replace custom 8960 apis with generic apis

2021-04-04 Thread Ansuel Smith
Rework calibrate function to use common function. Derive the offset from
a missing hardcoded slope table and the data from the nvmem calib
efuses.
Drop custom get_temp function and use generic api.

Signed-off-by: Ansuel Smith 
Acked-by: Thara Gopinath 
---
 drivers/thermal/qcom/tsens-8960.c | 56 +--
 1 file changed, 15 insertions(+), 41 deletions(-)

diff --git a/drivers/thermal/qcom/tsens-8960.c 
b/drivers/thermal/qcom/tsens-8960.c
index 95fcccafae14..9cc8a7dd23ae 100644
--- a/drivers/thermal/qcom/tsens-8960.c
+++ b/drivers/thermal/qcom/tsens-8960.c
@@ -67,6 +67,13 @@
 #define S9_STATUS_OFF  0x3674
 #define S10_STATUS_OFF 0x3678
 
+/* Original slope - 200 to compensate mC to C inaccuracy */
+static u32 tsens_msm8960_slope[] = {
+   976, 976, 954, 976,
+   911, 932, 932, 999,
+   932, 999, 932
+   };
+
 static int suspend_8960(struct tsens_priv *priv)
 {
int ret;
@@ -194,9 +201,7 @@ static int calibrate_8960(struct tsens_priv *priv)
 {
int i;
char *data;
-
-   ssize_t num_read = priv->num_sensors;
-   struct tsens_sensor *s = priv->sensor;
+   u32 p1[11];
 
data = qfprom_read(priv->dev, "calib");
if (IS_ERR(data))
@@ -204,49 +209,18 @@ static int calibrate_8960(struct tsens_priv *priv)
if (IS_ERR(data))
return PTR_ERR(data);
 
-   for (i = 0; i < num_read; i++, s++)
-   s->offset = data[i];
+   for (i = 0; i < priv->num_sensors; i++) {
+   p1[i] = data[i];
+   priv->sensor[i].slope = tsens_msm8960_slope[i];
+   }
+
+   compute_intercept_slope(priv, p1, NULL, ONE_PT_CALIB);
 
kfree(data);
 
return 0;
 }
 
-/* Temperature on y axis and ADC-code on x-axis */
-static inline int code_to_mdegC(u32 adc_code, const struct tsens_sensor *s)
-{
-   int slope, offset;
-
-   slope = thermal_zone_get_slope(s->tzd);
-   offset = CAL_MDEGC - slope * s->offset;
-
-   return adc_code * slope + offset;
-}
-
-static int get_temp_8960(const struct tsens_sensor *s, int *temp)
-{
-   int ret;
-   u32 code, trdy;
-   struct tsens_priv *priv = s->priv;
-   unsigned long timeout;
-
-   timeout = jiffies + usecs_to_jiffies(TIMEOUT_US);
-   do {
-   ret = regmap_read(priv->tm_map, INT_STATUS_ADDR, );
-   if (ret)
-   return ret;
-   if (!(trdy & TRDY_MASK))
-   continue;
-   ret = regmap_read(priv->tm_map, s->status, );
-   if (ret)
-   return ret;
-   *temp = code_to_mdegC(code, s);
-   return 0;
-   } while (time_before(jiffies, timeout));
-
-   return -ETIMEDOUT;
-}
-
 static struct tsens_features tsens_8960_feat = {
.ver_major  = VER_0,
.crit_int   = 0,
@@ -315,7 +289,7 @@ static const struct reg_field 
tsens_8960_regfields[MAX_REGFIELDS] = {
 static const struct tsens_ops ops_8960 = {
.init   = init_common,
.calibrate  = calibrate_8960,
-   .get_temp   = get_temp_8960,
+   .get_temp   = get_temp_common,
.enable = enable_8960,
.disable= disable_8960,
.suspend= suspend_8960,
-- 
2.30.2



[PATCH v14 5/9] drivers: thermal: tsens: Fix bug in sensor enable for msm8960

2021-04-04 Thread Ansuel Smith
Device based on tsens VER_0 contains a hardware bug that results in some
problem with sensor enablement. Sensor id 6-11 can't be enabled
selectively and all of them must be enabled in one step.

Signed-off-by: Ansuel Smith 
Acked-by: Thara Gopinath 
---
 drivers/thermal/qcom/tsens-8960.c | 23 ---
 1 file changed, 20 insertions(+), 3 deletions(-)

diff --git a/drivers/thermal/qcom/tsens-8960.c 
b/drivers/thermal/qcom/tsens-8960.c
index 86585f439985..95fcccafae14 100644
--- a/drivers/thermal/qcom/tsens-8960.c
+++ b/drivers/thermal/qcom/tsens-8960.c
@@ -27,9 +27,9 @@
 #define EN BIT(0)
 #define SW_RST BIT(1)
 #define SENSOR0_EN BIT(3)
+#define MEASURE_PERIOD BIT(18)
 #define SLP_CLK_ENABIT(26)
 #define SLP_CLK_ENA_8660   BIT(24)
-#define MEASURE_PERIOD 1
 #define SENSOR0_SHIFT  3
 
 /* INT_STATUS_ADDR bitmasks */
@@ -126,17 +126,34 @@ static int resume_8960(struct tsens_priv *priv)
 static int enable_8960(struct tsens_priv *priv, int id)
 {
int ret;
-   u32 reg, mask;
+   u32 reg, mask = BIT(id);
 
ret = regmap_read(priv->tm_map, CNTL_ADDR, );
if (ret)
return ret;
 
-   mask = BIT(id + SENSOR0_SHIFT);
+   /* HARDWARE BUG:
+* On platforms with more than 6 sensors, all remaining sensors
+* must be enabled together, otherwise undefined results are expected.
+* (Sensor 6-7 disabled, Sensor 3 disabled...) In the original driver,
+* all the sensors are enabled in one step hence this bug is not
+* triggered.
+*/
+   if (id > 5)
+   mask = GENMASK(10, 6);
+
+   mask <<= SENSOR0_SHIFT;
+
+   /* Sensors already enabled. Skip. */
+   if ((reg & mask) == mask)
+   return 0;
+
ret = regmap_write(priv->tm_map, CNTL_ADDR, reg | SW_RST);
if (ret)
return ret;
 
+   reg |= MEASURE_PERIOD;
+
if (priv->num_sensors > 1)
reg |= mask | SLP_CLK_ENA | EN;
else
-- 
2.30.2



[PATCH v14 4/9] drivers: thermal: tsens: Use init_common for msm8960

2021-04-04 Thread Ansuel Smith
Use init_common and drop custom init for msm8960.

Signed-off-by: Ansuel Smith 
Reviewed-by: Thara Gopinath 
---
 drivers/thermal/qcom/tsens-8960.c | 52 +--
 1 file changed, 1 insertion(+), 51 deletions(-)

diff --git a/drivers/thermal/qcom/tsens-8960.c 
b/drivers/thermal/qcom/tsens-8960.c
index 3f4fc1ffe679..86585f439985 100644
--- a/drivers/thermal/qcom/tsens-8960.c
+++ b/drivers/thermal/qcom/tsens-8960.c
@@ -173,56 +173,6 @@ static void disable_8960(struct tsens_priv *priv)
regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
 }
 
-static int init_8960(struct tsens_priv *priv)
-{
-   int ret, i;
-   u32 reg_cntl;
-
-   priv->tm_map = dev_get_regmap(priv->dev, NULL);
-   if (!priv->tm_map)
-   return -ENODEV;
-
-   /*
-* The status registers for each sensor are discontiguous
-* because some SoCs have 5 sensors while others have more
-* but the control registers stay in the same place, i.e
-* directly after the first 5 status registers.
-*/
-   for (i = 0; i < priv->num_sensors; i++) {
-   if (i >= 5)
-   priv->sensor[i].status = S0_STATUS_ADDR + 40;
-   priv->sensor[i].status += i * 4;
-   }
-
-   reg_cntl = SW_RST;
-   ret = regmap_update_bits(priv->tm_map, CNTL_ADDR, SW_RST, reg_cntl);
-   if (ret)
-   return ret;
-
-   if (priv->num_sensors > 1) {
-   reg_cntl |= SLP_CLK_ENA | (MEASURE_PERIOD << 18);
-   reg_cntl &= ~SW_RST;
-   ret = regmap_update_bits(priv->tm_map, CONFIG_ADDR,
-CONFIG_MASK, CONFIG);
-   } else {
-   reg_cntl |= SLP_CLK_ENA_8660 | (MEASURE_PERIOD << 16);
-   reg_cntl &= ~CONFIG_MASK_8660;
-   reg_cntl |= CONFIG_8660 << CONFIG_SHIFT_8660;
-   }
-
-   reg_cntl |= GENMASK(priv->num_sensors - 1, 0) << SENSOR0_SHIFT;
-   ret = regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
-   if (ret)
-   return ret;
-
-   reg_cntl |= EN;
-   ret = regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
-   if (ret)
-   return ret;
-
-   return 0;
-}
-
 static int calibrate_8960(struct tsens_priv *priv)
 {
int i;
@@ -346,7 +296,7 @@ static const struct reg_field 
tsens_8960_regfields[MAX_REGFIELDS] = {
 };
 
 static const struct tsens_ops ops_8960 = {
-   .init   = init_8960,
+   .init   = init_common,
.calibrate  = calibrate_8960,
.get_temp   = get_temp_8960,
.enable = enable_8960,
-- 
2.30.2



[PATCH v14 3/9] drivers: thermal: tsens: Convert msm8960 to reg_field

2021-04-04 Thread Ansuel Smith
Convert msm9860 driver to reg_field to use the init_common
function.

Signed-off-by: Ansuel Smith 
Acked-by: Thara Gopinath 
---
 drivers/thermal/qcom/tsens-8960.c | 80 ++-
 1 file changed, 79 insertions(+), 1 deletion(-)

diff --git a/drivers/thermal/qcom/tsens-8960.c 
b/drivers/thermal/qcom/tsens-8960.c
index 2a28a5af209e..3f4fc1ffe679 100644
--- a/drivers/thermal/qcom/tsens-8960.c
+++ b/drivers/thermal/qcom/tsens-8960.c
@@ -51,11 +51,22 @@
 #define MIN_LIMIT_TH   0x0
 #define MAX_LIMIT_TH   0xff
 
-#define S0_STATUS_ADDR 0x3628
 #define INT_STATUS_ADDR0x363c
 #define TRDY_MASK  BIT(7)
 #define TIMEOUT_US 100
 
+#define S0_STATUS_OFF  0x3628
+#define S1_STATUS_OFF  0x362c
+#define S2_STATUS_OFF  0x3630
+#define S3_STATUS_OFF  0x3634
+#define S4_STATUS_OFF  0x3638
+#define S5_STATUS_OFF  0x3664  /* Sensors 5-10 found on 
apq8064/msm8960 */
+#define S6_STATUS_OFF  0x3668
+#define S7_STATUS_OFF  0x366c
+#define S8_STATUS_OFF  0x3670
+#define S9_STATUS_OFF  0x3674
+#define S10_STATUS_OFF 0x3678
+
 static int suspend_8960(struct tsens_priv *priv)
 {
int ret;
@@ -269,6 +280,71 @@ static int get_temp_8960(const struct tsens_sensor *s, int 
*temp)
return -ETIMEDOUT;
 }
 
+static struct tsens_features tsens_8960_feat = {
+   .ver_major  = VER_0,
+   .crit_int   = 0,
+   .adc= 1,
+   .srot_split = 0,
+   .max_sensors= 11,
+};
+
+static const struct reg_field tsens_8960_regfields[MAX_REGFIELDS] = {
+   /* - SROT -- */
+   /* No VERSION information */
+
+   /* CNTL */
+   [TSENS_EN] = REG_FIELD(CNTL_ADDR,  0, 0),
+   [TSENS_SW_RST] = REG_FIELD(CNTL_ADDR,  1, 1),
+   /* 8960 has 5 sensors, 8660 has 11, we only handle 5 */
+   [SENSOR_EN]= REG_FIELD(CNTL_ADDR,  3, 7),
+
+   /* - TM -- */
+   /* INTERRUPT ENABLE */
+   /* NO INTERRUPT ENABLE */
+
+   /* Single UPPER/LOWER TEMPERATURE THRESHOLD for all sensors */
+   [LOW_THRESH_0]   = REG_FIELD(THRESHOLD_ADDR,  0,  7),
+   [UP_THRESH_0]= REG_FIELD(THRESHOLD_ADDR,  8, 15),
+   /* MIN_THRESH_0 and MAX_THRESH_0 are not present in the regfield
+* Recycle CRIT_THRESH_0 and 1 to set the required regs to hardcoded 
temp
+* MIN_THRESH_0 -> CRIT_THRESH_1
+* MAX_THRESH_0 -> CRIT_THRESH_0
+*/
+   [CRIT_THRESH_1]   = REG_FIELD(THRESHOLD_ADDR, 16, 23),
+   [CRIT_THRESH_0]   = REG_FIELD(THRESHOLD_ADDR, 24, 31),
+
+   /* UPPER/LOWER INTERRUPT [CLEAR/STATUS] */
+   /* 1 == clear, 0 == normal operation */
+   [LOW_INT_CLEAR_0]   = REG_FIELD(CNTL_ADDR,  9,  9),
+   [UP_INT_CLEAR_0]= REG_FIELD(CNTL_ADDR, 10, 10),
+
+   /* NO CRITICAL INTERRUPT SUPPORT on 8960 */
+
+   /* Sn_STATUS */
+   [LAST_TEMP_0]  = REG_FIELD(S0_STATUS_OFF,  0,  7),
+   [LAST_TEMP_1]  = REG_FIELD(S1_STATUS_OFF,  0,  7),
+   [LAST_TEMP_2]  = REG_FIELD(S2_STATUS_OFF,  0,  7),
+   [LAST_TEMP_3]  = REG_FIELD(S3_STATUS_OFF,  0,  7),
+   [LAST_TEMP_4]  = REG_FIELD(S4_STATUS_OFF,  0,  7),
+   [LAST_TEMP_5]  = REG_FIELD(S5_STATUS_OFF,  0,  7),
+   [LAST_TEMP_6]  = REG_FIELD(S6_STATUS_OFF,  0,  7),
+   [LAST_TEMP_7]  = REG_FIELD(S7_STATUS_OFF,  0,  7),
+   [LAST_TEMP_8]  = REG_FIELD(S8_STATUS_OFF,  0,  7),
+   [LAST_TEMP_9]  = REG_FIELD(S9_STATUS_OFF,  0,  7),
+   [LAST_TEMP_10] = REG_FIELD(S10_STATUS_OFF, 0,  7),
+
+   /* No VALID field on 8960 */
+   /* TSENS_INT_STATUS bits: 1 == threshold violated */
+   [MIN_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 0, 0),
+   [LOWER_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 1, 1),
+   [UPPER_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 2, 2),
+   /* No CRITICAL field on 8960 */
+   [MAX_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 3, 3),
+
+   /* TRDY: 1=ready, 0=in progress */
+   [TRDY] = REG_FIELD(INT_STATUS_ADDR, 7, 7),
+};
+
 static const struct tsens_ops ops_8960 = {
.init   = init_8960,
.calibrate  = calibrate_8960,
@@ -282,4 +358,6 @@ static const struct tsens_ops ops_8960 = {
 struct tsens_plat_data data_8960 = {
.num_sensors= 11,
.ops= _8960,
+   .feat   = _8960_feat,
+   .fields = tsens_8960_regfields,
 };
-- 
2.30.2



[PATCH v14 1/9] drivers: thermal: tsens: Add VER_0 tsens version

2021-04-04 Thread Ansuel Smith
VER_0 is used to describe device based on tsens version before v0.1.
These device are devices based on msm8960 for example apq8064 or
ipq806x.

Signed-off-by: Ansuel Smith 
Reviewed-by: Thara Gopinath 
Reported-by: kernel test robot 
Reported-by: Dan Carpenter 
---
 drivers/thermal/qcom/tsens.c | 150 ---
 drivers/thermal/qcom/tsens.h |   4 +-
 2 files changed, 124 insertions(+), 30 deletions(-)

diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
index d8ce3a687b80..9a7e991d4bd2 100644
--- a/drivers/thermal/qcom/tsens.c
+++ b/drivers/thermal/qcom/tsens.c
@@ -12,6 +12,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -515,6 +516,15 @@ static irqreturn_t tsens_irq_thread(int irq, void *data)
dev_dbg(priv->dev, "[%u] %s: no violation:  %d\n",
hw_id, __func__, temp);
}
+
+   if (tsens_version(priv) < VER_0_1) {
+   /* Constraint: There is only 1 interrupt control 
register for all
+* 11 temperature sensor. So monitoring more than 1 
sensor based
+* on interrupts will yield inconsistent result. To 
overcome this
+* issue we will monitor only sensor 0 which is the 
master sensor.
+*/
+   break;
+   }
}
 
return IRQ_HANDLED;
@@ -530,6 +540,13 @@ static int tsens_set_trips(void *_sensor, int low, int 
high)
int high_val, low_val, cl_high, cl_low;
u32 hw_id = s->hw_id;
 
+   if (tsens_version(priv) < VER_0_1) {
+   /* Pre v0.1 IP had a single register for each type of interrupt
+* and thresholds
+*/
+   hw_id = 0;
+   }
+
dev_dbg(dev, "[%u] %s: proposed thresholds: (%d:%d)\n",
hw_id, __func__, low, high);
 
@@ -584,18 +601,21 @@ int get_temp_tsens_valid(const struct tsens_sensor *s, 
int *temp)
u32 valid;
int ret;
 
-   ret = regmap_field_read(priv->rf[valid_idx], );
-   if (ret)
-   return ret;
-   while (!valid) {
-   /* Valid bit is 0 for 6 AHB clock cycles.
-* At 19.2MHz, 1 AHB clock is ~60ns.
-* We should enter this loop very, very rarely.
-*/
-   ndelay(400);
+   /* VER_0 doesn't have VALID bit */
+   if (tsens_version(priv) >= VER_0_1) {
ret = regmap_field_read(priv->rf[valid_idx], );
if (ret)
return ret;
+   while (!valid) {
+   /* Valid bit is 0 for 6 AHB clock cycles.
+* At 19.2MHz, 1 AHB clock is ~60ns.
+* We should enter this loop very, very rarely.
+*/
+   ndelay(400);
+   ret = regmap_field_read(priv->rf[valid_idx], );
+   if (ret)
+   return ret;
+   }
}
 
/* Valid bit is set, OK to read the temperature */
@@ -608,15 +628,29 @@ int get_temp_common(const struct tsens_sensor *s, int 
*temp)
 {
struct tsens_priv *priv = s->priv;
int hw_id = s->hw_id;
-   int last_temp = 0, ret;
+   int last_temp = 0, ret, trdy;
+   unsigned long timeout;
 
-   ret = regmap_field_read(priv->rf[LAST_TEMP_0 + hw_id], _temp);
-   if (ret)
-   return ret;
+   timeout = jiffies + usecs_to_jiffies(TIMEOUT_US);
+   do {
+   if (tsens_version(priv) == VER_0) {
+   ret = regmap_field_read(priv->rf[TRDY], );
+   if (ret)
+   return ret;
+   if (!trdy)
+   continue;
+   }
 
-   *temp = code_to_degc(last_temp, s) * 1000;
+   ret = regmap_field_read(priv->rf[LAST_TEMP_0 + hw_id], 
_temp);
+   if (ret)
+   return ret;
 
-   return 0;
+   *temp = code_to_degc(last_temp, s) * 1000;
+
+   return 0;
+   } while (time_before(jiffies, timeout));
+
+   return -ETIMEDOUT;
 }
 
 #ifdef CONFIG_DEBUG_FS
@@ -738,19 +772,34 @@ int __init init_common(struct tsens_priv *priv)
priv->tm_offset = 0x1000;
}
 
-   res = platform_get_resource(op, IORESOURCE_MEM, 0);
-   tm_base = devm_ioremap_resource(dev, res);
-   if (IS_ERR(tm_base)) {
-   ret = PTR_ERR(tm_base);
-   goto err_put_device;
+   if (tsens_version(priv) >= VER_0_1) {
+   res = platform_get_resource(op, IORESOURCE_MEM, 0);
+   tm_base = devm_ioremap_resource(dev, res);
+   if (IS_ERR(tm_base)) {
+   re

[PATCH v14 2/9] drivers: thermal: tsens: Don't hardcode sensor slope

2021-04-04 Thread Ansuel Smith
Function compute_intercept_slope hardcode the sensor slope to
SLOPE_DEFAULT. Change this and use the default value only if a slope is
not defined. This is needed for tsens VER_0 that has a hardcoded slope
table.

Signed-off-by: Ansuel Smith 
Reviewed-by: Thara Gopinath 
---
 drivers/thermal/qcom/tsens.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
index 9a7e991d4bd2..38b9936def1a 100644
--- a/drivers/thermal/qcom/tsens.c
+++ b/drivers/thermal/qcom/tsens.c
@@ -86,7 +86,8 @@ void compute_intercept_slope(struct tsens_priv *priv, u32 *p1,
"%s: sensor%d - data_point1:%#x data_point2:%#x\n",
__func__, i, p1[i], p2[i]);
 
-   priv->sensor[i].slope = SLOPE_DEFAULT;
+   if (!priv->sensor[i].slope)
+   priv->sensor[i].slope = SLOPE_DEFAULT;
if (mode == TWO_PT_CALIB) {
/*
 * slope (m) = adc_code2 - adc_code1 (y2 - y1)/
-- 
2.30.2



[PATCH v14 0/9] Add support for ipq8064 tsens

2021-04-04 Thread Ansuel Smith
This patchset convert msm8960 to reg_filed, use int_common instead 
of a custom function and fix wrong tsens get_temp function for msm8960.
Ipq8064 SoCs tsens driver is based on 8960 tsens driver. Ipq8064 needs
to be registered as a gcc child as the tsens regs on this platform are
shared with the controller.
This is based on work and code here
https://git.linaro.org/people/amit.kucheria/kernel.git/log/?h=wrk3/tsens-8960-breakage

v14:
* Fix warning reported by Dan Carpenter
v13:
* Simple reword
v12:
* Even more fix reported by Thara
v11:
* Address comments from Thara (thx)
v10:
* Fix wrong tsens init for ver_0 (crit_trips needs to be set in tsens_register)
v9:
* Fix warning from Documentation bot
v8:
* Drop MIN and MAX THRESH and use CRIT_THRESH instead
* Fix broken documentation patch
v7:
* Rework calibrate function to use get_temp_common
* Fix wrong required in the Documentation for ipq8064
* Fix hardware bug in sensor enable function
v6:
* Fix spelling error (can't find the problem with variable misallignment)
* Rework big if-else
* Remove extra comments
* Add description about different interrupts
v5:
* Conver driver to use reg_fiedl
* Use init_common 
* Drop custom set_trip and set_interrupt
* Use common set_trip and set_interrupt
* Fix bad get_temp function
* Add missing hardcoded slope
v4:
* Fix compilation error and warning reported by the bot
v3:
* Change driver to register as child instead of use phandle
v2:
* Fix dt-bindings problems

Ansuel Smith (9):
  drivers: thermal: tsens: Add VER_0 tsens version
  drivers: thermal: tsens: Don't hardcode sensor slope
  drivers: thermal: tsens: Convert msm8960 to reg_field
  drivers: thermal: tsens: Use init_common for msm8960
  drivers: thermal: tsens: Fix bug in sensor enable for msm8960
  drivers: thermal: tsens: Replace custom 8960 apis with generic apis
  drivers: thermal: tsens: Drop unused define for msm8960
  drivers: thermal: tsens: Add support for ipq8064-tsens
  dt-bindings: thermal: tsens: Document ipq8064 bindings

 .../bindings/thermal/qcom-tsens.yaml  |  56 -
 drivers/thermal/qcom/tsens-8960.c | 233 +-
 drivers/thermal/qcom/tsens.c  | 156 +---
 drivers/thermal/qcom/tsens.h  |   4 +-
 4 files changed, 292 insertions(+), 157 deletions(-)

-- 
2.30.2



[PATCH v13 8/9] drivers: thermal: tsens: Add support for ipq8064-tsens

2021-03-24 Thread Ansuel Smith
Add support for tsens present in ipq806x SoCs based on generic msm8960
tsens driver.

Signed-off-by: Ansuel Smith 
Reviewed-by: Thara Gopinath 
---
 drivers/thermal/qcom/tsens.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
index 6da567de1db7..df04e96c2044 100644
--- a/drivers/thermal/qcom/tsens.c
+++ b/drivers/thermal/qcom/tsens.c
@@ -963,6 +963,9 @@ static SIMPLE_DEV_PM_OPS(tsens_pm_ops, tsens_suspend, 
tsens_resume);
 
 static const struct of_device_id tsens_table[] = {
{
+   .compatible = "qcom,ipq8064-tsens",
+   .data = _8960,
+   }, {
.compatible = "qcom,msm8916-tsens",
.data = _8916,
}, {
-- 
2.30.2



[PATCH v13 9/9] dt-bindings: thermal: tsens: Document ipq8064 bindings

2021-03-24 Thread Ansuel Smith
Document the use of bindings used for msm8960 tsens based devices.
msm8960 use the same gcc regs and is set as a child of the qcom gcc.

Signed-off-by: Ansuel Smith 
Reviewed-by: Rob Herring 
---
 .../bindings/thermal/qcom-tsens.yaml  | 56 ---
 1 file changed, 48 insertions(+), 8 deletions(-)

diff --git a/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml 
b/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml
index 95462e071ab4..1785b1c75a3c 100644
--- a/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml
+++ b/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml
@@ -19,6 +19,11 @@ description: |
 properties:
   compatible:
 oneOf:
+  - description: msm9860 TSENS based
+items:
+  - enum:
+  - qcom,ipq8064-tsens
+
   - description: v0.1 of TSENS
 items:
   - enum:
@@ -73,7 +78,9 @@ properties:
 maxItems: 2
 items:
   - const: calib
-  - const: calib_sel
+  - enum:
+  - calib_backup
+  - calib_sel
 
   "#qcom,sensors":
 description:
@@ -88,12 +95,20 @@ properties:
   Number of cells required to uniquely identify the thermal sensors. Since
   we have multiple sensors this is set to 1
 
+required:
+  - compatible
+  - interrupts
+  - interrupt-names
+  - "#thermal-sensor-cells"
+  - "#qcom,sensors"
+
 allOf:
   - if:
   properties:
 compatible:
   contains:
 enum:
+  - qcom,ipq8064-tsens
   - qcom,msm8916-tsens
   - qcom,msm8974-tsens
   - qcom,msm8976-tsens
@@ -114,17 +129,42 @@ allOf:
 interrupt-names:
   minItems: 2
 
-required:
-  - compatible
-  - reg
-  - "#qcom,sensors"
-  - interrupts
-  - interrupt-names
-  - "#thermal-sensor-cells"
+  - if:
+  properties:
+compatible:
+  contains:
+enum:
+  - qcom,tsens-v0_1
+  - qcom,tsens-v1
+  - qcom,tsens-v2
+
+then:
+  required:
+- reg
 
 additionalProperties: false
 
 examples:
+  - |
+#include 
+// Example msm9860 based SoC (ipq8064):
+gcc: clock-controller {
+
+   /* ... */
+
+   tsens: thermal-sensor {
+compatible = "qcom,ipq8064-tsens";
+
+ nvmem-cells = <_calib>, <_calib_backup>;
+ nvmem-cell-names = "calib", "calib_backup";
+ interrupts = ;
+ interrupt-names = "uplow";
+
+ #qcom,sensors = <11>;
+ #thermal-sensor-cells = <1>;
+  };
+};
+
   - |
 #include 
 // Example 1 (legacy: for pre v1 IP):
-- 
2.30.2



[PATCH v13 7/9] drivers: thermal: tsens: Drop unused define for msm8960

2021-03-24 Thread Ansuel Smith
Drop unused define for msm8960 replaced by generic api and reg_field.

Signed-off-by: Ansuel Smith 
Reviewed-by: Thara Gopinath 
---
 drivers/thermal/qcom/tsens-8960.c | 24 +---
 1 file changed, 1 insertion(+), 23 deletions(-)

diff --git a/drivers/thermal/qcom/tsens-8960.c 
b/drivers/thermal/qcom/tsens-8960.c
index 9cc8a7dd23ae..58d09e927383 100644
--- a/drivers/thermal/qcom/tsens-8960.c
+++ b/drivers/thermal/qcom/tsens-8960.c
@@ -10,8 +10,6 @@
 #include 
 #include "tsens.h"
 
-#define CAL_MDEGC  3
-
 #define CONFIG_ADDR0x3640
 #define CONFIG_ADDR_8660   0x3620
 /* CONFIG_ADDR bitmasks */
@@ -21,39 +19,19 @@
 #define CONFIG_SHIFT_8660  28
 #define CONFIG_MASK_8660   (3 << CONFIG_SHIFT_8660)
 
-#define STATUS_CNTL_ADDR_8064  0x3660
 #define CNTL_ADDR  0x3620
 /* CNTL_ADDR bitmasks */
 #define EN BIT(0)
 #define SW_RST BIT(1)
-#define SENSOR0_EN BIT(3)
+
 #define MEASURE_PERIOD BIT(18)
 #define SLP_CLK_ENABIT(26)
 #define SLP_CLK_ENA_8660   BIT(24)
 #define SENSOR0_SHIFT  3
 
-/* INT_STATUS_ADDR bitmasks */
-#define MIN_STATUS_MASKBIT(0)
-#define LOWER_STATUS_CLR   BIT(1)
-#define UPPER_STATUS_CLR   BIT(2)
-#define MAX_STATUS_MASKBIT(3)
-
 #define THRESHOLD_ADDR 0x3624
-/* THRESHOLD_ADDR bitmasks */
-#define THRESHOLD_MAX_LIMIT_SHIFT  24
-#define THRESHOLD_MIN_LIMIT_SHIFT  16
-#define THRESHOLD_UPPER_LIMIT_SHIFT8
-#define THRESHOLD_LOWER_LIMIT_SHIFT0
-
-/* Initial temperature threshold values */
-#define LOWER_LIMIT_TH 0x50
-#define UPPER_LIMIT_TH 0xdf
-#define MIN_LIMIT_TH   0x0
-#define MAX_LIMIT_TH   0xff
 
 #define INT_STATUS_ADDR0x363c
-#define TRDY_MASK  BIT(7)
-#define TIMEOUT_US 100
 
 #define S0_STATUS_OFF  0x3628
 #define S1_STATUS_OFF  0x362c
-- 
2.30.2



[PATCH v13 6/9] drivers: thermal: tsens: Replace custom 8960 apis with generic apis

2021-03-24 Thread Ansuel Smith
Rework calibrate function to use common function. Derive the offset from
a missing hardcoded slope table and the data from the nvmem calib
efuses.
Drop custom get_temp function and use generic api.

Signed-off-by: Ansuel Smith 
Acked-by: Thara Gopinath 
---
 drivers/thermal/qcom/tsens-8960.c | 56 +--
 1 file changed, 15 insertions(+), 41 deletions(-)

diff --git a/drivers/thermal/qcom/tsens-8960.c 
b/drivers/thermal/qcom/tsens-8960.c
index 95fcccafae14..9cc8a7dd23ae 100644
--- a/drivers/thermal/qcom/tsens-8960.c
+++ b/drivers/thermal/qcom/tsens-8960.c
@@ -67,6 +67,13 @@
 #define S9_STATUS_OFF  0x3674
 #define S10_STATUS_OFF 0x3678
 
+/* Original slope - 200 to compensate mC to C inaccuracy */
+static u32 tsens_msm8960_slope[] = {
+   976, 976, 954, 976,
+   911, 932, 932, 999,
+   932, 999, 932
+   };
+
 static int suspend_8960(struct tsens_priv *priv)
 {
int ret;
@@ -194,9 +201,7 @@ static int calibrate_8960(struct tsens_priv *priv)
 {
int i;
char *data;
-
-   ssize_t num_read = priv->num_sensors;
-   struct tsens_sensor *s = priv->sensor;
+   u32 p1[11];
 
data = qfprom_read(priv->dev, "calib");
if (IS_ERR(data))
@@ -204,49 +209,18 @@ static int calibrate_8960(struct tsens_priv *priv)
if (IS_ERR(data))
return PTR_ERR(data);
 
-   for (i = 0; i < num_read; i++, s++)
-   s->offset = data[i];
+   for (i = 0; i < priv->num_sensors; i++) {
+   p1[i] = data[i];
+   priv->sensor[i].slope = tsens_msm8960_slope[i];
+   }
+
+   compute_intercept_slope(priv, p1, NULL, ONE_PT_CALIB);
 
kfree(data);
 
return 0;
 }
 
-/* Temperature on y axis and ADC-code on x-axis */
-static inline int code_to_mdegC(u32 adc_code, const struct tsens_sensor *s)
-{
-   int slope, offset;
-
-   slope = thermal_zone_get_slope(s->tzd);
-   offset = CAL_MDEGC - slope * s->offset;
-
-   return adc_code * slope + offset;
-}
-
-static int get_temp_8960(const struct tsens_sensor *s, int *temp)
-{
-   int ret;
-   u32 code, trdy;
-   struct tsens_priv *priv = s->priv;
-   unsigned long timeout;
-
-   timeout = jiffies + usecs_to_jiffies(TIMEOUT_US);
-   do {
-   ret = regmap_read(priv->tm_map, INT_STATUS_ADDR, );
-   if (ret)
-   return ret;
-   if (!(trdy & TRDY_MASK))
-   continue;
-   ret = regmap_read(priv->tm_map, s->status, );
-   if (ret)
-   return ret;
-   *temp = code_to_mdegC(code, s);
-   return 0;
-   } while (time_before(jiffies, timeout));
-
-   return -ETIMEDOUT;
-}
-
 static struct tsens_features tsens_8960_feat = {
.ver_major  = VER_0,
.crit_int   = 0,
@@ -315,7 +289,7 @@ static const struct reg_field 
tsens_8960_regfields[MAX_REGFIELDS] = {
 static const struct tsens_ops ops_8960 = {
.init   = init_common,
.calibrate  = calibrate_8960,
-   .get_temp   = get_temp_8960,
+   .get_temp   = get_temp_common,
.enable = enable_8960,
.disable= disable_8960,
.suspend= suspend_8960,
-- 
2.30.2



[PATCH v13 2/9] drivers: thermal: tsens: Don't hardcode sensor slope

2021-03-24 Thread Ansuel Smith
Function compute_intercept_slope hardcode the sensor slope to
SLOPE_DEFAULT. Change this and use the default value only if a slope is
not defined. This is needed for tsens VER_0 that has a hardcoded slope
table.

Signed-off-by: Ansuel Smith 
Reviewed-by: Thara Gopinath 
---
 drivers/thermal/qcom/tsens.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
index 6b582a81358f..6da567de1db7 100644
--- a/drivers/thermal/qcom/tsens.c
+++ b/drivers/thermal/qcom/tsens.c
@@ -86,7 +86,8 @@ void compute_intercept_slope(struct tsens_priv *priv, u32 *p1,
"%s: sensor%d - data_point1:%#x data_point2:%#x\n",
__func__, i, p1[i], p2[i]);
 
-   priv->sensor[i].slope = SLOPE_DEFAULT;
+   if (!priv->sensor[i].slope)
+   priv->sensor[i].slope = SLOPE_DEFAULT;
if (mode == TWO_PT_CALIB) {
/*
 * slope (m) = adc_code2 - adc_code1 (y2 - y1)/
-- 
2.30.2



[PATCH v13 4/9] drivers: thermal: tsens: Use init_common for msm8960

2021-03-24 Thread Ansuel Smith
Use init_common and drop custom init for msm8960.

Signed-off-by: Ansuel Smith 
Reviewed-by: Thara Gopinath 
---
 drivers/thermal/qcom/tsens-8960.c | 52 +--
 1 file changed, 1 insertion(+), 51 deletions(-)

diff --git a/drivers/thermal/qcom/tsens-8960.c 
b/drivers/thermal/qcom/tsens-8960.c
index 3f4fc1ffe679..86585f439985 100644
--- a/drivers/thermal/qcom/tsens-8960.c
+++ b/drivers/thermal/qcom/tsens-8960.c
@@ -173,56 +173,6 @@ static void disable_8960(struct tsens_priv *priv)
regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
 }
 
-static int init_8960(struct tsens_priv *priv)
-{
-   int ret, i;
-   u32 reg_cntl;
-
-   priv->tm_map = dev_get_regmap(priv->dev, NULL);
-   if (!priv->tm_map)
-   return -ENODEV;
-
-   /*
-* The status registers for each sensor are discontiguous
-* because some SoCs have 5 sensors while others have more
-* but the control registers stay in the same place, i.e
-* directly after the first 5 status registers.
-*/
-   for (i = 0; i < priv->num_sensors; i++) {
-   if (i >= 5)
-   priv->sensor[i].status = S0_STATUS_ADDR + 40;
-   priv->sensor[i].status += i * 4;
-   }
-
-   reg_cntl = SW_RST;
-   ret = regmap_update_bits(priv->tm_map, CNTL_ADDR, SW_RST, reg_cntl);
-   if (ret)
-   return ret;
-
-   if (priv->num_sensors > 1) {
-   reg_cntl |= SLP_CLK_ENA | (MEASURE_PERIOD << 18);
-   reg_cntl &= ~SW_RST;
-   ret = regmap_update_bits(priv->tm_map, CONFIG_ADDR,
-CONFIG_MASK, CONFIG);
-   } else {
-   reg_cntl |= SLP_CLK_ENA_8660 | (MEASURE_PERIOD << 16);
-   reg_cntl &= ~CONFIG_MASK_8660;
-   reg_cntl |= CONFIG_8660 << CONFIG_SHIFT_8660;
-   }
-
-   reg_cntl |= GENMASK(priv->num_sensors - 1, 0) << SENSOR0_SHIFT;
-   ret = regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
-   if (ret)
-   return ret;
-
-   reg_cntl |= EN;
-   ret = regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
-   if (ret)
-   return ret;
-
-   return 0;
-}
-
 static int calibrate_8960(struct tsens_priv *priv)
 {
int i;
@@ -346,7 +296,7 @@ static const struct reg_field 
tsens_8960_regfields[MAX_REGFIELDS] = {
 };
 
 static const struct tsens_ops ops_8960 = {
-   .init   = init_8960,
+   .init   = init_common,
.calibrate  = calibrate_8960,
.get_temp   = get_temp_8960,
.enable = enable_8960,
-- 
2.30.2



[PATCH v13 1/9] drivers: thermal: tsens: Add VER_0 tsens version

2021-03-24 Thread Ansuel Smith
VER_0 is used to describe device based on tsens version before v0.1.
These device are devices based on msm8960 for example apq8064 or
ipq806x.

Signed-off-by: Ansuel Smith 
Reviewed-by: Thara Gopinath 
---
 drivers/thermal/qcom/tsens.c | 145 ---
 drivers/thermal/qcom/tsens.h |   4 +-
 2 files changed, 120 insertions(+), 29 deletions(-)

diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
index d8ce3a687b80..6b582a81358f 100644
--- a/drivers/thermal/qcom/tsens.c
+++ b/drivers/thermal/qcom/tsens.c
@@ -12,6 +12,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -515,6 +516,15 @@ static irqreturn_t tsens_irq_thread(int irq, void *data)
dev_dbg(priv->dev, "[%u] %s: no violation:  %d\n",
hw_id, __func__, temp);
}
+
+   if (tsens_version(priv) < VER_0_1) {
+   /* Constraint: There is only 1 interrupt control 
register for all
+* 11 temperature sensor. So monitoring more than 1 
sensor based
+* on interrupts will yield inconsistent result. To 
overcome this
+* issue we will monitor only sensor 0 which is the 
master sensor.
+*/
+   break;
+   }
}
 
return IRQ_HANDLED;
@@ -530,6 +540,13 @@ static int tsens_set_trips(void *_sensor, int low, int 
high)
int high_val, low_val, cl_high, cl_low;
u32 hw_id = s->hw_id;
 
+   if (tsens_version(priv) < VER_0_1) {
+   /* Pre v0.1 IP had a single register for each type of interrupt
+* and thresholds
+*/
+   hw_id = 0;
+   }
+
dev_dbg(dev, "[%u] %s: proposed thresholds: (%d:%d)\n",
hw_id, __func__, low, high);
 
@@ -584,18 +601,21 @@ int get_temp_tsens_valid(const struct tsens_sensor *s, 
int *temp)
u32 valid;
int ret;
 
-   ret = regmap_field_read(priv->rf[valid_idx], );
-   if (ret)
-   return ret;
-   while (!valid) {
-   /* Valid bit is 0 for 6 AHB clock cycles.
-* At 19.2MHz, 1 AHB clock is ~60ns.
-* We should enter this loop very, very rarely.
-*/
-   ndelay(400);
+   /* VER_0 doesn't have VALID bit */
+   if (tsens_version(priv) >= VER_0_1) {
ret = regmap_field_read(priv->rf[valid_idx], );
if (ret)
return ret;
+   while (!valid) {
+   /* Valid bit is 0 for 6 AHB clock cycles.
+* At 19.2MHz, 1 AHB clock is ~60ns.
+* We should enter this loop very, very rarely.
+*/
+   ndelay(400);
+   ret = regmap_field_read(priv->rf[valid_idx], );
+   if (ret)
+   return ret;
+   }
}
 
/* Valid bit is set, OK to read the temperature */
@@ -608,15 +628,29 @@ int get_temp_common(const struct tsens_sensor *s, int 
*temp)
 {
struct tsens_priv *priv = s->priv;
int hw_id = s->hw_id;
-   int last_temp = 0, ret;
+   int last_temp = 0, ret, trdy;
+   unsigned long timeout;
 
-   ret = regmap_field_read(priv->rf[LAST_TEMP_0 + hw_id], _temp);
-   if (ret)
-   return ret;
+   timeout = jiffies + usecs_to_jiffies(TIMEOUT_US);
+   do {
+   if (tsens_version(priv) == VER_0) {
+   ret = regmap_field_read(priv->rf[TRDY], );
+   if (ret)
+   return ret;
+   if (!trdy)
+   continue;
+   }
 
-   *temp = code_to_degc(last_temp, s) * 1000;
+   ret = regmap_field_read(priv->rf[LAST_TEMP_0 + hw_id], 
_temp);
+   if (ret)
+   return ret;
 
-   return 0;
+   *temp = code_to_degc(last_temp, s) * 1000;
+
+   return 0;
+   } while (time_before(jiffies, timeout));
+
+   return -ETIMEDOUT;
 }
 
 #ifdef CONFIG_DEBUG_FS
@@ -738,19 +772,31 @@ int __init init_common(struct tsens_priv *priv)
priv->tm_offset = 0x1000;
}
 
-   res = platform_get_resource(op, IORESOURCE_MEM, 0);
-   tm_base = devm_ioremap_resource(dev, res);
-   if (IS_ERR(tm_base)) {
-   ret = PTR_ERR(tm_base);
-   goto err_put_device;
+   if (tsens_version(priv) >= VER_0_1) {
+   res = platform_get_resource(op, IORESOURCE_MEM, 0);
+   tm_base = devm_ioremap_resource(dev, res);
+   if (IS_ERR(tm_base)) {
+   ret = PTR_ERR(tm_base);
+   goto

[PATCH v13 3/9] drivers: thermal: tsens: Convert msm8960 to reg_field

2021-03-24 Thread Ansuel Smith
Convert msm9860 driver to reg_field to use the init_common
function.

Signed-off-by: Ansuel Smith 
Acked-by: Thara Gopinath 
---
 drivers/thermal/qcom/tsens-8960.c | 80 ++-
 1 file changed, 79 insertions(+), 1 deletion(-)

diff --git a/drivers/thermal/qcom/tsens-8960.c 
b/drivers/thermal/qcom/tsens-8960.c
index 2a28a5af209e..3f4fc1ffe679 100644
--- a/drivers/thermal/qcom/tsens-8960.c
+++ b/drivers/thermal/qcom/tsens-8960.c
@@ -51,11 +51,22 @@
 #define MIN_LIMIT_TH   0x0
 #define MAX_LIMIT_TH   0xff
 
-#define S0_STATUS_ADDR 0x3628
 #define INT_STATUS_ADDR0x363c
 #define TRDY_MASK  BIT(7)
 #define TIMEOUT_US 100
 
+#define S0_STATUS_OFF  0x3628
+#define S1_STATUS_OFF  0x362c
+#define S2_STATUS_OFF  0x3630
+#define S3_STATUS_OFF  0x3634
+#define S4_STATUS_OFF  0x3638
+#define S5_STATUS_OFF  0x3664  /* Sensors 5-10 found on 
apq8064/msm8960 */
+#define S6_STATUS_OFF  0x3668
+#define S7_STATUS_OFF  0x366c
+#define S8_STATUS_OFF  0x3670
+#define S9_STATUS_OFF  0x3674
+#define S10_STATUS_OFF 0x3678
+
 static int suspend_8960(struct tsens_priv *priv)
 {
int ret;
@@ -269,6 +280,71 @@ static int get_temp_8960(const struct tsens_sensor *s, int 
*temp)
return -ETIMEDOUT;
 }
 
+static struct tsens_features tsens_8960_feat = {
+   .ver_major  = VER_0,
+   .crit_int   = 0,
+   .adc= 1,
+   .srot_split = 0,
+   .max_sensors= 11,
+};
+
+static const struct reg_field tsens_8960_regfields[MAX_REGFIELDS] = {
+   /* - SROT -- */
+   /* No VERSION information */
+
+   /* CNTL */
+   [TSENS_EN] = REG_FIELD(CNTL_ADDR,  0, 0),
+   [TSENS_SW_RST] = REG_FIELD(CNTL_ADDR,  1, 1),
+   /* 8960 has 5 sensors, 8660 has 11, we only handle 5 */
+   [SENSOR_EN]= REG_FIELD(CNTL_ADDR,  3, 7),
+
+   /* - TM -- */
+   /* INTERRUPT ENABLE */
+   /* NO INTERRUPT ENABLE */
+
+   /* Single UPPER/LOWER TEMPERATURE THRESHOLD for all sensors */
+   [LOW_THRESH_0]   = REG_FIELD(THRESHOLD_ADDR,  0,  7),
+   [UP_THRESH_0]= REG_FIELD(THRESHOLD_ADDR,  8, 15),
+   /* MIN_THRESH_0 and MAX_THRESH_0 are not present in the regfield
+* Recycle CRIT_THRESH_0 and 1 to set the required regs to hardcoded 
temp
+* MIN_THRESH_0 -> CRIT_THRESH_1
+* MAX_THRESH_0 -> CRIT_THRESH_0
+*/
+   [CRIT_THRESH_1]   = REG_FIELD(THRESHOLD_ADDR, 16, 23),
+   [CRIT_THRESH_0]   = REG_FIELD(THRESHOLD_ADDR, 24, 31),
+
+   /* UPPER/LOWER INTERRUPT [CLEAR/STATUS] */
+   /* 1 == clear, 0 == normal operation */
+   [LOW_INT_CLEAR_0]   = REG_FIELD(CNTL_ADDR,  9,  9),
+   [UP_INT_CLEAR_0]= REG_FIELD(CNTL_ADDR, 10, 10),
+
+   /* NO CRITICAL INTERRUPT SUPPORT on 8960 */
+
+   /* Sn_STATUS */
+   [LAST_TEMP_0]  = REG_FIELD(S0_STATUS_OFF,  0,  7),
+   [LAST_TEMP_1]  = REG_FIELD(S1_STATUS_OFF,  0,  7),
+   [LAST_TEMP_2]  = REG_FIELD(S2_STATUS_OFF,  0,  7),
+   [LAST_TEMP_3]  = REG_FIELD(S3_STATUS_OFF,  0,  7),
+   [LAST_TEMP_4]  = REG_FIELD(S4_STATUS_OFF,  0,  7),
+   [LAST_TEMP_5]  = REG_FIELD(S5_STATUS_OFF,  0,  7),
+   [LAST_TEMP_6]  = REG_FIELD(S6_STATUS_OFF,  0,  7),
+   [LAST_TEMP_7]  = REG_FIELD(S7_STATUS_OFF,  0,  7),
+   [LAST_TEMP_8]  = REG_FIELD(S8_STATUS_OFF,  0,  7),
+   [LAST_TEMP_9]  = REG_FIELD(S9_STATUS_OFF,  0,  7),
+   [LAST_TEMP_10] = REG_FIELD(S10_STATUS_OFF, 0,  7),
+
+   /* No VALID field on 8960 */
+   /* TSENS_INT_STATUS bits: 1 == threshold violated */
+   [MIN_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 0, 0),
+   [LOWER_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 1, 1),
+   [UPPER_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 2, 2),
+   /* No CRITICAL field on 8960 */
+   [MAX_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 3, 3),
+
+   /* TRDY: 1=ready, 0=in progress */
+   [TRDY] = REG_FIELD(INT_STATUS_ADDR, 7, 7),
+};
+
 static const struct tsens_ops ops_8960 = {
.init   = init_8960,
.calibrate  = calibrate_8960,
@@ -282,4 +358,6 @@ static const struct tsens_ops ops_8960 = {
 struct tsens_plat_data data_8960 = {
.num_sensors= 11,
.ops= _8960,
+   .feat   = _8960_feat,
+   .fields = tsens_8960_regfields,
 };
-- 
2.30.2



[PATCH v13 5/9] drivers: thermal: tsens: Fix bug in sensor enable for msm8960

2021-03-24 Thread Ansuel Smith
Device based on tsens VER_0 contains a hardware bug that results in some
problem with sensor enablement. Sensor id 6-11 can't be enabled
selectively and all of them must be enabled in one step.

Signed-off-by: Ansuel Smith 
Acked-by: Thara Gopinath 
---
 drivers/thermal/qcom/tsens-8960.c | 23 ---
 1 file changed, 20 insertions(+), 3 deletions(-)

diff --git a/drivers/thermal/qcom/tsens-8960.c 
b/drivers/thermal/qcom/tsens-8960.c
index 86585f439985..95fcccafae14 100644
--- a/drivers/thermal/qcom/tsens-8960.c
+++ b/drivers/thermal/qcom/tsens-8960.c
@@ -27,9 +27,9 @@
 #define EN BIT(0)
 #define SW_RST BIT(1)
 #define SENSOR0_EN BIT(3)
+#define MEASURE_PERIOD BIT(18)
 #define SLP_CLK_ENABIT(26)
 #define SLP_CLK_ENA_8660   BIT(24)
-#define MEASURE_PERIOD 1
 #define SENSOR0_SHIFT  3
 
 /* INT_STATUS_ADDR bitmasks */
@@ -126,17 +126,34 @@ static int resume_8960(struct tsens_priv *priv)
 static int enable_8960(struct tsens_priv *priv, int id)
 {
int ret;
-   u32 reg, mask;
+   u32 reg, mask = BIT(id);
 
ret = regmap_read(priv->tm_map, CNTL_ADDR, );
if (ret)
return ret;
 
-   mask = BIT(id + SENSOR0_SHIFT);
+   /* HARDWARE BUG:
+* On platforms with more than 6 sensors, all remaining sensors
+* must be enabled together, otherwise undefined results are expected.
+* (Sensor 6-7 disabled, Sensor 3 disabled...) In the original driver,
+* all the sensors are enabled in one step hence this bug is not
+* triggered.
+*/
+   if (id > 5)
+   mask = GENMASK(10, 6);
+
+   mask <<= SENSOR0_SHIFT;
+
+   /* Sensors already enabled. Skip. */
+   if ((reg & mask) == mask)
+   return 0;
+
ret = regmap_write(priv->tm_map, CNTL_ADDR, reg | SW_RST);
if (ret)
return ret;
 
+   reg |= MEASURE_PERIOD;
+
if (priv->num_sensors > 1)
reg |= mask | SLP_CLK_ENA | EN;
else
-- 
2.30.2



[PATCH v13 0/9] Add support for ipq8064 tsens

2021-03-24 Thread Ansuel Smith
This patchset convert msm8960 to reg_filed, use int_common instead 
of a custom function and fix wrong tsens get_temp function for msm8960.
Ipq8064 SoCs tsens driver is based on 8960 tsens driver. Ipq8064 needs
to be registered as a gcc child as the tsens regs on this platform are
shared with the controller.
This is based on work and code here
https://git.linaro.org/people/amit.kucheria/kernel.git/log/?h=wrk3/tsens-8960-breakage

v13:
* Simple reword
v12:
* Even more fix reported by Thara
v11:
* Address comments from Thara (thx)
v10:
* Fix wrong tsens init for ver_0 (crit_trips needs to be set in tsens_register)
v9:
* Fix warning from Documentation bot
v8:
* Drop MIN and MAX THRESH and use CRIT_THRESH instead
* Fix broken documentation patch
v7:
* Rework calibrate function to use get_temp_common
* Fix wrong required in the Documentation for ipq8064
* Fix hardware bug in sensor enable function
v6:
* Fix spelling error (can't find the problem with variable misallignment)
* Rework big if-else
* Remove extra comments
* Add description about different interrupts
v5:
* Conver driver to use reg_fiedl
* Use init_common 
* Drop custom set_trip and set_interrupt
* Use common set_trip and set_interrupt
* Fix bad get_temp function
* Add missing hardcoded slope
v4:
* Fix compilation error and warning reported by the bot
v3:
* Change driver to register as child instead of use phandle
v2:
* Fix dt-bindings problems

Ansuel Smith (9):
  drivers: thermal: tsens: Add VER_0 tsens version
  drivers: thermal: tsens: Don't hardcode sensor slope
  drivers: thermal: tsens: Convert msm8960 to reg_field
  drivers: thermal: tsens: Use init_common for msm8960
  drivers: thermal: tsens: Fix bug in sensor enable for msm8960
  drivers: thermal: tsens: Replace custom 8960 apis with generic apis
  drivers: thermal: tsens: Drop unused define for msm8960
  drivers: thermal: tsens: Add support for ipq8064-tsens
  dt-bindings: thermal: tsens: Document ipq8064 bindings

 .../bindings/thermal/qcom-tsens.yaml  |  56 -
 drivers/thermal/qcom/tsens-8960.c | 233 +-
 drivers/thermal/qcom/tsens.c  | 151 +---
 drivers/thermal/qcom/tsens.h  |   4 +-
 4 files changed, 288 insertions(+), 156 deletions(-)

-- 
2.30.2



Re: [PATCH] clang-format: Update ColumnLimit

2021-03-19 Thread Ansuel Smith
On Fri, Mar 19, 2021 at 11:42:34AM -0700, Nathan Chancellor wrote:
> On Fri, Mar 19, 2021 at 07:37:14PM +0100, Ansuel Smith wrote:
> > Update ColumnLimit value, changed from 80 to 100.
> > 
> > Signed-off-by: Ansuel Smith 
> > ---
> >  .clang-format | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> > 
> > diff --git a/.clang-format b/.clang-format
> > index c24b147cac01..3212542df113 100644
> > --- a/.clang-format
> > +++ b/.clang-format
> > @@ -52,7 +52,7 @@ BreakConstructorInitializersBeforeComma: false
> >  #BreakConstructorInitializers: BeforeComma # Unknown to clang-format-4.0
> >  BreakAfterJavaFieldAnnotations: false
> >  BreakStringLiterals: false
> > -ColumnLimit: 80
> > +ColumnLimit: 100
> >  CommentPragmas: '^ IWYU pragma:'
> >  #CompactNamespaces: false # Unknown to clang-format-4.0
> >  ConstructorInitializerAllOnOneLineOrOnePerLine: false
> > -- 
> > 2.30.2
> > 
> 
> Not sure how opinions have changed since but this has come up before:
> 
> https://lore.kernel.org/r/20200610125147.2782142-1-christian.brau...@ubuntu.com/
> 

Sorry, didn't notice that. Considering that checkpatch complains and
some reviewers actually state that 100 is the new limit, I think it's
time to update the file.

> Cheers,
> Nathan


[PATCH] clang-format: Update ColumnLimit

2021-03-19 Thread Ansuel Smith
Update ColumnLimit value, changed from 80 to 100.

Signed-off-by: Ansuel Smith 
---
 .clang-format | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.clang-format b/.clang-format
index c24b147cac01..3212542df113 100644
--- a/.clang-format
+++ b/.clang-format
@@ -52,7 +52,7 @@ BreakConstructorInitializersBeforeComma: false
 #BreakConstructorInitializers: BeforeComma # Unknown to clang-format-4.0
 BreakAfterJavaFieldAnnotations: false
 BreakStringLiterals: false
-ColumnLimit: 80
+ColumnLimit: 100
 CommentPragmas: '^ IWYU pragma:'
 #CompactNamespaces: false # Unknown to clang-format-4.0
 ConstructorInitializerAllOnOneLineOrOnePerLine: false
-- 
2.30.2



[PATCH v12 8/9] drivers: thermal: tsens: Add support for ipq8064-tsens

2021-03-19 Thread Ansuel Smith
Add support for tsens present in ipq806x SoCs based on generic msm8960
tsens driver.

Signed-off-by: Ansuel Smith 
Reviewed-by: Thara Gopinath 
---
 drivers/thermal/qcom/tsens.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
index 6da567de1db7..df04e96c2044 100644
--- a/drivers/thermal/qcom/tsens.c
+++ b/drivers/thermal/qcom/tsens.c
@@ -963,6 +963,9 @@ static SIMPLE_DEV_PM_OPS(tsens_pm_ops, tsens_suspend, 
tsens_resume);
 
 static const struct of_device_id tsens_table[] = {
{
+   .compatible = "qcom,ipq8064-tsens",
+   .data = _8960,
+   }, {
.compatible = "qcom,msm8916-tsens",
.data = _8916,
}, {
-- 
2.30.2



[PATCH v12 7/9] drivers: thermal: tsens: Drop unused define for msm8960

2021-03-19 Thread Ansuel Smith
Drop unused define for msm8960 replaced by generic api and reg_field.

Signed-off-by: Ansuel Smith 
Reviewed-by: Thara Gopinath 
---
 drivers/thermal/qcom/tsens-8960.c | 24 +---
 1 file changed, 1 insertion(+), 23 deletions(-)

diff --git a/drivers/thermal/qcom/tsens-8960.c 
b/drivers/thermal/qcom/tsens-8960.c
index b139075dd004..4037f3a432e1 100644
--- a/drivers/thermal/qcom/tsens-8960.c
+++ b/drivers/thermal/qcom/tsens-8960.c
@@ -10,8 +10,6 @@
 #include 
 #include "tsens.h"
 
-#define CAL_MDEGC  3
-
 #define CONFIG_ADDR0x3640
 #define CONFIG_ADDR_8660   0x3620
 /* CONFIG_ADDR bitmasks */
@@ -21,39 +19,19 @@
 #define CONFIG_SHIFT_8660  28
 #define CONFIG_MASK_8660   (3 << CONFIG_SHIFT_8660)
 
-#define STATUS_CNTL_ADDR_8064  0x3660
 #define CNTL_ADDR  0x3620
 /* CNTL_ADDR bitmasks */
 #define EN BIT(0)
 #define SW_RST BIT(1)
-#define SENSOR0_EN BIT(3)
+
 #define MEASURE_PERIOD BIT(18)
 #define SLP_CLK_ENABIT(26)
 #define SLP_CLK_ENA_8660   BIT(24)
 #define SENSOR0_SHIFT  3
 
-/* INT_STATUS_ADDR bitmasks */
-#define MIN_STATUS_MASKBIT(0)
-#define LOWER_STATUS_CLR   BIT(1)
-#define UPPER_STATUS_CLR   BIT(2)
-#define MAX_STATUS_MASKBIT(3)
-
 #define THRESHOLD_ADDR 0x3624
-/* THRESHOLD_ADDR bitmasks */
-#define THRESHOLD_MAX_LIMIT_SHIFT  24
-#define THRESHOLD_MIN_LIMIT_SHIFT  16
-#define THRESHOLD_UPPER_LIMIT_SHIFT8
-#define THRESHOLD_LOWER_LIMIT_SHIFT0
-
-/* Initial temperature threshold values */
-#define LOWER_LIMIT_TH 0x50
-#define UPPER_LIMIT_TH 0xdf
-#define MIN_LIMIT_TH   0x0
-#define MAX_LIMIT_TH   0xff
 
 #define INT_STATUS_ADDR0x363c
-#define TRDY_MASK  BIT(7)
-#define TIMEOUT_US 100
 
 #define S0_STATUS_OFF  0x3628
 #define S1_STATUS_OFF  0x362c
-- 
2.30.2



[PATCH v12 9/9] dt-bindings: thermal: tsens: Document ipq8064 bindings

2021-03-19 Thread Ansuel Smith
Document the use of bindings used for msm8960 tsens based devices.
msm8960 use the same gcc regs and is set as a child of the qcom gcc.

Signed-off-by: Ansuel Smith 
Reviewed-by: Rob Herring 
---
 .../bindings/thermal/qcom-tsens.yaml  | 56 ---
 1 file changed, 48 insertions(+), 8 deletions(-)

diff --git a/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml 
b/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml
index 95462e071ab4..1785b1c75a3c 100644
--- a/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml
+++ b/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml
@@ -19,6 +19,11 @@ description: |
 properties:
   compatible:
 oneOf:
+  - description: msm9860 TSENS based
+items:
+  - enum:
+  - qcom,ipq8064-tsens
+
   - description: v0.1 of TSENS
 items:
   - enum:
@@ -73,7 +78,9 @@ properties:
 maxItems: 2
 items:
   - const: calib
-  - const: calib_sel
+  - enum:
+  - calib_backup
+  - calib_sel
 
   "#qcom,sensors":
 description:
@@ -88,12 +95,20 @@ properties:
   Number of cells required to uniquely identify the thermal sensors. Since
   we have multiple sensors this is set to 1
 
+required:
+  - compatible
+  - interrupts
+  - interrupt-names
+  - "#thermal-sensor-cells"
+  - "#qcom,sensors"
+
 allOf:
   - if:
   properties:
 compatible:
   contains:
 enum:
+  - qcom,ipq8064-tsens
   - qcom,msm8916-tsens
   - qcom,msm8974-tsens
   - qcom,msm8976-tsens
@@ -114,17 +129,42 @@ allOf:
 interrupt-names:
   minItems: 2
 
-required:
-  - compatible
-  - reg
-  - "#qcom,sensors"
-  - interrupts
-  - interrupt-names
-  - "#thermal-sensor-cells"
+  - if:
+  properties:
+compatible:
+  contains:
+enum:
+  - qcom,tsens-v0_1
+  - qcom,tsens-v1
+  - qcom,tsens-v2
+
+then:
+  required:
+- reg
 
 additionalProperties: false
 
 examples:
+  - |
+#include 
+// Example msm9860 based SoC (ipq8064):
+gcc: clock-controller {
+
+   /* ... */
+
+   tsens: thermal-sensor {
+compatible = "qcom,ipq8064-tsens";
+
+ nvmem-cells = <_calib>, <_calib_backup>;
+ nvmem-cell-names = "calib", "calib_backup";
+ interrupts = ;
+ interrupt-names = "uplow";
+
+ #qcom,sensors = <11>;
+ #thermal-sensor-cells = <1>;
+  };
+};
+
   - |
 #include 
 // Example 1 (legacy: for pre v1 IP):
-- 
2.30.2



[PATCH v12 6/9] drivers: thermal: tsens: Replace custom 8960 apis with generic apis

2021-03-19 Thread Ansuel Smith
Rework calibrate function to use common function. Derive the offset from
a missing hardcoded slope table and the data from the nvmem calib
efuses.
Drop custom get_temp function and use generic api.

Signed-off-by: Ansuel Smith 
Acked-by: Thara Gopinath 
---
 drivers/thermal/qcom/tsens-8960.c | 56 +--
 1 file changed, 15 insertions(+), 41 deletions(-)

diff --git a/drivers/thermal/qcom/tsens-8960.c 
b/drivers/thermal/qcom/tsens-8960.c
index bf8dfaf06428..b139075dd004 100644
--- a/drivers/thermal/qcom/tsens-8960.c
+++ b/drivers/thermal/qcom/tsens-8960.c
@@ -67,6 +67,13 @@
 #define S9_STATUS_OFF  0x3674
 #define S10_STATUS_OFF 0x3678
 
+/* Original slope - 200 to compensate mC to C inaccuracy */
+static u32 tsens_msm8960_slope[] = {
+   976, 976, 954, 976,
+   911, 932, 932, 999,
+   932, 999, 932
+   };
+
 static int suspend_8960(struct tsens_priv *priv)
 {
int ret;
@@ -194,9 +201,7 @@ static int calibrate_8960(struct tsens_priv *priv)
 {
int i;
char *data;
-
-   ssize_t num_read = priv->num_sensors;
-   struct tsens_sensor *s = priv->sensor;
+   u32 p1[11];
 
data = qfprom_read(priv->dev, "calib");
if (IS_ERR(data))
@@ -204,49 +209,18 @@ static int calibrate_8960(struct tsens_priv *priv)
if (IS_ERR(data))
return PTR_ERR(data);
 
-   for (i = 0; i < num_read; i++, s++)
-   s->offset = data[i];
+   for (i = 0; i < priv->num_sensors; i++) {
+   p1[i] = data[i];
+   priv->sensor[i].slope = tsens_msm8960_slope[i];
+   }
+
+   compute_intercept_slope(priv, p1, NULL, ONE_PT_CALIB);
 
kfree(data);
 
return 0;
 }
 
-/* Temperature on y axis and ADC-code on x-axis */
-static inline int code_to_mdegC(u32 adc_code, const struct tsens_sensor *s)
-{
-   int slope, offset;
-
-   slope = thermal_zone_get_slope(s->tzd);
-   offset = CAL_MDEGC - slope * s->offset;
-
-   return adc_code * slope + offset;
-}
-
-static int get_temp_8960(const struct tsens_sensor *s, int *temp)
-{
-   int ret;
-   u32 code, trdy;
-   struct tsens_priv *priv = s->priv;
-   unsigned long timeout;
-
-   timeout = jiffies + usecs_to_jiffies(TIMEOUT_US);
-   do {
-   ret = regmap_read(priv->tm_map, INT_STATUS_ADDR, );
-   if (ret)
-   return ret;
-   if (!(trdy & TRDY_MASK))
-   continue;
-   ret = regmap_read(priv->tm_map, s->status, );
-   if (ret)
-   return ret;
-   *temp = code_to_mdegC(code, s);
-   return 0;
-   } while (time_before(jiffies, timeout));
-
-   return -ETIMEDOUT;
-}
-
 static struct tsens_features tsens_8960_feat = {
.ver_major  = VER_0,
.crit_int   = 0,
@@ -315,7 +289,7 @@ static const struct reg_field 
tsens_8960_regfields[MAX_REGFIELDS] = {
 static const struct tsens_ops ops_8960 = {
.init   = init_common,
.calibrate  = calibrate_8960,
-   .get_temp   = get_temp_8960,
+   .get_temp   = get_temp_common,
.enable = enable_8960,
.disable= disable_8960,
.suspend= suspend_8960,
-- 
2.30.2



[PATCH v12 5/9] drivers: thermal: tsens: Fix bug in sensor enable for msm8960

2021-03-19 Thread Ansuel Smith
Device based on tsens VER_0 contains a hardware bug that results in some
problem with sensor enablement. Sensor id 6-11 can't be enabled
selectively and all of them must be enabled in one step.

Signed-off-by: Ansuel Smith 
---
 drivers/thermal/qcom/tsens-8960.c | 23 ---
 1 file changed, 20 insertions(+), 3 deletions(-)

diff --git a/drivers/thermal/qcom/tsens-8960.c 
b/drivers/thermal/qcom/tsens-8960.c
index 86585f439985..bf8dfaf06428 100644
--- a/drivers/thermal/qcom/tsens-8960.c
+++ b/drivers/thermal/qcom/tsens-8960.c
@@ -27,9 +27,9 @@
 #define EN BIT(0)
 #define SW_RST BIT(1)
 #define SENSOR0_EN BIT(3)
+#define MEASURE_PERIOD BIT(18)
 #define SLP_CLK_ENABIT(26)
 #define SLP_CLK_ENA_8660   BIT(24)
-#define MEASURE_PERIOD 1
 #define SENSOR0_SHIFT  3
 
 /* INT_STATUS_ADDR bitmasks */
@@ -126,17 +126,34 @@ static int resume_8960(struct tsens_priv *priv)
 static int enable_8960(struct tsens_priv *priv, int id)
 {
int ret;
-   u32 reg, mask;
+   u32 reg, mask = BIT(id);
 
ret = regmap_read(priv->tm_map, CNTL_ADDR, );
if (ret)
return ret;
 
-   mask = BIT(id + SENSOR0_SHIFT);
+   /* HARDWARE BUG:
+* On platform with more than 6 sensors, all the remaining
+* sensors needs to be enabled all togheder or underfined
+* results are expected. (Sensor 6-7 disabled, Sensor 3
+* disabled...) In the original driver, all the sensors
+* are enabled in one step hence this bug is not triggered.
+*/
+   if (id > 5)
+   mask = GENMASK(10, 6);
+
+   mask <<= SENSOR0_SHIFT;
+
+   /* Sensors already enabled. Skip. */
+   if ((reg & mask) == mask)
+   return 0;
+
ret = regmap_write(priv->tm_map, CNTL_ADDR, reg | SW_RST);
if (ret)
return ret;
 
+   reg |= MEASURE_PERIOD;
+
if (priv->num_sensors > 1)
reg |= mask | SLP_CLK_ENA | EN;
else
-- 
2.30.2



[PATCH v12 4/9] drivers: thermal: tsens: Use init_common for msm8960

2021-03-19 Thread Ansuel Smith
Use init_common and drop custom init for msm8960.

Signed-off-by: Ansuel Smith 
Reviewed-by: Thara Gopinath 
---
 drivers/thermal/qcom/tsens-8960.c | 52 +--
 1 file changed, 1 insertion(+), 51 deletions(-)

diff --git a/drivers/thermal/qcom/tsens-8960.c 
b/drivers/thermal/qcom/tsens-8960.c
index 3f4fc1ffe679..86585f439985 100644
--- a/drivers/thermal/qcom/tsens-8960.c
+++ b/drivers/thermal/qcom/tsens-8960.c
@@ -173,56 +173,6 @@ static void disable_8960(struct tsens_priv *priv)
regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
 }
 
-static int init_8960(struct tsens_priv *priv)
-{
-   int ret, i;
-   u32 reg_cntl;
-
-   priv->tm_map = dev_get_regmap(priv->dev, NULL);
-   if (!priv->tm_map)
-   return -ENODEV;
-
-   /*
-* The status registers for each sensor are discontiguous
-* because some SoCs have 5 sensors while others have more
-* but the control registers stay in the same place, i.e
-* directly after the first 5 status registers.
-*/
-   for (i = 0; i < priv->num_sensors; i++) {
-   if (i >= 5)
-   priv->sensor[i].status = S0_STATUS_ADDR + 40;
-   priv->sensor[i].status += i * 4;
-   }
-
-   reg_cntl = SW_RST;
-   ret = regmap_update_bits(priv->tm_map, CNTL_ADDR, SW_RST, reg_cntl);
-   if (ret)
-   return ret;
-
-   if (priv->num_sensors > 1) {
-   reg_cntl |= SLP_CLK_ENA | (MEASURE_PERIOD << 18);
-   reg_cntl &= ~SW_RST;
-   ret = regmap_update_bits(priv->tm_map, CONFIG_ADDR,
-CONFIG_MASK, CONFIG);
-   } else {
-   reg_cntl |= SLP_CLK_ENA_8660 | (MEASURE_PERIOD << 16);
-   reg_cntl &= ~CONFIG_MASK_8660;
-   reg_cntl |= CONFIG_8660 << CONFIG_SHIFT_8660;
-   }
-
-   reg_cntl |= GENMASK(priv->num_sensors - 1, 0) << SENSOR0_SHIFT;
-   ret = regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
-   if (ret)
-   return ret;
-
-   reg_cntl |= EN;
-   ret = regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
-   if (ret)
-   return ret;
-
-   return 0;
-}
-
 static int calibrate_8960(struct tsens_priv *priv)
 {
int i;
@@ -346,7 +296,7 @@ static const struct reg_field 
tsens_8960_regfields[MAX_REGFIELDS] = {
 };
 
 static const struct tsens_ops ops_8960 = {
-   .init   = init_8960,
+   .init   = init_common,
.calibrate  = calibrate_8960,
.get_temp   = get_temp_8960,
.enable = enable_8960,
-- 
2.30.2



[PATCH v12 3/9] drivers: thermal: tsens: Convert msm8960 to reg_field

2021-03-19 Thread Ansuel Smith
Convert msm9860 driver to reg_field to use the init_common
function.

Signed-off-by: Ansuel Smith 
Acked-by: Thara Gopinath 
---
 drivers/thermal/qcom/tsens-8960.c | 80 ++-
 1 file changed, 79 insertions(+), 1 deletion(-)

diff --git a/drivers/thermal/qcom/tsens-8960.c 
b/drivers/thermal/qcom/tsens-8960.c
index 2a28a5af209e..3f4fc1ffe679 100644
--- a/drivers/thermal/qcom/tsens-8960.c
+++ b/drivers/thermal/qcom/tsens-8960.c
@@ -51,11 +51,22 @@
 #define MIN_LIMIT_TH   0x0
 #define MAX_LIMIT_TH   0xff
 
-#define S0_STATUS_ADDR 0x3628
 #define INT_STATUS_ADDR0x363c
 #define TRDY_MASK  BIT(7)
 #define TIMEOUT_US 100
 
+#define S0_STATUS_OFF  0x3628
+#define S1_STATUS_OFF  0x362c
+#define S2_STATUS_OFF  0x3630
+#define S3_STATUS_OFF  0x3634
+#define S4_STATUS_OFF  0x3638
+#define S5_STATUS_OFF  0x3664  /* Sensors 5-10 found on 
apq8064/msm8960 */
+#define S6_STATUS_OFF  0x3668
+#define S7_STATUS_OFF  0x366c
+#define S8_STATUS_OFF  0x3670
+#define S9_STATUS_OFF  0x3674
+#define S10_STATUS_OFF 0x3678
+
 static int suspend_8960(struct tsens_priv *priv)
 {
int ret;
@@ -269,6 +280,71 @@ static int get_temp_8960(const struct tsens_sensor *s, int 
*temp)
return -ETIMEDOUT;
 }
 
+static struct tsens_features tsens_8960_feat = {
+   .ver_major  = VER_0,
+   .crit_int   = 0,
+   .adc= 1,
+   .srot_split = 0,
+   .max_sensors= 11,
+};
+
+static const struct reg_field tsens_8960_regfields[MAX_REGFIELDS] = {
+   /* - SROT -- */
+   /* No VERSION information */
+
+   /* CNTL */
+   [TSENS_EN] = REG_FIELD(CNTL_ADDR,  0, 0),
+   [TSENS_SW_RST] = REG_FIELD(CNTL_ADDR,  1, 1),
+   /* 8960 has 5 sensors, 8660 has 11, we only handle 5 */
+   [SENSOR_EN]= REG_FIELD(CNTL_ADDR,  3, 7),
+
+   /* - TM -- */
+   /* INTERRUPT ENABLE */
+   /* NO INTERRUPT ENABLE */
+
+   /* Single UPPER/LOWER TEMPERATURE THRESHOLD for all sensors */
+   [LOW_THRESH_0]   = REG_FIELD(THRESHOLD_ADDR,  0,  7),
+   [UP_THRESH_0]= REG_FIELD(THRESHOLD_ADDR,  8, 15),
+   /* MIN_THRESH_0 and MAX_THRESH_0 are not present in the regfield
+* Recycle CRIT_THRESH_0 and 1 to set the required regs to hardcoded 
temp
+* MIN_THRESH_0 -> CRIT_THRESH_1
+* MAX_THRESH_0 -> CRIT_THRESH_0
+*/
+   [CRIT_THRESH_1]   = REG_FIELD(THRESHOLD_ADDR, 16, 23),
+   [CRIT_THRESH_0]   = REG_FIELD(THRESHOLD_ADDR, 24, 31),
+
+   /* UPPER/LOWER INTERRUPT [CLEAR/STATUS] */
+   /* 1 == clear, 0 == normal operation */
+   [LOW_INT_CLEAR_0]   = REG_FIELD(CNTL_ADDR,  9,  9),
+   [UP_INT_CLEAR_0]= REG_FIELD(CNTL_ADDR, 10, 10),
+
+   /* NO CRITICAL INTERRUPT SUPPORT on 8960 */
+
+   /* Sn_STATUS */
+   [LAST_TEMP_0]  = REG_FIELD(S0_STATUS_OFF,  0,  7),
+   [LAST_TEMP_1]  = REG_FIELD(S1_STATUS_OFF,  0,  7),
+   [LAST_TEMP_2]  = REG_FIELD(S2_STATUS_OFF,  0,  7),
+   [LAST_TEMP_3]  = REG_FIELD(S3_STATUS_OFF,  0,  7),
+   [LAST_TEMP_4]  = REG_FIELD(S4_STATUS_OFF,  0,  7),
+   [LAST_TEMP_5]  = REG_FIELD(S5_STATUS_OFF,  0,  7),
+   [LAST_TEMP_6]  = REG_FIELD(S6_STATUS_OFF,  0,  7),
+   [LAST_TEMP_7]  = REG_FIELD(S7_STATUS_OFF,  0,  7),
+   [LAST_TEMP_8]  = REG_FIELD(S8_STATUS_OFF,  0,  7),
+   [LAST_TEMP_9]  = REG_FIELD(S9_STATUS_OFF,  0,  7),
+   [LAST_TEMP_10] = REG_FIELD(S10_STATUS_OFF, 0,  7),
+
+   /* No VALID field on 8960 */
+   /* TSENS_INT_STATUS bits: 1 == threshold violated */
+   [MIN_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 0, 0),
+   [LOWER_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 1, 1),
+   [UPPER_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 2, 2),
+   /* No CRITICAL field on 8960 */
+   [MAX_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 3, 3),
+
+   /* TRDY: 1=ready, 0=in progress */
+   [TRDY] = REG_FIELD(INT_STATUS_ADDR, 7, 7),
+};
+
 static const struct tsens_ops ops_8960 = {
.init   = init_8960,
.calibrate  = calibrate_8960,
@@ -282,4 +358,6 @@ static const struct tsens_ops ops_8960 = {
 struct tsens_plat_data data_8960 = {
.num_sensors= 11,
.ops= _8960,
+   .feat   = _8960_feat,
+   .fields = tsens_8960_regfields,
 };
-- 
2.30.2



[PATCH v12 1/9] drivers: thermal: tsens: Add VER_0 tsens version

2021-03-19 Thread Ansuel Smith
VER_0 is used to describe device based on tsens version before v0.1.
These device are devices based on msm8960 for example apq8064 or
ipq806x.

Signed-off-by: Ansuel Smith 
Reviewed-by: Thara Gopinath 
---
 drivers/thermal/qcom/tsens.c | 145 ---
 drivers/thermal/qcom/tsens.h |   4 +-
 2 files changed, 120 insertions(+), 29 deletions(-)

diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
index d8ce3a687b80..6b582a81358f 100644
--- a/drivers/thermal/qcom/tsens.c
+++ b/drivers/thermal/qcom/tsens.c
@@ -12,6 +12,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -515,6 +516,15 @@ static irqreturn_t tsens_irq_thread(int irq, void *data)
dev_dbg(priv->dev, "[%u] %s: no violation:  %d\n",
hw_id, __func__, temp);
}
+
+   if (tsens_version(priv) < VER_0_1) {
+   /* Constraint: There is only 1 interrupt control 
register for all
+* 11 temperature sensor. So monitoring more than 1 
sensor based
+* on interrupts will yield inconsistent result. To 
overcome this
+* issue we will monitor only sensor 0 which is the 
master sensor.
+*/
+   break;
+   }
}
 
return IRQ_HANDLED;
@@ -530,6 +540,13 @@ static int tsens_set_trips(void *_sensor, int low, int 
high)
int high_val, low_val, cl_high, cl_low;
u32 hw_id = s->hw_id;
 
+   if (tsens_version(priv) < VER_0_1) {
+   /* Pre v0.1 IP had a single register for each type of interrupt
+* and thresholds
+*/
+   hw_id = 0;
+   }
+
dev_dbg(dev, "[%u] %s: proposed thresholds: (%d:%d)\n",
hw_id, __func__, low, high);
 
@@ -584,18 +601,21 @@ int get_temp_tsens_valid(const struct tsens_sensor *s, 
int *temp)
u32 valid;
int ret;
 
-   ret = regmap_field_read(priv->rf[valid_idx], );
-   if (ret)
-   return ret;
-   while (!valid) {
-   /* Valid bit is 0 for 6 AHB clock cycles.
-* At 19.2MHz, 1 AHB clock is ~60ns.
-* We should enter this loop very, very rarely.
-*/
-   ndelay(400);
+   /* VER_0 doesn't have VALID bit */
+   if (tsens_version(priv) >= VER_0_1) {
ret = regmap_field_read(priv->rf[valid_idx], );
if (ret)
return ret;
+   while (!valid) {
+   /* Valid bit is 0 for 6 AHB clock cycles.
+* At 19.2MHz, 1 AHB clock is ~60ns.
+* We should enter this loop very, very rarely.
+*/
+   ndelay(400);
+   ret = regmap_field_read(priv->rf[valid_idx], );
+   if (ret)
+   return ret;
+   }
}
 
/* Valid bit is set, OK to read the temperature */
@@ -608,15 +628,29 @@ int get_temp_common(const struct tsens_sensor *s, int 
*temp)
 {
struct tsens_priv *priv = s->priv;
int hw_id = s->hw_id;
-   int last_temp = 0, ret;
+   int last_temp = 0, ret, trdy;
+   unsigned long timeout;
 
-   ret = regmap_field_read(priv->rf[LAST_TEMP_0 + hw_id], _temp);
-   if (ret)
-   return ret;
+   timeout = jiffies + usecs_to_jiffies(TIMEOUT_US);
+   do {
+   if (tsens_version(priv) == VER_0) {
+   ret = regmap_field_read(priv->rf[TRDY], );
+   if (ret)
+   return ret;
+   if (!trdy)
+   continue;
+   }
 
-   *temp = code_to_degc(last_temp, s) * 1000;
+   ret = regmap_field_read(priv->rf[LAST_TEMP_0 + hw_id], 
_temp);
+   if (ret)
+   return ret;
 
-   return 0;
+   *temp = code_to_degc(last_temp, s) * 1000;
+
+   return 0;
+   } while (time_before(jiffies, timeout));
+
+   return -ETIMEDOUT;
 }
 
 #ifdef CONFIG_DEBUG_FS
@@ -738,19 +772,31 @@ int __init init_common(struct tsens_priv *priv)
priv->tm_offset = 0x1000;
}
 
-   res = platform_get_resource(op, IORESOURCE_MEM, 0);
-   tm_base = devm_ioremap_resource(dev, res);
-   if (IS_ERR(tm_base)) {
-   ret = PTR_ERR(tm_base);
-   goto err_put_device;
+   if (tsens_version(priv) >= VER_0_1) {
+   res = platform_get_resource(op, IORESOURCE_MEM, 0);
+   tm_base = devm_ioremap_resource(dev, res);
+   if (IS_ERR(tm_base)) {
+   ret = PTR_ERR(tm_base);
+   goto

[PATCH v12 2/9] drivers: thermal: tsens: Don't hardcode sensor slope

2021-03-19 Thread Ansuel Smith
Function compute_intercept_slope hardcode the sensor slope to
SLOPE_DEFAULT. Change this and use the default value only if a slope is
not defined. This is needed for tsens VER_0 that has a hardcoded slope
table.

Signed-off-by: Ansuel Smith 
Reviewed-by: Thara Gopinath 
---
 drivers/thermal/qcom/tsens.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
index 6b582a81358f..6da567de1db7 100644
--- a/drivers/thermal/qcom/tsens.c
+++ b/drivers/thermal/qcom/tsens.c
@@ -86,7 +86,8 @@ void compute_intercept_slope(struct tsens_priv *priv, u32 *p1,
"%s: sensor%d - data_point1:%#x data_point2:%#x\n",
__func__, i, p1[i], p2[i]);
 
-   priv->sensor[i].slope = SLOPE_DEFAULT;
+   if (!priv->sensor[i].slope)
+   priv->sensor[i].slope = SLOPE_DEFAULT;
if (mode == TWO_PT_CALIB) {
/*
 * slope (m) = adc_code2 - adc_code1 (y2 - y1)/
-- 
2.30.2



[PATCH v12 0/9] Add support for ipq8064 tsens

2021-03-19 Thread Ansuel Smith
This patchset convert msm8960 to reg_filed, use int_common instead 
of a custom function and fix wrong tsens get_temp function for msm8960.
Ipq8064 SoCs tsens driver is based on 8960 tsens driver. Ipq8064 needs
to be registered as a gcc child as the tsens regs on this platform are
shared with the controller.
This is based on work and code here
https://git.linaro.org/people/amit.kucheria/kernel.git/log/?h=wrk3/tsens-8960-breakage

v12:
* Even more fix reported by Thara
v11:
* Address comments from Thara (thx)
v10:
* Fix wrong tsens init for ver_0 (crit_trips needs to be set in tsens_register)
v9:
* Fix warning from Documentation bot
v8:
* Drop MIN and MAX THRESH and use CRIT_THRESH instead
* Fix broken documentation patch
v7:
* Rework calibrate function to use get_temp_common
* Fix wrong required in the Documentation for ipq8064
* Fix hardware bug in sensor enable function
v6:
* Fix spelling error (can't find the problem with variable misallignment)
* Rework big if-else
* Remove extra comments
* Add description about different interrupts
v5:
* Conver driver to use reg_fiedl
* Use init_common 
* Drop custom set_trip and set_interrupt
* Use common set_trip and set_interrupt
* Fix bad get_temp function
* Add missing hardcoded slope
v4:
* Fix compilation error and warning reported by the bot
v3:
* Change driver to register as child instead of use phandle
v2:
* Fix dt-bindings problems

Ansuel Smith (9):
  drivers: thermal: tsens: Add VER_0 tsens version
  drivers: thermal: tsens: Don't hardcode sensor slope
  drivers: thermal: tsens: Convert msm8960 to reg_field
  drivers: thermal: tsens: Use init_common for msm8960
  drivers: thermal: tsens: Fix bug in sensor enable for msm8960
  drivers: thermal: tsens: Replace custom 8960 apis with generic apis
  drivers: thermal: tsens: Drop unused define for msm8960
  drivers: thermal: tsens: Add support for ipq8064-tsens
  dt-bindings: thermal: tsens: Document ipq8064 bindings

 .../bindings/thermal/qcom-tsens.yaml  |  56 -
 drivers/thermal/qcom/tsens-8960.c | 233 +-
 drivers/thermal/qcom/tsens.c  | 151 +---
 drivers/thermal/qcom/tsens.h  |   4 +-
 4 files changed, 288 insertions(+), 156 deletions(-)

-- 
2.30.2



Re: [PATCH v11 1/9] drivers: thermal: tsens: Add VER_0 tsens version

2021-03-19 Thread Ansuel Smith
On Fri, Mar 19, 2021 at 09:11:38AM -0400, Thara Gopinath wrote:
> 
> 
> On 3/18/21 8:52 PM, Ansuel Smith wrote:
> > VER_0 is used to describe device based on tsens version before v0.1.
> > These device are devices based on msm8960 for example apq8064 or
> > ipq806x.
> 
> Hi Ansuel,
> 
> There are still checkpatch check warnings in this patch. Please run
> checkpatch.pl --strict and fix them. Once that is done, you can add
> 
> Reviewed-by: Thara Gopinath 
> 
> Warm Regards
> Thara
>

Hi,
thanks a lot for the review. The only warning I have is a line ending
with ( that i think I can't fix or I will go over the max char for line.
Do you have something more?

> > 
> > Signed-off-by: Ansuel Smith 
> > ---
> >   drivers/thermal/qcom/tsens.c | 141 ---
> >   drivers/thermal/qcom/tsens.h |   4 +-
> >   2 files changed, 116 insertions(+), 29 deletions(-)
> > 
> > diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
> > index d8ce3a687b80..277d9b17e949 100644
> > --- a/drivers/thermal/qcom/tsens.c
> > +++ b/drivers/thermal/qcom/tsens.c
> > @@ -12,6 +12,7 @@
> >   #include 
> >   #include 
> >   #include 
> > +#include 
> >   #include 
> >   #include 
> >   #include 
> > @@ -515,6 +516,15 @@ static irqreturn_t tsens_irq_thread(int irq, void 
> > *data)
> > dev_dbg(priv->dev, "[%u] %s: no violation:  %d\n",
> > hw_id, __func__, temp);
> > }
> > +
> > +   if (tsens_version(priv) < VER_0_1) {
> > +   /* Constraint: There is only 1 interrupt control 
> > register for all
> > +* 11 temperature sensor. So monitoring more than 1 
> > sensor based
> > +* on interrupts will yield inconsistent result. To 
> > overcome this
> > +* issue we will monitor only sensor 0 which is the 
> > master sensor.
> > +*/
> > +   break;
> > +   }
> > }
> > return IRQ_HANDLED;
> > @@ -530,6 +540,13 @@ static int tsens_set_trips(void *_sensor, int low, int 
> > high)
> > int high_val, low_val, cl_high, cl_low;
> > u32 hw_id = s->hw_id;
> > +   if (tsens_version(priv) < VER_0_1) {
> > +   /* Pre v0.1 IP had a single register for each type of interrupt
> > +* and thresholds
> > +*/
> > +   hw_id = 0;
> > +   }
> > +
> > dev_dbg(dev, "[%u] %s: proposed thresholds: (%d:%d)\n",
> > hw_id, __func__, low, high);
> > @@ -584,18 +601,21 @@ int get_temp_tsens_valid(const struct tsens_sensor 
> > *s, int *temp)
> > u32 valid;
> > int ret;
> > -   ret = regmap_field_read(priv->rf[valid_idx], );
> > -   if (ret)
> > -   return ret;
> > -   while (!valid) {
> > -   /* Valid bit is 0 for 6 AHB clock cycles.
> > -* At 19.2MHz, 1 AHB clock is ~60ns.
> > -* We should enter this loop very, very rarely.
> > -*/
> > -   ndelay(400);
> > +   /* VER_0 doesn't have VALID bit */
> > +   if (tsens_version(priv) >= VER_0_1) {
> > ret = regmap_field_read(priv->rf[valid_idx], );
> > if (ret)
> > return ret;
> > +   while (!valid) {
> > +   /* Valid bit is 0 for 6 AHB clock cycles.
> > +* At 19.2MHz, 1 AHB clock is ~60ns.
> > +* We should enter this loop very, very rarely.
> > +*/
> > +   ndelay(400);
> > +   ret = regmap_field_read(priv->rf[valid_idx], );
> > +   if (ret)
> > +   return ret;
> > +   }
> > }
> > /* Valid bit is set, OK to read the temperature */
> > @@ -608,15 +628,29 @@ int get_temp_common(const struct tsens_sensor *s, int 
> > *temp)
> >   {
> > struct tsens_priv *priv = s->priv;
> > int hw_id = s->hw_id;
> > -   int last_temp = 0, ret;
> > +   int last_temp = 0, ret, trdy;
> > +   unsigned long timeout;
> > -   ret = regmap_field_read(priv->rf[LAST_TEMP_0 + hw_id], _temp);
> > -   if (ret)
> > -   return ret;
> > +   timeout = jiffies + usecs_to_jiffies(TIMEOUT_US);
> > +   do {
> > +   if (tsens_version(priv) == VER_0) {
> > +   ret = regmap_fie

[PATCH v11 9/9] dt-bindings: thermal: tsens: Document ipq8064 bindings

2021-03-18 Thread Ansuel Smith
Document the use of bindings used for msm8960 tsens based devices.
msm8960 use the same gcc regs and is set as a child of the qcom gcc.

Signed-off-by: Ansuel Smith 
Reviewed-by: Rob Herring 
---
 .../bindings/thermal/qcom-tsens.yaml  | 56 ---
 1 file changed, 48 insertions(+), 8 deletions(-)

diff --git a/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml 
b/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml
index 95462e071ab4..1785b1c75a3c 100644
--- a/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml
+++ b/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml
@@ -19,6 +19,11 @@ description: |
 properties:
   compatible:
 oneOf:
+  - description: msm9860 TSENS based
+items:
+  - enum:
+  - qcom,ipq8064-tsens
+
   - description: v0.1 of TSENS
 items:
   - enum:
@@ -73,7 +78,9 @@ properties:
 maxItems: 2
 items:
   - const: calib
-  - const: calib_sel
+  - enum:
+  - calib_backup
+  - calib_sel
 
   "#qcom,sensors":
 description:
@@ -88,12 +95,20 @@ properties:
   Number of cells required to uniquely identify the thermal sensors. Since
   we have multiple sensors this is set to 1
 
+required:
+  - compatible
+  - interrupts
+  - interrupt-names
+  - "#thermal-sensor-cells"
+  - "#qcom,sensors"
+
 allOf:
   - if:
   properties:
 compatible:
   contains:
 enum:
+  - qcom,ipq8064-tsens
   - qcom,msm8916-tsens
   - qcom,msm8974-tsens
   - qcom,msm8976-tsens
@@ -114,17 +129,42 @@ allOf:
 interrupt-names:
   minItems: 2
 
-required:
-  - compatible
-  - reg
-  - "#qcom,sensors"
-  - interrupts
-  - interrupt-names
-  - "#thermal-sensor-cells"
+  - if:
+  properties:
+compatible:
+  contains:
+enum:
+  - qcom,tsens-v0_1
+  - qcom,tsens-v1
+  - qcom,tsens-v2
+
+then:
+  required:
+- reg
 
 additionalProperties: false
 
 examples:
+  - |
+#include 
+// Example msm9860 based SoC (ipq8064):
+gcc: clock-controller {
+
+   /* ... */
+
+   tsens: thermal-sensor {
+compatible = "qcom,ipq8064-tsens";
+
+ nvmem-cells = <_calib>, <_calib_backup>;
+ nvmem-cell-names = "calib", "calib_backup";
+ interrupts = ;
+ interrupt-names = "uplow";
+
+ #qcom,sensors = <11>;
+ #thermal-sensor-cells = <1>;
+  };
+};
+
   - |
 #include 
 // Example 1 (legacy: for pre v1 IP):
-- 
2.30.2



[PATCH v11 8/9] drivers: thermal: tsens: Add support for ipq8064-tsens

2021-03-18 Thread Ansuel Smith
Add support for tsens present in ipq806x SoCs based on generic msm8960
tsens driver.

Signed-off-by: Ansuel Smith 
Reviewed-by: Thara Gopinath 
---
 drivers/thermal/qcom/tsens.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
index 44bce16217db..1fd634f8f5d2 100644
--- a/drivers/thermal/qcom/tsens.c
+++ b/drivers/thermal/qcom/tsens.c
@@ -964,6 +964,9 @@ static SIMPLE_DEV_PM_OPS(tsens_pm_ops, tsens_suspend, 
tsens_resume);
 
 static const struct of_device_id tsens_table[] = {
{
+   .compatible = "qcom,ipq8064-tsens",
+   .data = _8960,
+   }, {
.compatible = "qcom,msm8916-tsens",
.data = _8916,
}, {
-- 
2.30.2



[PATCH v11 7/9] drivers: thermal: tsens: Drop unused define for msm8960

2021-03-18 Thread Ansuel Smith
Drop unused define for msm8960 replaced by generic api and reg_field.

Signed-off-by: Ansuel Smith 
---
 drivers/thermal/qcom/tsens-8960.c | 24 +---
 1 file changed, 1 insertion(+), 23 deletions(-)

diff --git a/drivers/thermal/qcom/tsens-8960.c 
b/drivers/thermal/qcom/tsens-8960.c
index 8c523b764862..31e44d17d484 100644
--- a/drivers/thermal/qcom/tsens-8960.c
+++ b/drivers/thermal/qcom/tsens-8960.c
@@ -10,8 +10,6 @@
 #include 
 #include "tsens.h"
 
-#define CAL_MDEGC  3
-
 #define CONFIG_ADDR0x3640
 #define CONFIG_ADDR_8660   0x3620
 /* CONFIG_ADDR bitmasks */
@@ -21,39 +19,19 @@
 #define CONFIG_SHIFT_8660  28
 #define CONFIG_MASK_8660   (3 << CONFIG_SHIFT_8660)
 
-#define STATUS_CNTL_ADDR_8064  0x3660
 #define CNTL_ADDR  0x3620
 /* CNTL_ADDR bitmasks */
 #define EN BIT(0)
 #define SW_RST BIT(1)
-#define SENSOR0_EN BIT(3)
+
 #define MEASURE_PERIOD BIT(18)
 #define SLP_CLK_ENABIT(26)
 #define SLP_CLK_ENA_8660   BIT(24)
 #define SENSOR0_SHIFT  3
 
-/* INT_STATUS_ADDR bitmasks */
-#define MIN_STATUS_MASKBIT(0)
-#define LOWER_STATUS_CLR   BIT(1)
-#define UPPER_STATUS_CLR   BIT(2)
-#define MAX_STATUS_MASKBIT(3)
-
 #define THRESHOLD_ADDR 0x3624
-/* THRESHOLD_ADDR bitmasks */
-#define THRESHOLD_MAX_LIMIT_SHIFT  24
-#define THRESHOLD_MIN_LIMIT_SHIFT  16
-#define THRESHOLD_UPPER_LIMIT_SHIFT8
-#define THRESHOLD_LOWER_LIMIT_SHIFT0
-
-/* Initial temperature threshold values */
-#define LOWER_LIMIT_TH 0x50
-#define UPPER_LIMIT_TH 0xdf
-#define MIN_LIMIT_TH   0x0
-#define MAX_LIMIT_TH   0xff
 
 #define INT_STATUS_ADDR0x363c
-#define TRDY_MASK  BIT(7)
-#define TIMEOUT_US 100
 
 #define S0_STATUS_OFF  0x3628
 #define S1_STATUS_OFF  0x362c
-- 
2.30.2



[PATCH v11 3/9] drivers: thermal: tsens: Convert msm8960 to reg_field

2021-03-18 Thread Ansuel Smith
Convert msm9860 driver to reg_field to use the init_common
function.

Signed-off-by: Ansuel Smith 
Acked-by: Thara Gopinath 
---
 drivers/thermal/qcom/tsens-8960.c | 80 ++-
 1 file changed, 79 insertions(+), 1 deletion(-)

diff --git a/drivers/thermal/qcom/tsens-8960.c 
b/drivers/thermal/qcom/tsens-8960.c
index 2a28a5af209e..3f4fc1ffe679 100644
--- a/drivers/thermal/qcom/tsens-8960.c
+++ b/drivers/thermal/qcom/tsens-8960.c
@@ -51,11 +51,22 @@
 #define MIN_LIMIT_TH   0x0
 #define MAX_LIMIT_TH   0xff
 
-#define S0_STATUS_ADDR 0x3628
 #define INT_STATUS_ADDR0x363c
 #define TRDY_MASK  BIT(7)
 #define TIMEOUT_US 100
 
+#define S0_STATUS_OFF  0x3628
+#define S1_STATUS_OFF  0x362c
+#define S2_STATUS_OFF  0x3630
+#define S3_STATUS_OFF  0x3634
+#define S4_STATUS_OFF  0x3638
+#define S5_STATUS_OFF  0x3664  /* Sensors 5-10 found on 
apq8064/msm8960 */
+#define S6_STATUS_OFF  0x3668
+#define S7_STATUS_OFF  0x366c
+#define S8_STATUS_OFF  0x3670
+#define S9_STATUS_OFF  0x3674
+#define S10_STATUS_OFF 0x3678
+
 static int suspend_8960(struct tsens_priv *priv)
 {
int ret;
@@ -269,6 +280,71 @@ static int get_temp_8960(const struct tsens_sensor *s, int 
*temp)
return -ETIMEDOUT;
 }
 
+static struct tsens_features tsens_8960_feat = {
+   .ver_major  = VER_0,
+   .crit_int   = 0,
+   .adc= 1,
+   .srot_split = 0,
+   .max_sensors= 11,
+};
+
+static const struct reg_field tsens_8960_regfields[MAX_REGFIELDS] = {
+   /* - SROT -- */
+   /* No VERSION information */
+
+   /* CNTL */
+   [TSENS_EN] = REG_FIELD(CNTL_ADDR,  0, 0),
+   [TSENS_SW_RST] = REG_FIELD(CNTL_ADDR,  1, 1),
+   /* 8960 has 5 sensors, 8660 has 11, we only handle 5 */
+   [SENSOR_EN]= REG_FIELD(CNTL_ADDR,  3, 7),
+
+   /* - TM -- */
+   /* INTERRUPT ENABLE */
+   /* NO INTERRUPT ENABLE */
+
+   /* Single UPPER/LOWER TEMPERATURE THRESHOLD for all sensors */
+   [LOW_THRESH_0]   = REG_FIELD(THRESHOLD_ADDR,  0,  7),
+   [UP_THRESH_0]= REG_FIELD(THRESHOLD_ADDR,  8, 15),
+   /* MIN_THRESH_0 and MAX_THRESH_0 are not present in the regfield
+* Recycle CRIT_THRESH_0 and 1 to set the required regs to hardcoded 
temp
+* MIN_THRESH_0 -> CRIT_THRESH_1
+* MAX_THRESH_0 -> CRIT_THRESH_0
+*/
+   [CRIT_THRESH_1]   = REG_FIELD(THRESHOLD_ADDR, 16, 23),
+   [CRIT_THRESH_0]   = REG_FIELD(THRESHOLD_ADDR, 24, 31),
+
+   /* UPPER/LOWER INTERRUPT [CLEAR/STATUS] */
+   /* 1 == clear, 0 == normal operation */
+   [LOW_INT_CLEAR_0]   = REG_FIELD(CNTL_ADDR,  9,  9),
+   [UP_INT_CLEAR_0]= REG_FIELD(CNTL_ADDR, 10, 10),
+
+   /* NO CRITICAL INTERRUPT SUPPORT on 8960 */
+
+   /* Sn_STATUS */
+   [LAST_TEMP_0]  = REG_FIELD(S0_STATUS_OFF,  0,  7),
+   [LAST_TEMP_1]  = REG_FIELD(S1_STATUS_OFF,  0,  7),
+   [LAST_TEMP_2]  = REG_FIELD(S2_STATUS_OFF,  0,  7),
+   [LAST_TEMP_3]  = REG_FIELD(S3_STATUS_OFF,  0,  7),
+   [LAST_TEMP_4]  = REG_FIELD(S4_STATUS_OFF,  0,  7),
+   [LAST_TEMP_5]  = REG_FIELD(S5_STATUS_OFF,  0,  7),
+   [LAST_TEMP_6]  = REG_FIELD(S6_STATUS_OFF,  0,  7),
+   [LAST_TEMP_7]  = REG_FIELD(S7_STATUS_OFF,  0,  7),
+   [LAST_TEMP_8]  = REG_FIELD(S8_STATUS_OFF,  0,  7),
+   [LAST_TEMP_9]  = REG_FIELD(S9_STATUS_OFF,  0,  7),
+   [LAST_TEMP_10] = REG_FIELD(S10_STATUS_OFF, 0,  7),
+
+   /* No VALID field on 8960 */
+   /* TSENS_INT_STATUS bits: 1 == threshold violated */
+   [MIN_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 0, 0),
+   [LOWER_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 1, 1),
+   [UPPER_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 2, 2),
+   /* No CRITICAL field on 8960 */
+   [MAX_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 3, 3),
+
+   /* TRDY: 1=ready, 0=in progress */
+   [TRDY] = REG_FIELD(INT_STATUS_ADDR, 7, 7),
+};
+
 static const struct tsens_ops ops_8960 = {
.init   = init_8960,
.calibrate  = calibrate_8960,
@@ -282,4 +358,6 @@ static const struct tsens_ops ops_8960 = {
 struct tsens_plat_data data_8960 = {
.num_sensors= 11,
.ops= _8960,
+   .feat   = _8960_feat,
+   .fields = tsens_8960_regfields,
 };
-- 
2.30.2



[PATCH v11 6/9] drivers: thermal: tsens: Replace custom 8960 apis with generic apis

2021-03-18 Thread Ansuel Smith
Rework calibrate function to use common function. Derive the offset from
a missing hardcoded slope table and the data from the nvmem calib
efuses.
Drop custom get_temp function and use generic api.

Signed-off-by: Ansuel Smith 
Acked-by: Thara Gopinath 
---
 drivers/thermal/qcom/tsens-8960.c | 56 +--
 1 file changed, 15 insertions(+), 41 deletions(-)

diff --git a/drivers/thermal/qcom/tsens-8960.c 
b/drivers/thermal/qcom/tsens-8960.c
index bdc64d4188bf..8c523b764862 100644
--- a/drivers/thermal/qcom/tsens-8960.c
+++ b/drivers/thermal/qcom/tsens-8960.c
@@ -67,6 +67,13 @@
 #define S9_STATUS_OFF  0x3674
 #define S10_STATUS_OFF 0x3678
 
+/* Original slope - 200 to compensate mC to C inaccuracy */
+u32 tsens_msm8960_slope[] = {
+   976, 976, 954, 976,
+   911, 932, 932, 999,
+   932, 999, 932
+   };
+
 static int suspend_8960(struct tsens_priv *priv)
 {
int ret;
@@ -195,9 +202,7 @@ static int calibrate_8960(struct tsens_priv *priv)
 {
int i;
char *data;
-
-   ssize_t num_read = priv->num_sensors;
-   struct tsens_sensor *s = priv->sensor;
+   u32 p1[11];
 
data = qfprom_read(priv->dev, "calib");
if (IS_ERR(data))
@@ -205,49 +210,18 @@ static int calibrate_8960(struct tsens_priv *priv)
if (IS_ERR(data))
return PTR_ERR(data);
 
-   for (i = 0; i < num_read; i++, s++)
-   s->offset = data[i];
+   for (i = 0; i < priv->num_sensors; i++) {
+   p1[i] = data[i];
+   priv->sensor[i].slope = tsens_msm8960_slope[i];
+   }
+
+   compute_intercept_slope(priv, p1, NULL, ONE_PT_CALIB);
 
kfree(data);
 
return 0;
 }
 
-/* Temperature on y axis and ADC-code on x-axis */
-static inline int code_to_mdegC(u32 adc_code, const struct tsens_sensor *s)
-{
-   int slope, offset;
-
-   slope = thermal_zone_get_slope(s->tzd);
-   offset = CAL_MDEGC - slope * s->offset;
-
-   return adc_code * slope + offset;
-}
-
-static int get_temp_8960(const struct tsens_sensor *s, int *temp)
-{
-   int ret;
-   u32 code, trdy;
-   struct tsens_priv *priv = s->priv;
-   unsigned long timeout;
-
-   timeout = jiffies + usecs_to_jiffies(TIMEOUT_US);
-   do {
-   ret = regmap_read(priv->tm_map, INT_STATUS_ADDR, );
-   if (ret)
-   return ret;
-   if (!(trdy & TRDY_MASK))
-   continue;
-   ret = regmap_read(priv->tm_map, s->status, );
-   if (ret)
-   return ret;
-   *temp = code_to_mdegC(code, s);
-   return 0;
-   } while (time_before(jiffies, timeout));
-
-   return -ETIMEDOUT;
-}
-
 static struct tsens_features tsens_8960_feat = {
.ver_major  = VER_0,
.crit_int   = 0,
@@ -316,7 +290,7 @@ static const struct reg_field 
tsens_8960_regfields[MAX_REGFIELDS] = {
 static const struct tsens_ops ops_8960 = {
.init   = init_common,
.calibrate  = calibrate_8960,
-   .get_temp   = get_temp_8960,
+   .get_temp   = get_temp_common,
.enable = enable_8960,
.disable= disable_8960,
.suspend= suspend_8960,
-- 
2.30.2



[PATCH v11 5/9] drivers: thermal: tsens: Fix bug in sensor enable for msm8960

2021-03-18 Thread Ansuel Smith
Device based on tsens VER_0 contains a hardware bug that results in some
problem with sensor enablement. Sensor id 6-11 can't be enabled
selectively and all of them must be enabled in one step.

Signed-off-by: Ansuel Smith 
---
 drivers/thermal/qcom/tsens-8960.c | 24 +---
 1 file changed, 21 insertions(+), 3 deletions(-)

diff --git a/drivers/thermal/qcom/tsens-8960.c 
b/drivers/thermal/qcom/tsens-8960.c
index 86585f439985..bdc64d4188bf 100644
--- a/drivers/thermal/qcom/tsens-8960.c
+++ b/drivers/thermal/qcom/tsens-8960.c
@@ -27,9 +27,9 @@
 #define EN BIT(0)
 #define SW_RST BIT(1)
 #define SENSOR0_EN BIT(3)
+#define MEASURE_PERIOD BIT(18)
 #define SLP_CLK_ENABIT(26)
 #define SLP_CLK_ENA_8660   BIT(24)
-#define MEASURE_PERIOD 1
 #define SENSOR0_SHIFT  3
 
 /* INT_STATUS_ADDR bitmasks */
@@ -126,17 +126,35 @@ static int resume_8960(struct tsens_priv *priv)
 static int enable_8960(struct tsens_priv *priv, int id)
 {
int ret;
-   u32 reg, mask;
+   u32 reg, mask = BIT(id);
 
ret = regmap_read(priv->tm_map, CNTL_ADDR, );
if (ret)
return ret;
 
-   mask = BIT(id + SENSOR0_SHIFT);
+   /* HARDWARE BUG:
+* On platform with more than 6 sensors, all the remaining
+* sensors needs to be enabled all togheder or underfined
+* results are expected. (Sensor 6-7 disabled, Sensor 3
+* disabled...) In the original driver, all the sensors
+* are enabled in one step hence this bug is not triggered.
+*/
+   if (id > 5) {
+   mask = GENMASK(10, 6);
+
+   /* Sensors already enabled. Skip. */
+   if ((reg & mask) == mask)
+   return 0;
+   }
+
+   mask <<= SENSOR0_SHIFT;
+
ret = regmap_write(priv->tm_map, CNTL_ADDR, reg | SW_RST);
if (ret)
return ret;
 
+   reg |= MEASURE_PERIOD;
+
if (priv->num_sensors > 1)
reg |= mask | SLP_CLK_ENA | EN;
else
-- 
2.30.2



[PATCH v11 4/9] drivers: thermal: tsens: Use init_common for msm8960

2021-03-18 Thread Ansuel Smith
Use init_common and drop custom init for msm8960.

Signed-off-by: Ansuel Smith 
Reviewed-by: Thara Gopinath 
---
 drivers/thermal/qcom/tsens-8960.c | 52 +--
 1 file changed, 1 insertion(+), 51 deletions(-)

diff --git a/drivers/thermal/qcom/tsens-8960.c 
b/drivers/thermal/qcom/tsens-8960.c
index 3f4fc1ffe679..86585f439985 100644
--- a/drivers/thermal/qcom/tsens-8960.c
+++ b/drivers/thermal/qcom/tsens-8960.c
@@ -173,56 +173,6 @@ static void disable_8960(struct tsens_priv *priv)
regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
 }
 
-static int init_8960(struct tsens_priv *priv)
-{
-   int ret, i;
-   u32 reg_cntl;
-
-   priv->tm_map = dev_get_regmap(priv->dev, NULL);
-   if (!priv->tm_map)
-   return -ENODEV;
-
-   /*
-* The status registers for each sensor are discontiguous
-* because some SoCs have 5 sensors while others have more
-* but the control registers stay in the same place, i.e
-* directly after the first 5 status registers.
-*/
-   for (i = 0; i < priv->num_sensors; i++) {
-   if (i >= 5)
-   priv->sensor[i].status = S0_STATUS_ADDR + 40;
-   priv->sensor[i].status += i * 4;
-   }
-
-   reg_cntl = SW_RST;
-   ret = regmap_update_bits(priv->tm_map, CNTL_ADDR, SW_RST, reg_cntl);
-   if (ret)
-   return ret;
-
-   if (priv->num_sensors > 1) {
-   reg_cntl |= SLP_CLK_ENA | (MEASURE_PERIOD << 18);
-   reg_cntl &= ~SW_RST;
-   ret = regmap_update_bits(priv->tm_map, CONFIG_ADDR,
-CONFIG_MASK, CONFIG);
-   } else {
-   reg_cntl |= SLP_CLK_ENA_8660 | (MEASURE_PERIOD << 16);
-   reg_cntl &= ~CONFIG_MASK_8660;
-   reg_cntl |= CONFIG_8660 << CONFIG_SHIFT_8660;
-   }
-
-   reg_cntl |= GENMASK(priv->num_sensors - 1, 0) << SENSOR0_SHIFT;
-   ret = regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
-   if (ret)
-   return ret;
-
-   reg_cntl |= EN;
-   ret = regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
-   if (ret)
-   return ret;
-
-   return 0;
-}
-
 static int calibrate_8960(struct tsens_priv *priv)
 {
int i;
@@ -346,7 +296,7 @@ static const struct reg_field 
tsens_8960_regfields[MAX_REGFIELDS] = {
 };
 
 static const struct tsens_ops ops_8960 = {
-   .init   = init_8960,
+   .init   = init_common,
.calibrate  = calibrate_8960,
.get_temp   = get_temp_8960,
.enable = enable_8960,
-- 
2.30.2



[PATCH v11 2/9] drivers: thermal: tsens: Don't hardcode sensor slope

2021-03-18 Thread Ansuel Smith
Function compute_intercept_slope hardcode the sensor slope to
SLOPE_DEFAULT. Change this and use the default value only if a slope is
not defined. This is needed for tsens VER_0 that has a hardcoded slope
table.

Signed-off-by: Ansuel Smith 
Reviewed-by: Thara Gopinath 
---
 drivers/thermal/qcom/tsens.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
index 277d9b17e949..44bce16217db 100644
--- a/drivers/thermal/qcom/tsens.c
+++ b/drivers/thermal/qcom/tsens.c
@@ -86,7 +86,8 @@ void compute_intercept_slope(struct tsens_priv *priv, u32 *p1,
"%s: sensor%d - data_point1:%#x data_point2:%#x\n",
__func__, i, p1[i], p2[i]);
 
-   priv->sensor[i].slope = SLOPE_DEFAULT;
+   if (!priv->sensor[i].slope)
+   priv->sensor[i].slope = SLOPE_DEFAULT;
if (mode == TWO_PT_CALIB) {
/*
 * slope (m) = adc_code2 - adc_code1 (y2 - y1)/
-- 
2.30.2



[PATCH v11 1/9] drivers: thermal: tsens: Add VER_0 tsens version

2021-03-18 Thread Ansuel Smith
VER_0 is used to describe device based on tsens version before v0.1.
These device are devices based on msm8960 for example apq8064 or
ipq806x.

Signed-off-by: Ansuel Smith 
---
 drivers/thermal/qcom/tsens.c | 141 ---
 drivers/thermal/qcom/tsens.h |   4 +-
 2 files changed, 116 insertions(+), 29 deletions(-)

diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
index d8ce3a687b80..277d9b17e949 100644
--- a/drivers/thermal/qcom/tsens.c
+++ b/drivers/thermal/qcom/tsens.c
@@ -12,6 +12,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -515,6 +516,15 @@ static irqreturn_t tsens_irq_thread(int irq, void *data)
dev_dbg(priv->dev, "[%u] %s: no violation:  %d\n",
hw_id, __func__, temp);
}
+
+   if (tsens_version(priv) < VER_0_1) {
+   /* Constraint: There is only 1 interrupt control 
register for all
+* 11 temperature sensor. So monitoring more than 1 
sensor based
+* on interrupts will yield inconsistent result. To 
overcome this
+* issue we will monitor only sensor 0 which is the 
master sensor.
+*/
+   break;
+   }
}
 
return IRQ_HANDLED;
@@ -530,6 +540,13 @@ static int tsens_set_trips(void *_sensor, int low, int 
high)
int high_val, low_val, cl_high, cl_low;
u32 hw_id = s->hw_id;
 
+   if (tsens_version(priv) < VER_0_1) {
+   /* Pre v0.1 IP had a single register for each type of interrupt
+* and thresholds
+*/
+   hw_id = 0;
+   }
+
dev_dbg(dev, "[%u] %s: proposed thresholds: (%d:%d)\n",
hw_id, __func__, low, high);
 
@@ -584,18 +601,21 @@ int get_temp_tsens_valid(const struct tsens_sensor *s, 
int *temp)
u32 valid;
int ret;
 
-   ret = regmap_field_read(priv->rf[valid_idx], );
-   if (ret)
-   return ret;
-   while (!valid) {
-   /* Valid bit is 0 for 6 AHB clock cycles.
-* At 19.2MHz, 1 AHB clock is ~60ns.
-* We should enter this loop very, very rarely.
-*/
-   ndelay(400);
+   /* VER_0 doesn't have VALID bit */
+   if (tsens_version(priv) >= VER_0_1) {
ret = regmap_field_read(priv->rf[valid_idx], );
if (ret)
return ret;
+   while (!valid) {
+   /* Valid bit is 0 for 6 AHB clock cycles.
+* At 19.2MHz, 1 AHB clock is ~60ns.
+* We should enter this loop very, very rarely.
+*/
+   ndelay(400);
+   ret = regmap_field_read(priv->rf[valid_idx], );
+   if (ret)
+   return ret;
+   }
}
 
/* Valid bit is set, OK to read the temperature */
@@ -608,15 +628,29 @@ int get_temp_common(const struct tsens_sensor *s, int 
*temp)
 {
struct tsens_priv *priv = s->priv;
int hw_id = s->hw_id;
-   int last_temp = 0, ret;
+   int last_temp = 0, ret, trdy;
+   unsigned long timeout;
 
-   ret = regmap_field_read(priv->rf[LAST_TEMP_0 + hw_id], _temp);
-   if (ret)
-   return ret;
+   timeout = jiffies + usecs_to_jiffies(TIMEOUT_US);
+   do {
+   if (tsens_version(priv) == VER_0) {
+   ret = regmap_field_read(priv->rf[TRDY], );
+   if (ret)
+   return ret;
+   if (!trdy)
+   continue;
+   }
 
-   *temp = code_to_degc(last_temp, s) * 1000;
+   ret = regmap_field_read(priv->rf[LAST_TEMP_0 + hw_id], 
_temp);
+   if (ret)
+   return ret;
 
-   return 0;
+   *temp = code_to_degc(last_temp, s) * 1000;
+
+   return 0;
+   } while (time_before(jiffies, timeout));
+
+   return -ETIMEDOUT;
 }
 
 #ifdef CONFIG_DEBUG_FS
@@ -738,19 +772,31 @@ int __init init_common(struct tsens_priv *priv)
priv->tm_offset = 0x1000;
}
 
-   res = platform_get_resource(op, IORESOURCE_MEM, 0);
-   tm_base = devm_ioremap_resource(dev, res);
-   if (IS_ERR(tm_base)) {
-   ret = PTR_ERR(tm_base);
-   goto err_put_device;
+   if (tsens_version(priv) >= VER_0_1) {
+   res = platform_get_resource(op, IORESOURCE_MEM, 0);
+   tm_base = devm_ioremap_resource(dev, res);
+   if (IS_ERR(tm_base)) {
+   ret = PTR_ERR(tm_base);
+   goto err_put_device;
+   }
+
+ 

[PATCH v11 0/9] Add support for ipq8064 tsens

2021-03-18 Thread Ansuel Smith
This patchset convert msm8960 to reg_filed, use int_common instead 
of a custom function and fix wrong tsens get_temp function for msm8960.
Ipq8064 SoCs tsens driver is based on 8960 tsens driver. Ipq8064 needs
to be registered as a gcc child as the tsens regs on this platform are
shared with the controller.
This is based on work and code here
https://git.linaro.org/people/amit.kucheria/kernel.git/log/?h=wrk3/tsens-8960-breakage

v11:
* Address comments from Thara (thx)
v10:
* Fix wrong tsens init for ver_0 (crit_trips needs to be set in tsens_register)
v9:
* Fix warning from Documentation bot
v8:
* Drop MIN and MAX THRESH and use CRIT_THRESH instead
* Fix broken documentation patch
v7:
* Rework calibrate function to use get_temp_common
* Fix wrong required in the Documentation for ipq8064
* Fix hardware bug in sensor enable function
v6:
* Fix spelling error (can't find the problem with variable misallignment)
* Rework big if-else
* Remove extra comments
* Add description about different interrupts
v5:
* Conver driver to use reg_fiedl
* Use init_common 
* Drop custom set_trip and set_interrupt
* Use common set_trip and set_interrupt
* Fix bad get_temp function
* Add missing hardcoded slope
v4:
* Fix compilation error and warning reported by the bot
v3:
* Change driver to register as child instead of use phandle
v2:
* Fix dt-bindings problems

Ansuel Smith (9):
  drivers: thermal: tsens: Add VER_0 tsens version
  drivers: thermal: tsens: Don't hardcode sensor slope
  drivers: thermal: tsens: Convert msm8960 to reg_field
  drivers: thermal: tsens: Use init_common for msm8960
  drivers: thermal: tsens: Fix bug in sensor enable for msm8960
  drivers: thermal: tsens: Replace custom 8960 apis with generic apis
  drivers: thermal: tsens: Drop unused define for msm8960
  drivers: thermal: tsens: Add support for ipq8064-tsens
  dt-bindings: thermal: tsens: Document ipq8064 bindings

 .../bindings/thermal/qcom-tsens.yaml  |  56 -
 drivers/thermal/qcom/tsens-8960.c | 234 +-
 drivers/thermal/qcom/tsens.c  | 147 ---
 drivers/thermal/qcom/tsens.h  |   4 +-
 4 files changed, 285 insertions(+), 156 deletions(-)

-- 
2.30.2



[PATCH v7 1/3] mtd: core: add nvmem-cells compatible to parse mtd as nvmem cells

2021-03-12 Thread Ansuel Smith
Partitions that contains the nvmem-cells compatible will register
their direct subonodes as nvmem cells and the node will be treated as a
nvmem provider.

Signed-off-by: Ansuel Smith 
Tested-by: Rafał Miłecki 
---
 drivers/mtd/mtdcore.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index 2d6423d89a17..ac1b4f176a17 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -531,6 +531,7 @@ static int mtd_nvmem_reg_read(void *priv, unsigned int 
offset,
 
 static int mtd_nvmem_add(struct mtd_info *mtd)
 {
+   struct device_node *node = mtd_get_of_node(mtd);
struct nvmem_config config = {};
 
config.id = -1;
@@ -543,7 +544,7 @@ static int mtd_nvmem_add(struct mtd_info *mtd)
config.stride = 1;
config.read_only = true;
config.root_only = true;
-   config.no_of_node = true;
+   config.no_of_node = !of_device_is_compatible(node, "nvmem-cells");
config.priv = mtd;
 
mtd->nvmem = nvmem_register();
-- 
2.30.0



[PATCH v7 2/3] devicetree: nvmem: nvmem: drop $nodename restriction

2021-03-12 Thread Ansuel Smith
Drop $nodename restriction as now mtd partition can also be used as
nvmem provider.

Signed-off-by: Ansuel Smith 
---
 Documentation/devicetree/bindings/nvmem/nvmem.yaml | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/nvmem/nvmem.yaml 
b/Documentation/devicetree/bindings/nvmem/nvmem.yaml
index 7481a9e48f19..b8dc3d2b6e92 100644
--- a/Documentation/devicetree/bindings/nvmem/nvmem.yaml
+++ b/Documentation/devicetree/bindings/nvmem/nvmem.yaml
@@ -20,9 +20,6 @@ description: |
   storage device.
 
 properties:
-  $nodename:
-pattern: "^(eeprom|efuse|nvram)(@.*|-[0-9a-f])*$"
-
   "#address-cells":
 const: 1
 
-- 
2.30.0



[PATCH v7 3/3] dt-bindings: mtd: Document use of nvmem-cells compatible

2021-03-12 Thread Ansuel Smith
Document nvmem-cells compatible used to treat mtd partitions as a
nvmem provider.

Signed-off-by: Ansuel Smith 
Reviewed-by: Rob Herring 
---
 .../bindings/mtd/partitions/nvmem-cells.yaml  | 99 +++
 1 file changed, 99 insertions(+)
 create mode 100644 
Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml

diff --git a/Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml 
b/Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml
new file mode 100644
index ..5cdd2efa9132
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml
@@ -0,0 +1,99 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mtd/partitions/nvmem-cells.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Nvmem cells
+
+description: |
+  Any partition containing the compatible "nvmem-cells" will register as a
+  nvmem provider.
+  Each direct subnodes represents a nvmem cell following the nvmem binding.
+  Nvmem binding to declare nvmem-cells can be found in:
+  Documentation/devicetree/bindings/nvmem/nvmem.yaml
+
+maintainers:
+  - Ansuel Smith 
+
+allOf:
+  - $ref: /schemas/nvmem/nvmem.yaml#
+
+properties:
+  compatible:
+const: nvmem-cells
+
+required:
+  - compatible
+
+additionalProperties: true
+
+examples:
+  - |
+partitions {
+  compatible = "fixed-partitions";
+  #address-cells = <1>;
+  #size-cells = <1>;
+
+  /* ... */
+
+  };
+  art: art@120 {
+compatible = "nvmem-cells";
+reg = <0x120 0x014>;
+label = "art";
+read-only;
+#address-cells = <1>;
+#size-cells = <1>;
+
+macaddr_gmac1: macaddr_gmac1@0 {
+  reg = <0x0 0x6>;
+};
+
+macaddr_gmac2: macaddr_gmac2@6 {
+  reg = <0x6 0x6>;
+};
+
+pre_cal_24g: pre_cal_24g@1000 {
+  reg = <0x1000 0x2f20>;
+};
+
+pre_cal_5g: pre_cal_5g@5000{
+  reg = <0x5000 0x2f20>;
+};
+  };
+  - |
+partitions {
+compatible = "fixed-partitions";
+#address-cells = <1>;
+#size-cells = <1>;
+
+partition@0 {
+label = "bootloader";
+reg = <0x00 0x10>;
+read-only;
+};
+
+firmware@10 {
+compatible = "brcm,trx";
+label = "firmware";
+reg = <0x10 0xe0>;
+};
+
+calibration@f0 {
+compatible = "nvmem-cells";
+label = "calibration";
+reg = <0xf0 0x10>;
+ranges = <0 0xf0 0x10>;
+#address-cells = <1>;
+#size-cells = <1>;
+
+wifi0@0 {
+reg = <0x00 0x08>;
+};
+
+wifi1@8 {
+reg = <0x08 0x08>;
+};
+};
+};
-- 
2.30.0



Re: [PATCH v5 2/3] dt-bindings: mtd: Document use of nvmem-cells compatible

2021-03-11 Thread Ansuel Smith
On Thu, Mar 11, 2021 at 10:32:21AM -0700, Rob Herring wrote:
> On Thu, Mar 11, 2021 at 06:12:48AM +0100, Ansuel Smith wrote:
> > Document nvmem-cells compatible used to treat mtd partitions as a
> > nvmem provider.
> > 
> > Signed-off-by: Ansuel Smith 
> > ---
> >  .../bindings/mtd/partitions/nvmem-cells.yaml  | 99 +++
> >  1 file changed, 99 insertions(+)
> >  create mode 100644 
> > Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml
> > 
> > diff --git 
> > a/Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml 
> > b/Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml
> > new file mode 100644
> > index ..b53faf87d4e4
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml
> > @@ -0,0 +1,99 @@
> > +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/mtd/partitions/nvmem-cells.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: Nvmem cells
> > +
> > +description: |
> > +  Any partition containing the compatible "nvmem-cells" will register as a
> > +  nvmem provider.
> > +  Each direct subnodes represents a nvmem cell following the nvmem binding.
> > +  Nvmem binding to declare nvmem-cells can be found in:
> > +  Documentation/devicetree/bindings/nvmem/nvmem.yaml
> > +
> > +maintainers:
> > +  - Ansuel Smith 
> > +
> > +allOf:
> > +  - $ref: "../../nvmem/nvmem.yaml#"
> 
> I'd rather have the 'absolute' path:
> 
> /schemas/nvmem/nvmem.yaml
> 
> Otherwise,
> 
> Reviewed-by: Rob Herring 
>

Should I send a v7?

> > +
> > +properties:
> > +  compatible:
> > +const: nvmem-cells
> > +
> > +required:
> > +  - compatible
> > +
> > +additionalProperties: true
> > +
> > +examples:
> > +  - |
> > +partitions {
> > +  compatible = "fixed-partitions";
> > +  #address-cells = <1>;
> > +  #size-cells = <1>;
> > +
> > +  /* ... */
> > +
> > +  };
> > +  art: art@120 {
> > +compatible = "nvmem-cells";
> > +reg = <0x120 0x014>;
> > +label = "art";
> > +read-only;
> > +#address-cells = <1>;
> > +#size-cells = <1>;
> > +
> > +macaddr_gmac1: macaddr_gmac1@0 {
> > +  reg = <0x0 0x6>;
> > +};
> > +
> > +macaddr_gmac2: macaddr_gmac2@6 {
> > +  reg = <0x6 0x6>;
> > +};
> > +
> > +pre_cal_24g: pre_cal_24g@1000 {
> > +  reg = <0x1000 0x2f20>;
> > +};
> > +
> > +pre_cal_5g: pre_cal_5g@5000{
> > +  reg = <0x5000 0x2f20>;
> > +};
> > +  };
> > +  - |
> > +partitions {
> > +compatible = "fixed-partitions";
> > +#address-cells = <1>;
> > +#size-cells = <1>;
> > +
> > +partition@0 {
> > +label = "bootloader";
> > +reg = <0x00 0x10>;
> > +read-only;
> > +};
> > +
> > +firmware@10 {
> > +compatible = "brcm,trx";
> > +label = "firmware";
> > +reg = <0x10 0xe0>;
> > +};
> > +
> > +calibration@f0 {
> > +compatible = "nvmem-cells";
> > +label = "calibration";
> > +reg = <0xf0 0x10>;
> > +ranges = <0 0xf0 0x10>;
> > +#address-cells = <1>;
> > +#size-cells = <1>;
> > +
> > +wifi0@0 {
> > +reg = <0x00 0x08>;
> > +};
> > +
> > +wifi1@8 {
> > +reg = <0x08 0x08>;
> > +};
> > +};
> > +};
> > -- 
> > 2.30.0
> > 


[PATCH v6 3/3] dt-bindings: mtd: Document use of nvmem-cells compatible

2021-03-11 Thread Ansuel Smith
Document nvmem-cells compatible used to treat mtd partitions as a
nvmem provider.

Signed-off-by: Ansuel Smith 
---
 .../bindings/mtd/partitions/nvmem-cells.yaml  | 99 +++
 1 file changed, 99 insertions(+)
 create mode 100644 
Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml

diff --git a/Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml 
b/Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml
new file mode 100644
index ..b53faf87d4e4
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml
@@ -0,0 +1,99 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mtd/partitions/nvmem-cells.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Nvmem cells
+
+description: |
+  Any partition containing the compatible "nvmem-cells" will register as a
+  nvmem provider.
+  Each direct subnodes represents a nvmem cell following the nvmem binding.
+  Nvmem binding to declare nvmem-cells can be found in:
+  Documentation/devicetree/bindings/nvmem/nvmem.yaml
+
+maintainers:
+  - Ansuel Smith 
+
+allOf:
+  - $ref: "../../nvmem/nvmem.yaml#"
+
+properties:
+  compatible:
+const: nvmem-cells
+
+required:
+  - compatible
+
+additionalProperties: true
+
+examples:
+  - |
+partitions {
+  compatible = "fixed-partitions";
+  #address-cells = <1>;
+  #size-cells = <1>;
+
+  /* ... */
+
+  };
+  art: art@120 {
+compatible = "nvmem-cells";
+reg = <0x120 0x014>;
+label = "art";
+read-only;
+#address-cells = <1>;
+#size-cells = <1>;
+
+macaddr_gmac1: macaddr_gmac1@0 {
+  reg = <0x0 0x6>;
+};
+
+macaddr_gmac2: macaddr_gmac2@6 {
+  reg = <0x6 0x6>;
+};
+
+pre_cal_24g: pre_cal_24g@1000 {
+  reg = <0x1000 0x2f20>;
+};
+
+pre_cal_5g: pre_cal_5g@5000{
+  reg = <0x5000 0x2f20>;
+};
+  };
+  - |
+partitions {
+compatible = "fixed-partitions";
+#address-cells = <1>;
+#size-cells = <1>;
+
+partition@0 {
+label = "bootloader";
+reg = <0x00 0x10>;
+read-only;
+};
+
+firmware@10 {
+compatible = "brcm,trx";
+label = "firmware";
+reg = <0x10 0xe0>;
+};
+
+calibration@f0 {
+compatible = "nvmem-cells";
+label = "calibration";
+reg = <0xf0 0x10>;
+ranges = <0 0xf0 0x10>;
+#address-cells = <1>;
+#size-cells = <1>;
+
+wifi0@0 {
+reg = <0x00 0x08>;
+};
+
+wifi1@8 {
+reg = <0x08 0x08>;
+};
+};
+};
-- 
2.30.0



[PATCH v6 2/3] devicetree: nvmem: nvmem: drop $nodename restriction

2021-03-11 Thread Ansuel Smith
Drop $nodename restriction as now mtd partition can also be used as
nvmem provider.

Signed-off-by: Ansuel Smith 
---
 Documentation/devicetree/bindings/nvmem/nvmem.yaml | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/nvmem/nvmem.yaml 
b/Documentation/devicetree/bindings/nvmem/nvmem.yaml
index 7481a9e48f19..b8dc3d2b6e92 100644
--- a/Documentation/devicetree/bindings/nvmem/nvmem.yaml
+++ b/Documentation/devicetree/bindings/nvmem/nvmem.yaml
@@ -20,9 +20,6 @@ description: |
   storage device.
 
 properties:
-  $nodename:
-pattern: "^(eeprom|efuse|nvram)(@.*|-[0-9a-f])*$"
-
   "#address-cells":
 const: 1
 
-- 
2.30.0



[PATCH v6 1/3] mtd: core: add nvmem-cells compatible to parse mtd as nvmem cells

2021-03-11 Thread Ansuel Smith
Partitions that contains the nvmem-cells compatible will register
their direct subonodes as nvmem cells and the node will be treated as a
nvmem provider.

Signed-off-by: Ansuel Smith 
---
 drivers/mtd/mtdcore.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index 2d6423d89a17..ac1b4f176a17 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -531,6 +531,7 @@ static int mtd_nvmem_reg_read(void *priv, unsigned int 
offset,
 
 static int mtd_nvmem_add(struct mtd_info *mtd)
 {
+   struct device_node *node = mtd_get_of_node(mtd);
struct nvmem_config config = {};
 
config.id = -1;
@@ -543,7 +544,7 @@ static int mtd_nvmem_add(struct mtd_info *mtd)
config.stride = 1;
config.read_only = true;
config.root_only = true;
-   config.no_of_node = true;
+   config.no_of_node = !of_device_is_compatible(node, "nvmem-cells");
config.priv = mtd;
 
mtd->nvmem = nvmem_register();
-- 
2.30.0



Re: [PATCH v4 2/3] dt-bindings: mtd: Document use of nvmem-cells compatible

2021-03-11 Thread Ansuel Smith
On Thu, Mar 11, 2021 at 07:37:13AM +0100, Rafał Miłecki wrote:
> On 10.03.2021 23:47, Ansuel Smith wrote:
> > On Wed, Mar 10, 2021 at 11:41:24PM +0100, Rafał Miłecki wrote:
> > > See inline
> > > 
> > > On 10.03.2021 22:08, Ansuel Smith wrote:
> > > > Document nvmem-cells compatible used to treat mtd partitions as a
> > > > nvmem provider.
> > > > 
> > > > Signed-off-by: Ansuel Smith 
> > > > ---
> > > >.../bindings/mtd/partitions/nvmem-cells.yaml  | 96 
> > > > +++
> > > >1 file changed, 96 insertions(+)
> > > >create mode 100644 
> > > > Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml
> > > > 
> > > > diff --git 
> > > > a/Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml 
> > > > b/Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml
> > > > new file mode 100644
> > > > index ..f70d7597a6b0
> > > > --- /dev/null
> > > > +++ b/Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml
> > > > @@ -0,0 +1,96 @@
> > > > +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
> > > > +%YAML 1.2
> > > > +---
> > > > +$id: http://devicetree.org/schemas/mtd/partitions/nvmem-cells.yaml#
> > > > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > > > +
> > > > +title: Nvmem cells
> > > > +
> > > > +description: |
> > > > +  Any partition containing the compatible "nvmem-cells" will register 
> > > > as a
> > > > +  nvmem provider.
> > > > +  Each direct subnodes represents a nvmem cell following the nvmem 
> > > > binding.
> > > > +  Nvmem binding to declare nvmem-cells can be found in:
> > > > +  Documentation/devicetree/bindings/nvmem/nvmem.yaml
> > > > +
> > > > +maintainers:
> > > > +  - Ansuel Smith 
> > > 
> > > I think that when Rob wrote:
> > > 
> > > On 10.03.2021 03:58, Rob Herring wrote:
> > > > I think this should reference nvmem.yaml.
> > > 
> > > he meant you using:
> > > 
> > > allOf:
> > >- $ref: "nvmem.yaml#"
> > > 
> > > (you'll need to adjust binding path).
> > > 
> > > Please check how it's done in 
> > > Documentation/devicetree/bindings/nvmem/*.yaml files
> > > 
> > > 
> > 
> > Aside from that, should I readd the old properties or I can keep the
> > compatible as the only one required?
> 
> What old properties do you mean?
> 
> You shouldn't need to add anything to the list of "required" I think.
> 
> Some NVMEM providers add "#address-cells" and "#size-cells". That makes
> sense if NVMEM provider must provide at least 1 cell. I'm not sure if we
> need that for MTD.
> 
> Even "compatible" is actually redundant but most YAML files list it for
> convenience. Source:
>

Thanks for the clarification, I sent the new version hoping the yaml
documentation is now correct.

> On 10.12.2020 03:48, Rob Herring wrote:
> > And drop 'compatible' as required. It's redundant anyways because the
> > schema will only be applied if compatible matches.
> 
> http://lists.infradead.org/pipermail/linux-mtd/2020-December/084574.html
> https://patchwork.ozlabs.org/comment/2597326/


[PATCH v5 3/3] devicetree: nvmem: nvmem: drop $nodename restriction

2021-03-11 Thread Ansuel Smith
Drop $nodename restriction as now mtd partition can also be used as
nvmem provider.

Signed-off-by: Ansuel Smith 
---
 Documentation/devicetree/bindings/nvmem/nvmem.yaml | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/nvmem/nvmem.yaml 
b/Documentation/devicetree/bindings/nvmem/nvmem.yaml
index 7481a9e48f19..b8dc3d2b6e92 100644
--- a/Documentation/devicetree/bindings/nvmem/nvmem.yaml
+++ b/Documentation/devicetree/bindings/nvmem/nvmem.yaml
@@ -20,9 +20,6 @@ description: |
   storage device.
 
 properties:
-  $nodename:
-pattern: "^(eeprom|efuse|nvram)(@.*|-[0-9a-f])*$"
-
   "#address-cells":
 const: 1
 
-- 
2.30.0



[PATCH v5 2/3] dt-bindings: mtd: Document use of nvmem-cells compatible

2021-03-11 Thread Ansuel Smith
Document nvmem-cells compatible used to treat mtd partitions as a
nvmem provider.

Signed-off-by: Ansuel Smith 
---
 .../bindings/mtd/partitions/nvmem-cells.yaml  | 99 +++
 1 file changed, 99 insertions(+)
 create mode 100644 
Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml

diff --git a/Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml 
b/Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml
new file mode 100644
index ..b53faf87d4e4
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml
@@ -0,0 +1,99 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mtd/partitions/nvmem-cells.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Nvmem cells
+
+description: |
+  Any partition containing the compatible "nvmem-cells" will register as a
+  nvmem provider.
+  Each direct subnodes represents a nvmem cell following the nvmem binding.
+  Nvmem binding to declare nvmem-cells can be found in:
+  Documentation/devicetree/bindings/nvmem/nvmem.yaml
+
+maintainers:
+  - Ansuel Smith 
+
+allOf:
+  - $ref: "../../nvmem/nvmem.yaml#"
+
+properties:
+  compatible:
+const: nvmem-cells
+
+required:
+  - compatible
+
+additionalProperties: true
+
+examples:
+  - |
+partitions {
+  compatible = "fixed-partitions";
+  #address-cells = <1>;
+  #size-cells = <1>;
+
+  /* ... */
+
+  };
+  art: art@120 {
+compatible = "nvmem-cells";
+reg = <0x120 0x014>;
+label = "art";
+read-only;
+#address-cells = <1>;
+#size-cells = <1>;
+
+macaddr_gmac1: macaddr_gmac1@0 {
+  reg = <0x0 0x6>;
+};
+
+macaddr_gmac2: macaddr_gmac2@6 {
+  reg = <0x6 0x6>;
+};
+
+pre_cal_24g: pre_cal_24g@1000 {
+  reg = <0x1000 0x2f20>;
+};
+
+pre_cal_5g: pre_cal_5g@5000{
+  reg = <0x5000 0x2f20>;
+};
+  };
+  - |
+partitions {
+compatible = "fixed-partitions";
+#address-cells = <1>;
+#size-cells = <1>;
+
+partition@0 {
+label = "bootloader";
+reg = <0x00 0x10>;
+read-only;
+};
+
+firmware@10 {
+compatible = "brcm,trx";
+label = "firmware";
+reg = <0x10 0xe0>;
+};
+
+calibration@f0 {
+compatible = "nvmem-cells";
+label = "calibration";
+reg = <0xf0 0x10>;
+ranges = <0 0xf0 0x10>;
+#address-cells = <1>;
+#size-cells = <1>;
+
+wifi0@0 {
+reg = <0x00 0x08>;
+};
+
+wifi1@8 {
+reg = <0x08 0x08>;
+};
+};
+};
-- 
2.30.0



[PATCH v5 1/3] mtd: core: add nvmem-cells compatible to parse mtd as nvmem cells

2021-03-11 Thread Ansuel Smith
Partitions that contains the nvmem-cells compatible will register
their direct subonodes as nvmem cells and the node will be treated as a
nvmem provider.

Signed-off-by: Ansuel Smith 
---
 drivers/mtd/mtdcore.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index 2d6423d89a17..ac1b4f176a17 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -531,6 +531,7 @@ static int mtd_nvmem_reg_read(void *priv, unsigned int 
offset,
 
 static int mtd_nvmem_add(struct mtd_info *mtd)
 {
+   struct device_node *node = mtd_get_of_node(mtd);
struct nvmem_config config = {};
 
config.id = -1;
@@ -543,7 +544,7 @@ static int mtd_nvmem_add(struct mtd_info *mtd)
config.stride = 1;
config.read_only = true;
config.root_only = true;
-   config.no_of_node = true;
+   config.no_of_node = !of_device_is_compatible(node, "nvmem-cells");
config.priv = mtd;
 
mtd->nvmem = nvmem_register();
-- 
2.30.0



Re: [PATCH v4 2/3] dt-bindings: mtd: Document use of nvmem-cells compatible

2021-03-10 Thread Ansuel Smith
On Wed, Mar 10, 2021 at 11:41:24PM +0100, Rafał Miłecki wrote:
> See inline
> 
> On 10.03.2021 22:08, Ansuel Smith wrote:
> > Document nvmem-cells compatible used to treat mtd partitions as a
> > nvmem provider.
> > 
> > Signed-off-by: Ansuel Smith 
> > ---
> >   .../bindings/mtd/partitions/nvmem-cells.yaml  | 96 +++
> >   1 file changed, 96 insertions(+)
> >   create mode 100644 
> > Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml
> > 
> > diff --git 
> > a/Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml 
> > b/Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml
> > new file mode 100644
> > index ..f70d7597a6b0
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml
> > @@ -0,0 +1,96 @@
> > +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/mtd/partitions/nvmem-cells.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: Nvmem cells
> > +
> > +description: |
> > +  Any partition containing the compatible "nvmem-cells" will register as a
> > +  nvmem provider.
> > +  Each direct subnodes represents a nvmem cell following the nvmem binding.
> > +  Nvmem binding to declare nvmem-cells can be found in:
> > +  Documentation/devicetree/bindings/nvmem/nvmem.yaml
> > +
> > +maintainers:
> > +  - Ansuel Smith 
> 
> I think that when Rob wrote:
> 
> On 10.03.2021 03:58, Rob Herring wrote:
> > I think this should reference nvmem.yaml.
> 
> he meant you using:
> 
> allOf:
>   - $ref: "nvmem.yaml#"
> 
> (you'll need to adjust binding path).
> 
> Please check how it's done in Documentation/devicetree/bindings/nvmem/*.yaml 
> files
> 
>

Aside from that, should I readd the old properties or I can keep the
compatible as the only one required?

Thanks for the suggestion.

> > +properties:
> > +  compatible:
> > +const: nvmem-cells


[PATCH v4 3/3] devicetree: nvmem: nvmem: drop $nodename restriction

2021-03-10 Thread Ansuel Smith
Drop $nodename restriction as now mtd partition can also be used as
nvmem provider.

Signed-off-by: Ansuel Smith 
---
 Documentation/devicetree/bindings/nvmem/nvmem.yaml | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/nvmem/nvmem.yaml 
b/Documentation/devicetree/bindings/nvmem/nvmem.yaml
index 7481a9e48f19..b8dc3d2b6e92 100644
--- a/Documentation/devicetree/bindings/nvmem/nvmem.yaml
+++ b/Documentation/devicetree/bindings/nvmem/nvmem.yaml
@@ -20,9 +20,6 @@ description: |
   storage device.
 
 properties:
-  $nodename:
-pattern: "^(eeprom|efuse|nvram)(@.*|-[0-9a-f])*$"
-
   "#address-cells":
 const: 1
 
-- 
2.30.0



[PATCH v4 1/3] mtd: core: add nvmem-cells compatible to parse mtd as nvmem cells

2021-03-10 Thread Ansuel Smith
Partitions that contains the nvmem-cells compatible will register
their direct subonodes as nvmem cells and the node will be treated as a
nvmem provider.

Signed-off-by: Ansuel Smith 
---
 drivers/mtd/mtdcore.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index 2d6423d89a17..ac1b4f176a17 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -531,6 +531,7 @@ static int mtd_nvmem_reg_read(void *priv, unsigned int 
offset,
 
 static int mtd_nvmem_add(struct mtd_info *mtd)
 {
+   struct device_node *node = mtd_get_of_node(mtd);
struct nvmem_config config = {};
 
config.id = -1;
@@ -543,7 +544,7 @@ static int mtd_nvmem_add(struct mtd_info *mtd)
config.stride = 1;
config.read_only = true;
config.root_only = true;
-   config.no_of_node = true;
+   config.no_of_node = !of_device_is_compatible(node, "nvmem-cells");
config.priv = mtd;
 
mtd->nvmem = nvmem_register();
-- 
2.30.0



[PATCH v4 2/3] dt-bindings: mtd: Document use of nvmem-cells compatible

2021-03-10 Thread Ansuel Smith
Document nvmem-cells compatible used to treat mtd partitions as a
nvmem provider.

Signed-off-by: Ansuel Smith 
---
 .../bindings/mtd/partitions/nvmem-cells.yaml  | 96 +++
 1 file changed, 96 insertions(+)
 create mode 100644 
Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml

diff --git a/Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml 
b/Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml
new file mode 100644
index ..f70d7597a6b0
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml
@@ -0,0 +1,96 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mtd/partitions/nvmem-cells.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Nvmem cells
+
+description: |
+  Any partition containing the compatible "nvmem-cells" will register as a
+  nvmem provider.
+  Each direct subnodes represents a nvmem cell following the nvmem binding.
+  Nvmem binding to declare nvmem-cells can be found in:
+  Documentation/devicetree/bindings/nvmem/nvmem.yaml
+
+maintainers:
+  - Ansuel Smith 
+
+properties:
+  compatible:
+const: nvmem-cells
+
+required:
+  - compatible
+
+additionalProperties: true
+
+examples:
+  - |
+partitions {
+  compatible = "fixed-partitions";
+  #address-cells = <1>;
+  #size-cells = <1>;
+
+  /* ... */
+
+  };
+  art: art@120 {
+compatible = "nvmem-cells";
+reg = <0x120 0x014>;
+label = "art";
+read-only;
+#address-cells = <1>;
+#size-cells = <1>;
+
+macaddr_gmac1: macaddr_gmac1@0 {
+  reg = <0x0 0x6>;
+};
+
+macaddr_gmac2: macaddr_gmac2@6 {
+  reg = <0x6 0x6>;
+};
+
+pre_cal_24g: pre_cal_24g@1000 {
+  reg = <0x1000 0x2f20>;
+};
+
+pre_cal_5g: pre_cal_5g@5000{
+  reg = <0x5000 0x2f20>;
+};
+  };
+  - |
+partitions {
+compatible = "fixed-partitions";
+#address-cells = <1>;
+#size-cells = <1>;
+
+partition@0 {
+label = "bootloader";
+reg = <0x00 0x10>;
+read-only;
+};
+
+firmware@10 {
+compatible = "brcm,trx";
+label = "firmware";
+reg = <0x10 0xe0>;
+};
+
+calibration@f0 {
+compatible = "nvmem-cells";
+label = "calibration";
+reg = <0xf0 0x10>;
+ranges = <0 0xf0 0x10>;
+#address-cells = <1>;
+#size-cells = <1>;
+
+wifi0@0 {
+reg = <0x00 0x08>;
+};
+
+wifi1@8 {
+reg = <0x08 0x08>;
+};
+};
+};
-- 
2.30.0



[PATCH v3 2/2] dt-bindings: mtd: Document use of nvmem-cells compatible

2021-03-08 Thread Ansuel Smith
Document nvmem-cells compatible used to treat mtd partitions as a
nvmem provider.

Signed-off-by: Ansuel Smith 
---
 .../bindings/mtd/partitions/nvmem-cells.yaml  | 105 ++
 1 file changed, 105 insertions(+)
 create mode 100644 
Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml

diff --git a/Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml 
b/Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml
new file mode 100644
index ..4ed246b27985
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/partitions/nvmem-cells.yaml
@@ -0,0 +1,105 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mtd/partitions/nvmem-cells.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Nvmem cells
+
+description: |
+  This binding can be used to treat the specific partition as a nvmem provider.
+  Each direct subnodes represents the nvmem cells and won't be parsed as 
fixed-partitions.
+  Fixed-partitions bindings described in fixed-partitions.yaml apply to the 
nvmem provider node.
+
+maintainers:
+  - Ansuel Smith 
+
+properties:
+  compatible:
+const: nvmem-cells
+
+  "#address-cells": true
+
+  "#size-cells": true
+
+  reg:
+description: partition offset and size within the flash
+maxItems: 1
+
+required:
+  - compatible
+  - "#address-cells"
+  - "#size-cells"
+  - reg
+
+additionalProperties: true
+
+examples:
+  - |
+partitions {
+  compatible = "fixed-partitions";
+  #address-cells = <1>;
+  #size-cells = <1>;
+
+  /* ... */
+
+  };
+  art: art@120 {
+compatible = "nvmem-cells";
+reg = <0x120 0x014>;
+label = "art";
+read-only;
+#address-cells = <1>;
+#size-cells = <1>;
+
+macaddr_gmac1: macaddr_gmac1@0 {
+  reg = <0x0 0x6>;
+};
+
+macaddr_gmac2: macaddr_gmac2@6 {
+  reg = <0x6 0x6>;
+};
+
+pre_cal_24g: pre_cal_24g@1000 {
+  reg = <0x1000 0x2f20>;
+};
+
+pre_cal_5g: pre_cal_5g@5000{
+  reg = <0x5000 0x2f20>;
+};
+  };
+  - |
+partitions {
+compatible = "fixed-partitions";
+#address-cells = <1>;
+#size-cells = <1>;
+
+partition@0 {
+label = "bootloader";
+reg = <0x00 0x10>;
+read-only;
+};
+
+firmware@10 {
+compatible = "brcm,trx";
+label = "firmware";
+reg = <0x10 0xe0>;
+};
+
+calibration@f0 {
+compatible = "nvmem-cells";
+label = "calibration";
+reg = <0xf0 0x10>;
+ranges = <0 0xf0 0x10>;
+#address-cells = <1>;
+#size-cells = <1>;
+
+wifi0@0 {
+reg = <0x00 0x08>;
+};
+
+wifi1@8 {
+reg = <0x08 0x08>;
+};
+};
+};
-- 
2.30.0



[PATCH v3 1/2] mtd: core: add nvmem-cells compatible to parse mtd as nvmem cells

2021-03-08 Thread Ansuel Smith
Partitions that contains the nvmem-cells compatible will register
their direct subonodes as nvmem cells and the node will be treated as a
nvmem provider.

Signed-off-by: Ansuel Smith 
---
Depends on [PATCH] mtd: parsers: ofpart: limit parsing of deprecated DT syntax
---
 drivers/mtd/mtdcore.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index 2d6423d89a17..ac1b4f176a17 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -531,6 +531,7 @@ static int mtd_nvmem_reg_read(void *priv, unsigned int 
offset,
 
 static int mtd_nvmem_add(struct mtd_info *mtd)
 {
+   struct device_node *node = mtd_get_of_node(mtd);
struct nvmem_config config = {};
 
config.id = -1;
@@ -543,7 +544,7 @@ static int mtd_nvmem_add(struct mtd_info *mtd)
config.stride = 1;
config.read_only = true;
config.root_only = true;
-   config.no_of_node = true;
+   config.no_of_node = !of_device_is_compatible(node, "nvmem-cells");
config.priv = mtd;
 
mtd->nvmem = nvmem_register();
-- 
2.30.0



Re: [PATCH v2 3/3] dt-bindings: mtd: Document use of nvmem-partitions compatible

2021-03-08 Thread Ansuel Smith
On Mon, Mar 08, 2021 at 10:48:32AM +0100, Rafał Miłecki wrote:
> On 16.02.2021 22:26, Ansuel Smith wrote:
> > Document nvmem-partitions compatible used to treat mtd partitions as a
> > nvmem provider.
> 
> I'm just wondering if "nvmem-partitions" is accurate enough. Partitions
> bit sounds a bit ambiguous in the mtd context.
> 
> What do you think about "mtd-nvmem-cells" or just "nvmem-cells"?

I read somewhere that mtd is not so standard so "nvmem-cells" should be the
right compatible.
To sum up, with v2 I should change the compatible name and just push the
2 and 3 patch. (waiting your fix to be accepted) Correct?



Re: [PATCH v2 1/3] mtd: partitions: ofpart: skip subnodes parse with compatible

2021-03-03 Thread Ansuel Smith
On Tue, Mar 02, 2021 at 05:53:54PM +0100, Rafał Miłecki wrote:
> On 16.02.2021 22:26, Ansuel Smith wrote:
> > If a partitions structure is not used, parse direct subnodes as
> > fixed-partitions only if a compatible is not found or is of type
> > fixed-partition. A parser can be used directly on the subnode and
> > subnodes should not be parsed as fixed-partitions by default.
> > 
> > Signed-off-by: Ansuel Smith 
> > ---
> >   drivers/mtd/parsers/ofpart.c | 5 +
> >   1 file changed, 5 insertions(+)
> > 
> > diff --git a/drivers/mtd/parsers/ofpart.c b/drivers/mtd/parsers/ofpart.c
> > index daf507c123e6..4b363dd0311c 100644
> > --- a/drivers/mtd/parsers/ofpart.c
> > +++ b/drivers/mtd/parsers/ofpart.c
> > @@ -50,6 +50,11 @@ static int parse_fixed_partitions(struct mtd_info 
> > *master,
> >  master->name, mtd_node);
> > ofpart_node = mtd_node;
> > dedicated = false;
> > +
> > +   /* Skip parsing direct subnodes if a compatible is found and is 
> > not fixed-partitions */
> > +   if (node_has_compatible(ofpart_node) &&
> > +   !of_device_is_compatible(ofpart_node, "fixed-partitions"))
> > +   return 0;
> > } else if (!of_device_is_compatible(ofpart_node, "fixed-partitions")) {
> > /* The 'partitions' subnode might be used by another parser */
> > return 0;
> 
> I admit I'm not familiar with the old binding, so let me know if my
> understanding is incorrect.
> 
> It seems to me however that your change will break parsing in cases
> like:
> 
> spi-flash@0 {
>   compatible = "jedec,spi-nor";
>   reg = <0x0>;
> 
>   partition@0 {
>   label = "bootloader";
>   reg = <0x0 0x10>;
>   };
> };
> 
> nandcs@0 {
>   compatible = "brcm,nandcs";
>   reg = <0>;
> 
>   partition@0 {
>   label = "bootloader";
>   reg = <0x000 0x1>;
>   };
> };
> 
> Did we ever use "fixed-partitions" without partitions { } subnode?

Hi, very good point. You are right and I didin't think about this case.
I don't want to assume false statement, but since the ofpart parser and
the partitions structure should have been pushed at the same time, there
shouldn't be any use of "fixed-partitions" without partitions { }
subnodes. With this assumtion, the current implementation looks to be the 
cleanest way to skip parsing. (if the parsing is dubious, don't parse at
all... The idea was that)
The hacky and IMHO dirty way to solve this is add a bool to directly
skip the subnode parsing and check for that. Something like
"no-fixed-partition" that would disable the ofnode parser with no
partitions { } subnode would accomplish the same result of this patch
and keep compatibility with nodes scheme you pointed out.



[PATCH] arm: Enlarge IO_SPACE_LIMIT needed for some SoC

2021-02-28 Thread Ansuel Smith
Ipq8064 SoC requires larger IO_SPACE_LIMIT or second and third pci port
fails to register the IO addresses and connected device doesn't work.

Cc:  # 4.9+
Signed-off-by: Ansuel Smith 
---
 arch/arm/include/asm/io.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h
index fc748122f1e0..6f3e89f08bd8 100644
--- a/arch/arm/include/asm/io.h
+++ b/arch/arm/include/asm/io.h
@@ -197,7 +197,7 @@ void __iomem *pci_remap_cfgspace(resource_size_t 
res_cookie, size_t size);
 #ifdef CONFIG_NEED_MACH_IO_H
 #include 
 #elif defined(CONFIG_PCI)
-#define IO_SPACE_LIMIT ((resource_size_t)0xf)
+#define IO_SPACE_LIMIT ((resource_size_t)0xff)
 #define __io(a)__typesafe_io(PCI_IO_VIRT_BASE + ((a) & 
IO_SPACE_LIMIT))
 #else
 #define __io(a)__typesafe_io((a) & IO_SPACE_LIMIT)
-- 
2.30.0



[PATCH v10 6/8] drivers: thermal: tsens: Use get_temp_common for msm8960

2021-02-17 Thread Ansuel Smith
Rework calibrate function to use common function. Derive the offset from
a missing hardcoded slope table and the data from the nvmem calib
efuses.

Signed-off-by: Ansuel Smith 
---
 drivers/thermal/qcom/tsens-8960.c | 56 +--
 1 file changed, 15 insertions(+), 41 deletions(-)

diff --git a/drivers/thermal/qcom/tsens-8960.c 
b/drivers/thermal/qcom/tsens-8960.c
index 248aaa65b5b0..43ebe4d54672 100644
--- a/drivers/thermal/qcom/tsens-8960.c
+++ b/drivers/thermal/qcom/tsens-8960.c
@@ -67,6 +67,13 @@
 #define S9_STATUS_OFF  0x3674
 #define S10_STATUS_OFF 0x3678
 
+/* Original slope - 200 to compensate mC to C inaccuracy */
+u32 tsens_msm8960_slope[] = {
+   976, 976, 954, 976,
+   911, 932, 932, 999,
+   932, 999, 932
+   };
+
 static int suspend_8960(struct tsens_priv *priv)
 {
int ret;
@@ -192,9 +199,7 @@ static int calibrate_8960(struct tsens_priv *priv)
 {
int i;
char *data;
-
-   ssize_t num_read = priv->num_sensors;
-   struct tsens_sensor *s = priv->sensor;
+   u32 p1[11];
 
data = qfprom_read(priv->dev, "calib");
if (IS_ERR(data))
@@ -202,49 +207,18 @@ static int calibrate_8960(struct tsens_priv *priv)
if (IS_ERR(data))
return PTR_ERR(data);
 
-   for (i = 0; i < num_read; i++, s++)
-   s->offset = data[i];
+   for (i = 0; i < priv->num_sensors; i++) {
+   p1[i] = data[i];
+   priv->sensor[i].slope = tsens_msm8960_slope[i];
+   }
+
+   compute_intercept_slope(priv, p1, NULL, ONE_PT_CALIB);
 
kfree(data);
 
return 0;
 }
 
-/* Temperature on y axis and ADC-code on x-axis */
-static inline int code_to_mdegC(u32 adc_code, const struct tsens_sensor *s)
-{
-   int slope, offset;
-
-   slope = thermal_zone_get_slope(s->tzd);
-   offset = CAL_MDEGC - slope * s->offset;
-
-   return adc_code * slope + offset;
-}
-
-static int get_temp_8960(const struct tsens_sensor *s, int *temp)
-{
-   int ret;
-   u32 code, trdy;
-   struct tsens_priv *priv = s->priv;
-   unsigned long timeout;
-
-   timeout = jiffies + usecs_to_jiffies(TIMEOUT_US);
-   do {
-   ret = regmap_read(priv->tm_map, INT_STATUS_ADDR, );
-   if (ret)
-   return ret;
-   if (!(trdy & TRDY_MASK))
-   continue;
-   ret = regmap_read(priv->tm_map, s->status, );
-   if (ret)
-   return ret;
-   *temp = code_to_mdegC(code, s);
-   return 0;
-   } while (time_before(jiffies, timeout));
-
-   return -ETIMEDOUT;
-}
-
 static struct tsens_features tsens_8960_feat = {
.ver_major  = VER_0,
.crit_int   = 0,
@@ -313,7 +287,7 @@ static const struct reg_field 
tsens_8960_regfields[MAX_REGFIELDS] = {
 static const struct tsens_ops ops_8960 = {
.init   = init_common,
.calibrate  = calibrate_8960,
-   .get_temp   = get_temp_8960,
+   .get_temp   = get_temp_common,
.enable = enable_8960,
.disable= disable_8960,
.suspend= suspend_8960,
-- 
2.30.0



[PATCH v10 5/8] drivers: thermal: tsens: Fix bug in sensor enable for msm8960

2021-02-17 Thread Ansuel Smith
It's present a hardware bug in tsens VER_0 where if sensors upper to id
6 are enabled selectively, underfined results are expected. Fix this by
enabling all the remaining sensor in one step.

Signed-off-by: Ansuel Smith 
---
 drivers/thermal/qcom/tsens-8960.c | 19 +--
 1 file changed, 17 insertions(+), 2 deletions(-)

diff --git a/drivers/thermal/qcom/tsens-8960.c 
b/drivers/thermal/qcom/tsens-8960.c
index 86585f439985..248aaa65b5b0 100644
--- a/drivers/thermal/qcom/tsens-8960.c
+++ b/drivers/thermal/qcom/tsens-8960.c
@@ -27,9 +27,9 @@
 #define EN BIT(0)
 #define SW_RST BIT(1)
 #define SENSOR0_EN BIT(3)
+#define MEASURE_PERIOD BIT(18)
 #define SLP_CLK_ENABIT(26)
 #define SLP_CLK_ENA_8660   BIT(24)
-#define MEASURE_PERIOD 1
 #define SENSOR0_SHIFT  3
 
 /* INT_STATUS_ADDR bitmasks */
@@ -132,11 +132,26 @@ static int enable_8960(struct tsens_priv *priv, int id)
if (ret)
return ret;
 
-   mask = BIT(id + SENSOR0_SHIFT);
+   /* HARDWARE BUG:
+* On platform with more than 5 sensors, all the remaining
+* sensors needs to be enabled all togheder or underfined
+* results are expected. (Sensor 6-7 disabled, Sensor 3
+* disabled...) In the original driver, all the sensors
+* are enabled in one step hence this bug is not triggered.
+*/
+   if (id > 5)
+   mask = GENMASK(10, 6);
+   else
+   mask = BIT(id);
+
+   mask <<= SENSOR0_SHIFT;
+
ret = regmap_write(priv->tm_map, CNTL_ADDR, reg | SW_RST);
if (ret)
return ret;
 
+   reg |= MEASURE_PERIOD;
+
if (priv->num_sensors > 1)
reg |= mask | SLP_CLK_ENA | EN;
else
-- 
2.30.0



[PATCH v10 8/8] dt-bindings: thermal: tsens: Document ipq8064 bindings

2021-02-17 Thread Ansuel Smith
Document the use of bindings used for msm8960 tsens based devices.
msm8960 use the same gcc regs and is set as a child of the qcom gcc.

Signed-off-by: Ansuel Smith 
---
 .../bindings/thermal/qcom-tsens.yaml  | 56 ---
 1 file changed, 48 insertions(+), 8 deletions(-)

diff --git a/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml 
b/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml
index 95462e071ab4..1785b1c75a3c 100644
--- a/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml
+++ b/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml
@@ -19,6 +19,11 @@ description: |
 properties:
   compatible:
 oneOf:
+  - description: msm9860 TSENS based
+items:
+  - enum:
+  - qcom,ipq8064-tsens
+
   - description: v0.1 of TSENS
 items:
   - enum:
@@ -73,7 +78,9 @@ properties:
 maxItems: 2
 items:
   - const: calib
-  - const: calib_sel
+  - enum:
+  - calib_backup
+  - calib_sel
 
   "#qcom,sensors":
 description:
@@ -88,12 +95,20 @@ properties:
   Number of cells required to uniquely identify the thermal sensors. Since
   we have multiple sensors this is set to 1
 
+required:
+  - compatible
+  - interrupts
+  - interrupt-names
+  - "#thermal-sensor-cells"
+  - "#qcom,sensors"
+
 allOf:
   - if:
   properties:
 compatible:
   contains:
 enum:
+  - qcom,ipq8064-tsens
   - qcom,msm8916-tsens
   - qcom,msm8974-tsens
   - qcom,msm8976-tsens
@@ -114,17 +129,42 @@ allOf:
 interrupt-names:
   minItems: 2
 
-required:
-  - compatible
-  - reg
-  - "#qcom,sensors"
-  - interrupts
-  - interrupt-names
-  - "#thermal-sensor-cells"
+  - if:
+  properties:
+compatible:
+  contains:
+enum:
+  - qcom,tsens-v0_1
+  - qcom,tsens-v1
+  - qcom,tsens-v2
+
+then:
+  required:
+- reg
 
 additionalProperties: false
 
 examples:
+  - |
+#include 
+// Example msm9860 based SoC (ipq8064):
+gcc: clock-controller {
+
+   /* ... */
+
+   tsens: thermal-sensor {
+compatible = "qcom,ipq8064-tsens";
+
+ nvmem-cells = <_calib>, <_calib_backup>;
+ nvmem-cell-names = "calib", "calib_backup";
+ interrupts = ;
+ interrupt-names = "uplow";
+
+ #qcom,sensors = <11>;
+ #thermal-sensor-cells = <1>;
+  };
+};
+
   - |
 #include 
 // Example 1 (legacy: for pre v1 IP):
-- 
2.30.0



[PATCH v10 7/8] drivers: thermal: tsens: Add support for ipq8064-tsens

2021-02-17 Thread Ansuel Smith
Add support for tsens present in ipq806x SoCs based on generic msm8960
tsens driver.

Signed-off-by: Ansuel Smith 
---
 drivers/thermal/qcom/tsens.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
index 842f518fdf84..e14b90ddd0f9 100644
--- a/drivers/thermal/qcom/tsens.c
+++ b/drivers/thermal/qcom/tsens.c
@@ -1001,6 +1001,9 @@ static SIMPLE_DEV_PM_OPS(tsens_pm_ops, tsens_suspend, 
tsens_resume);
 
 static const struct of_device_id tsens_table[] = {
{
+   .compatible = "qcom,ipq8064-tsens",
+   .data = _8960,
+   }, {
.compatible = "qcom,msm8916-tsens",
.data = _8916,
}, {
-- 
2.30.0



[PATCH v10 2/8] drivers: thermal: tsens: Don't hardcode sensor slope

2021-02-17 Thread Ansuel Smith
Function compute_intercept_slope hardcode the sensor slope to
SLOPE_DEFAULT. Change this and use the default value only if a slope is
not defined. This is needed for tsens VER_0 that has a hardcoded slope
table.

Signed-off-by: Ansuel Smith 
---
 drivers/thermal/qcom/tsens.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
index f9126909892b..842f518fdf84 100644
--- a/drivers/thermal/qcom/tsens.c
+++ b/drivers/thermal/qcom/tsens.c
@@ -86,7 +86,8 @@ void compute_intercept_slope(struct tsens_priv *priv, u32 *p1,
"%s: sensor%d - data_point1:%#x data_point2:%#x\n",
__func__, i, p1[i], p2[i]);
 
-   priv->sensor[i].slope = SLOPE_DEFAULT;
+   if (!priv->sensor[i].slope)
+   priv->sensor[i].slope = SLOPE_DEFAULT;
if (mode == TWO_PT_CALIB) {
/*
 * slope (m) = adc_code2 - adc_code1 (y2 - y1)/
-- 
2.30.0



[PATCH v10 1/8] drivers: thermal: tsens: Add VER_0 tsens version

2021-02-17 Thread Ansuel Smith
VER_0 is used to describe device based on tsens version before v0.1.
These device are devices based on msm8960 for example apq8064 or
ipq806x.

Signed-off-by: Ansuel Smith 
---
 drivers/thermal/qcom/tsens.c | 175 +--
 drivers/thermal/qcom/tsens.h |   4 +-
 2 files changed, 151 insertions(+), 28 deletions(-)

diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
index d8ce3a687b80..f9126909892b 100644
--- a/drivers/thermal/qcom/tsens.c
+++ b/drivers/thermal/qcom/tsens.c
@@ -12,6 +12,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -515,6 +516,15 @@ static irqreturn_t tsens_irq_thread(int irq, void *data)
dev_dbg(priv->dev, "[%u] %s: no violation:  %d\n",
hw_id, __func__, temp);
}
+
+   if (tsens_version(priv) < VER_0_1) {
+   /* Constraint: There is only 1 interrupt control 
register for all
+* 11 temperature sensor. So monitoring more than 1 
sensor based
+* on interrupts will yield inconsistent result. To 
overcome this
+* issue we will monitor only sensor 0 which is the 
master sensor.
+*/
+   break;
+   }
}
 
return IRQ_HANDLED;
@@ -530,6 +540,13 @@ static int tsens_set_trips(void *_sensor, int low, int 
high)
int high_val, low_val, cl_high, cl_low;
u32 hw_id = s->hw_id;
 
+   if (tsens_version(priv) < VER_0_1) {
+   /* Pre v0.1 IP had a single register for each type of interrupt
+* and thresholds
+*/
+   hw_id = 0;
+   }
+
dev_dbg(dev, "[%u] %s: proposed thresholds: (%d:%d)\n",
hw_id, __func__, low, high);
 
@@ -584,18 +601,21 @@ int get_temp_tsens_valid(const struct tsens_sensor *s, 
int *temp)
u32 valid;
int ret;
 
-   ret = regmap_field_read(priv->rf[valid_idx], );
-   if (ret)
-   return ret;
-   while (!valid) {
-   /* Valid bit is 0 for 6 AHB clock cycles.
-* At 19.2MHz, 1 AHB clock is ~60ns.
-* We should enter this loop very, very rarely.
-*/
-   ndelay(400);
+   /* VER_0 doesn't have VALID bit */
+   if (tsens_version(priv) >= VER_0_1) {
ret = regmap_field_read(priv->rf[valid_idx], );
if (ret)
return ret;
+   while (!valid) {
+   /* Valid bit is 0 for 6 AHB clock cycles.
+* At 19.2MHz, 1 AHB clock is ~60ns.
+* We should enter this loop very, very rarely.
+*/
+   ndelay(400);
+   ret = regmap_field_read(priv->rf[valid_idx], );
+   if (ret)
+   return ret;
+   }
}
 
/* Valid bit is set, OK to read the temperature */
@@ -608,15 +628,29 @@ int get_temp_common(const struct tsens_sensor *s, int 
*temp)
 {
struct tsens_priv *priv = s->priv;
int hw_id = s->hw_id;
-   int last_temp = 0, ret;
+   int last_temp = 0, ret, trdy;
+   unsigned long timeout;
 
-   ret = regmap_field_read(priv->rf[LAST_TEMP_0 + hw_id], _temp);
-   if (ret)
-   return ret;
+   timeout = jiffies + usecs_to_jiffies(TIMEOUT_US);
+   do {
+   if (priv->rf[TRDY]) {
+   ret = regmap_field_read(priv->rf[TRDY], );
+   if (ret)
+   return ret;
+   if (!trdy)
+   continue;
+   }
+
+   ret = regmap_field_read(priv->rf[LAST_TEMP_0 + hw_id], 
_temp);
+   if (ret)
+   return ret;
 
-   *temp = code_to_degc(last_temp, s) * 1000;
+   *temp = code_to_degc(last_temp, s) * 1000;
 
-   return 0;
+   return 0;
+   } while (time_before(jiffies, timeout));
+
+   return -ETIMEDOUT;
 }
 
 #ifdef CONFIG_DEBUG_FS
@@ -738,19 +772,31 @@ int __init init_common(struct tsens_priv *priv)
priv->tm_offset = 0x1000;
}
 
-   res = platform_get_resource(op, IORESOURCE_MEM, 0);
-   tm_base = devm_ioremap_resource(dev, res);
-   if (IS_ERR(tm_base)) {
-   ret = PTR_ERR(tm_base);
-   goto err_put_device;
+   if (tsens_version(priv) >= VER_0_1) {
+   res = platform_get_resource(op, IORESOURCE_MEM, 0);
+   tm_base = devm_ioremap_resource(dev, res);
+   if (IS_ERR(tm_base)) {
+   ret = PTR_ERR(tm_base);
+   goto err_put_device;
+   }
+
+   priv->

[PATCH v10 0/8] Add support for ipq8064 tsens

2021-02-17 Thread Ansuel Smith
This patchset convert msm8960 to reg_filed, use int_common instead 
of a custom function and fix wrong tsens get_temp function for msm8960.
Ipq8064 SoCs tsens driver is based on 8960 tsens driver. Ipq8064 needs
to be registered as a gcc child as the tsens regs on this platform are
shared with the controller.
This is based on work and code here
https://git.linaro.org/people/amit.kucheria/kernel.git/log/?h=wrk3/tsens-8960-breakage

v10:
* Fix wrong tsens init for ver_0 (crit_trips needs to be set in tsens_register)
v9:
* Fix warning from Documentation bot
v8:
* Drop MIN and MAX THRESH and use CRIT_THRESH instead
* Fix broken documentation patch
v7:
* Rework calibrate function to use get_temp_common
* Fix wrong required in the Documentation for ipq8064
* Fix hardware bug in sensor enable function
v6:
* Fix spelling error (can't find the problem with variable misallignment)
* Rework big if-else
* Remove extra comments
* Add description about different interrupts
v5:
* Conver driver to use reg_fiedl
* Use init_common 
* Drop custom set_trip and set_interrupt
* Use common set_trip and set_interrupt
* Fix bad get_temp function
* Add missing hardcoded slope
v4:
* Fix compilation error and warning reported by the bot
v3:
* Change driver to register as child instead of use phandle
v2:
* Fix dt-bindings problems

Ansuel Smith (8):
  drivers: thermal: tsens: Add VER_0 tsens version
  drivers: thermal: tsens: Don't hardcode sensor slope
  drivers: thermal: tsens: Convert msm8960 to reg_field
  drivers: thermal: tsens: Use init_common for msm8960
  drivers: thermal: tsens: Fix bug in sensor enable for msm8960
  drivers: thermal: tsens: Use get_temp_common for msm8960
  drivers: thermal: tsens: Add support for ipq8064-tsens
  dt-bindings: thermal: tsens: Document ipq8064 bindings

 .../bindings/thermal/qcom-tsens.yaml  |  56 -
 drivers/thermal/qcom/tsens-8960.c | 203 ++
 drivers/thermal/qcom/tsens.c  | 181 +---
 drivers/thermal/qcom/tsens.h  |   4 +-
 4 files changed, 314 insertions(+), 130 deletions(-)

-- 
2.30.0



[PATCH v10 4/8] drivers: thermal: tsens: Use init_common for msm8960

2021-02-17 Thread Ansuel Smith
Use init_common and drop custom init for msm8960.

Signed-off-by: Ansuel Smith 
---
 drivers/thermal/qcom/tsens-8960.c | 52 +--
 1 file changed, 1 insertion(+), 51 deletions(-)

diff --git a/drivers/thermal/qcom/tsens-8960.c 
b/drivers/thermal/qcom/tsens-8960.c
index 3f4fc1ffe679..86585f439985 100644
--- a/drivers/thermal/qcom/tsens-8960.c
+++ b/drivers/thermal/qcom/tsens-8960.c
@@ -173,56 +173,6 @@ static void disable_8960(struct tsens_priv *priv)
regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
 }
 
-static int init_8960(struct tsens_priv *priv)
-{
-   int ret, i;
-   u32 reg_cntl;
-
-   priv->tm_map = dev_get_regmap(priv->dev, NULL);
-   if (!priv->tm_map)
-   return -ENODEV;
-
-   /*
-* The status registers for each sensor are discontiguous
-* because some SoCs have 5 sensors while others have more
-* but the control registers stay in the same place, i.e
-* directly after the first 5 status registers.
-*/
-   for (i = 0; i < priv->num_sensors; i++) {
-   if (i >= 5)
-   priv->sensor[i].status = S0_STATUS_ADDR + 40;
-   priv->sensor[i].status += i * 4;
-   }
-
-   reg_cntl = SW_RST;
-   ret = regmap_update_bits(priv->tm_map, CNTL_ADDR, SW_RST, reg_cntl);
-   if (ret)
-   return ret;
-
-   if (priv->num_sensors > 1) {
-   reg_cntl |= SLP_CLK_ENA | (MEASURE_PERIOD << 18);
-   reg_cntl &= ~SW_RST;
-   ret = regmap_update_bits(priv->tm_map, CONFIG_ADDR,
-CONFIG_MASK, CONFIG);
-   } else {
-   reg_cntl |= SLP_CLK_ENA_8660 | (MEASURE_PERIOD << 16);
-   reg_cntl &= ~CONFIG_MASK_8660;
-   reg_cntl |= CONFIG_8660 << CONFIG_SHIFT_8660;
-   }
-
-   reg_cntl |= GENMASK(priv->num_sensors - 1, 0) << SENSOR0_SHIFT;
-   ret = regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
-   if (ret)
-   return ret;
-
-   reg_cntl |= EN;
-   ret = regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
-   if (ret)
-   return ret;
-
-   return 0;
-}
-
 static int calibrate_8960(struct tsens_priv *priv)
 {
int i;
@@ -346,7 +296,7 @@ static const struct reg_field 
tsens_8960_regfields[MAX_REGFIELDS] = {
 };
 
 static const struct tsens_ops ops_8960 = {
-   .init   = init_8960,
+   .init   = init_common,
.calibrate  = calibrate_8960,
.get_temp   = get_temp_8960,
.enable = enable_8960,
-- 
2.30.0



[PATCH v10 3/8] drivers: thermal: tsens: Convert msm8960 to reg_field

2021-02-17 Thread Ansuel Smith
Convert msm9860 driver to reg_field to use the init_common
function.

Signed-off-by: Ansuel Smith 
---
 drivers/thermal/qcom/tsens-8960.c | 80 ++-
 1 file changed, 79 insertions(+), 1 deletion(-)

diff --git a/drivers/thermal/qcom/tsens-8960.c 
b/drivers/thermal/qcom/tsens-8960.c
index 2a28a5af209e..3f4fc1ffe679 100644
--- a/drivers/thermal/qcom/tsens-8960.c
+++ b/drivers/thermal/qcom/tsens-8960.c
@@ -51,11 +51,22 @@
 #define MIN_LIMIT_TH   0x0
 #define MAX_LIMIT_TH   0xff
 
-#define S0_STATUS_ADDR 0x3628
 #define INT_STATUS_ADDR0x363c
 #define TRDY_MASK  BIT(7)
 #define TIMEOUT_US 100
 
+#define S0_STATUS_OFF  0x3628
+#define S1_STATUS_OFF  0x362c
+#define S2_STATUS_OFF  0x3630
+#define S3_STATUS_OFF  0x3634
+#define S4_STATUS_OFF  0x3638
+#define S5_STATUS_OFF  0x3664  /* Sensors 5-10 found on 
apq8064/msm8960 */
+#define S6_STATUS_OFF  0x3668
+#define S7_STATUS_OFF  0x366c
+#define S8_STATUS_OFF  0x3670
+#define S9_STATUS_OFF  0x3674
+#define S10_STATUS_OFF 0x3678
+
 static int suspend_8960(struct tsens_priv *priv)
 {
int ret;
@@ -269,6 +280,71 @@ static int get_temp_8960(const struct tsens_sensor *s, int 
*temp)
return -ETIMEDOUT;
 }
 
+static struct tsens_features tsens_8960_feat = {
+   .ver_major  = VER_0,
+   .crit_int   = 0,
+   .adc= 1,
+   .srot_split = 0,
+   .max_sensors= 11,
+};
+
+static const struct reg_field tsens_8960_regfields[MAX_REGFIELDS] = {
+   /* - SROT -- */
+   /* No VERSION information */
+
+   /* CNTL */
+   [TSENS_EN] = REG_FIELD(CNTL_ADDR,  0, 0),
+   [TSENS_SW_RST] = REG_FIELD(CNTL_ADDR,  1, 1),
+   /* 8960 has 5 sensors, 8660 has 11, we only handle 5 */
+   [SENSOR_EN]= REG_FIELD(CNTL_ADDR,  3, 7),
+
+   /* - TM -- */
+   /* INTERRUPT ENABLE */
+   /* NO INTERRUPT ENABLE */
+
+   /* Single UPPER/LOWER TEMPERATURE THRESHOLD for all sensors */
+   [LOW_THRESH_0]   = REG_FIELD(THRESHOLD_ADDR,  0,  7),
+   [UP_THRESH_0]= REG_FIELD(THRESHOLD_ADDR,  8, 15),
+   /* MIN_THRESH_0 and MAX_THRESH_0 are not present in the regfield
+* Recycle CRIT_THRESH_0 and 1 to set the required regs to hardcoded 
temp
+* MIN_THRESH_0 -> CRIT_THRESH_1
+* MAX_THRESH_0 -> CRIT_THRESH_0
+*/
+   [CRIT_THRESH_1]   = REG_FIELD(THRESHOLD_ADDR, 16, 23),
+   [CRIT_THRESH_0]   = REG_FIELD(THRESHOLD_ADDR, 24, 31),
+
+   /* UPPER/LOWER INTERRUPT [CLEAR/STATUS] */
+   /* 1 == clear, 0 == normal operation */
+   [LOW_INT_CLEAR_0]   = REG_FIELD(CNTL_ADDR,  9,  9),
+   [UP_INT_CLEAR_0]= REG_FIELD(CNTL_ADDR, 10, 10),
+
+   /* NO CRITICAL INTERRUPT SUPPORT on 8960 */
+
+   /* Sn_STATUS */
+   [LAST_TEMP_0]  = REG_FIELD(S0_STATUS_OFF,  0,  7),
+   [LAST_TEMP_1]  = REG_FIELD(S1_STATUS_OFF,  0,  7),
+   [LAST_TEMP_2]  = REG_FIELD(S2_STATUS_OFF,  0,  7),
+   [LAST_TEMP_3]  = REG_FIELD(S3_STATUS_OFF,  0,  7),
+   [LAST_TEMP_4]  = REG_FIELD(S4_STATUS_OFF,  0,  7),
+   [LAST_TEMP_5]  = REG_FIELD(S5_STATUS_OFF,  0,  7),
+   [LAST_TEMP_6]  = REG_FIELD(S6_STATUS_OFF,  0,  7),
+   [LAST_TEMP_7]  = REG_FIELD(S7_STATUS_OFF,  0,  7),
+   [LAST_TEMP_8]  = REG_FIELD(S8_STATUS_OFF,  0,  7),
+   [LAST_TEMP_9]  = REG_FIELD(S9_STATUS_OFF,  0,  7),
+   [LAST_TEMP_10] = REG_FIELD(S10_STATUS_OFF, 0,  7),
+
+   /* No VALID field on 8960 */
+   /* TSENS_INT_STATUS bits: 1 == threshold violated */
+   [MIN_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 0, 0),
+   [LOWER_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 1, 1),
+   [UPPER_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 2, 2),
+   /* No CRITICAL field on 8960 */
+   [MAX_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 3, 3),
+
+   /* TRDY: 1=ready, 0=in progress */
+   [TRDY] = REG_FIELD(INT_STATUS_ADDR, 7, 7),
+};
+
 static const struct tsens_ops ops_8960 = {
.init   = init_8960,
.calibrate  = calibrate_8960,
@@ -282,4 +358,6 @@ static const struct tsens_ops ops_8960 = {
 struct tsens_plat_data data_8960 = {
.num_sensors= 11,
.ops= _8960,
+   .feat   = _8960_feat,
+   .fields = tsens_8960_regfields,
 };
-- 
2.30.0



[PATCH v2 1/3] mtd: partitions: ofpart: skip subnodes parse with compatible

2021-02-16 Thread Ansuel Smith
If a partitions structure is not used, parse direct subnodes as
fixed-partitions only if a compatible is not found or is of type
fixed-partition. A parser can be used directly on the subnode and
subnodes should not be parsed as fixed-partitions by default.

Signed-off-by: Ansuel Smith 
---
 drivers/mtd/parsers/ofpart.c | 5 +
 1 file changed, 5 insertions(+)

diff --git a/drivers/mtd/parsers/ofpart.c b/drivers/mtd/parsers/ofpart.c
index daf507c123e6..4b363dd0311c 100644
--- a/drivers/mtd/parsers/ofpart.c
+++ b/drivers/mtd/parsers/ofpart.c
@@ -50,6 +50,11 @@ static int parse_fixed_partitions(struct mtd_info *master,
 master->name, mtd_node);
ofpart_node = mtd_node;
dedicated = false;
+
+   /* Skip parsing direct subnodes if a compatible is found and is 
not fixed-partitions */
+   if (node_has_compatible(ofpart_node) &&
+   !of_device_is_compatible(ofpart_node, "fixed-partitions"))
+   return 0;
} else if (!of_device_is_compatible(ofpart_node, "fixed-partitions")) {
/* The 'partitions' subnode might be used by another parser */
return 0;
-- 
2.30.0



[PATCH v2 3/3] dt-bindings: mtd: Document use of nvmem-partitions compatible

2021-02-16 Thread Ansuel Smith
Document nvmem-partitions compatible used to treat mtd partitions as a
nvmem provider.

Signed-off-by: Ansuel Smith 
---
 .../mtd/partitions/nvmem-partitions.yaml  | 105 ++
 1 file changed, 105 insertions(+)
 create mode 100644 
Documentation/devicetree/bindings/mtd/partitions/nvmem-partitions.yaml

diff --git 
a/Documentation/devicetree/bindings/mtd/partitions/nvmem-partitions.yaml 
b/Documentation/devicetree/bindings/mtd/partitions/nvmem-partitions.yaml
new file mode 100644
index ..1ff283febcaa
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/partitions/nvmem-partitions.yaml
@@ -0,0 +1,105 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mtd/partitions/nvmem-partitions.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Nvmem partitions
+
+description: |
+  This binding can be used to treat the specific partition as a nvmem provider.
+  Each direct subnodes represents the nvmem cells and won't be parsed as 
fixed-partitions.
+  Fixed-partitions bindings described in fixed-partitions.yaml apply to the 
nvmem provider node.
+
+maintainers:
+  - Ansuel Smith 
+
+properties:
+  compatible:
+const: nvmem-partitions
+
+  "#address-cells": true
+
+  "#size-cells": true
+
+  reg:
+description: partition's offset and size within the flash
+maxItems: 1
+
+required:
+  - compatible
+  - "#address-cells"
+  - "#size-cells"
+  - reg
+
+additionalProperties: true
+
+examples:
+  - |
+partitions {
+  compatible = "fixed-partitions";
+  #address-cells = <1>;
+  #size-cells = <1>;
+
+  /* ... */
+
+  };
+  art: art@120 {
+compatible = "nvmem-partitions";
+reg = <0x120 0x014>;
+label = "art";
+read-only;
+#address-cells = <1>;
+#size-cells = <1>;
+
+macaddr_gmac1: macaddr_gmac1@0 {
+  reg = <0x0 0x6>;
+};
+
+macaddr_gmac2: macaddr_gmac2@6 {
+  reg = <0x6 0x6>;
+};
+
+pre_cal_24g: pre_cal_24g@1000 {
+  reg = <0x1000 0x2f20>;
+};
+
+pre_cal_5g: pre_cal_5g@5000{
+  reg = <0x5000 0x2f20>;
+};
+  };
+  - |
+partitions {
+compatible = "fixed-partitions";
+#address-cells = <1>;
+#size-cells = <1>;
+
+partition@0 {
+label = "bootloader";
+reg = <0x00 0x10>;
+read-only;
+};
+
+firmware@10 {
+compatible = "brcm,trx";
+label = "firmware";
+reg = <0x10 0xe0>;
+};
+
+calibration@f0 {
+compatible = "nvmem-partitions";
+label = "calibration";
+reg = <0xf0 0x10>;
+ranges = <0 0xf0 0x10>;
+#address-cells = <1>;
+#size-cells = <1>;
+
+wifi0@0 {
+reg = <0x00 0x08>;
+};
+
+wifi1@8 {
+reg = <0x08 0x08>;
+};
+};
+};
-- 
2.30.0



  1   2   3   4   >