R: [PATCH v4 5/7] drivers: thermal: tsens: add interrupt support for 9860 driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




> -----Messaggio originale-----
> Da: Amit Kucheria <amit.kucheria@xxxxxxxxxx>
> Inviato: lunedì 20 luglio 2020 11:41
> A: Ansuel Smith <ansuelsmth@xxxxxxxxx>
> Cc: Rob Herring <robh+dt@xxxxxxxxxx>; Andy Gross <agross@xxxxxxxxxx>;
> Bjorn Andersson <bjorn.andersson@xxxxxxxxxx>; Zhang Rui
> <rui.zhang@xxxxxxxxx>; Daniel Lezcano <daniel.lezcano@xxxxxxxxxx>;
> Michael Turquette <mturquette@xxxxxxxxxxxx>; Stephen Boyd
> <sboyd@xxxxxxxxxx>; Linux PM list <linux-pm@xxxxxxxxxxxxxxx>; linux-arm-
> msm <linux-arm-msm@xxxxxxxxxxxxxxx>; DTML
> <devicetree@xxxxxxxxxxxxxxx>; Linux Kernel Mailing List <linux-
> kernel@xxxxxxxxxxxxxxx>; linux-clk <linux-clk@xxxxxxxxxxxxxxx>
> Oggetto: Re: [PATCH v4 5/7] drivers: thermal: tsens: add interrupt support
> for 9860 driver
> 
> Hi Ansuel,
> 
> Thanks for this patch.
> 
> On Thu, Jul 16, 2020 at 7:58 AM Ansuel Smith <ansuelsmth@xxxxxxxxx>
> wrote:
> >
> > Add interrupt support for 9860 tsens driver used to set thermal trip
> > point for the system.
> 
> typo: 8960
> 
> You've used the names 8960 and ipq8064 interchangeably throughout the
> series. AFAICT, msm8960, ipq8064 and apq8064 use the same IP version
> of tsens. Please use 8960 in all patches, descriptions and dt-binding.
> to reflect the filename for the driver.
> Then add ipq8064 and apq8064 in a comment in the driver like here to
> show that the driver also supports these other SoCs:
> https://elixir.bootlin.com/linux/v5.8-
> rc4/source/drivers/thermal/qcom/tsens-v0_1.c#L328
> 
> You can also add a new compatible string for ipq8064 as a separate
> patch at the end of the series.
> 
> > Signed-off-by: Ansuel Smith <ansuelsmth@xxxxxxxxx>
> > ---
> >  drivers/thermal/qcom/tsens-8960.c | 197
> +++++++++++++++++++++++++++---
> >  drivers/thermal/qcom/tsens.h      |   3 +
> >  2 files changed, 186 insertions(+), 14 deletions(-)
> >
> > diff --git a/drivers/thermal/qcom/tsens-8960.c
> b/drivers/thermal/qcom/tsens-8960.c
> > index 45788eb3c666..20d0bfb10f1f 100644
> > --- a/drivers/thermal/qcom/tsens-8960.c
> > +++ b/drivers/thermal/qcom/tsens-8960.c
> > @@ -8,6 +8,7 @@
> >  #include <linux/bitops.h>
> >  #include <linux/regmap.h>
> >  #include <linux/mfd/syscon.h>
> > +#include <linux/interrupt.h>
> >  #include <linux/thermal.h>
> >  #include "tsens.h"
> >
> > @@ -27,7 +28,6 @@
> >  /* CNTL_ADDR bitmasks */
> >  #define EN                     BIT(0)
> >  #define SW_RST                 BIT(1)
> > -#define SENSOR0_EN             BIT(3)
> >  #define SLP_CLK_ENA            BIT(26)
> >  #define SLP_CLK_ENA_8660       BIT(24)
> >  #define MEASURE_PERIOD         1
> > @@ -41,14 +41,26 @@
> >
> >  #define THRESHOLD_ADDR         0x3624
> >  /* THRESHOLD_ADDR bitmasks */
> > +#define THRESHOLD_MAX_CODE             0x20000
> > +#define THRESHOLD_MIN_CODE             0
> >  #define THRESHOLD_MAX_LIMIT_SHIFT      24
> >  #define THRESHOLD_MIN_LIMIT_SHIFT      16
> >  #define THRESHOLD_UPPER_LIMIT_SHIFT    8
> >  #define THRESHOLD_LOWER_LIMIT_SHIFT    0
> > +#define THRESHOLD_MAX_LIMIT_MASK       (THRESHOLD_MAX_CODE
> << \
> > +                                               THRESHOLD_MAX_LIMIT_SHIFT)
> > +#define THRESHOLD_MIN_LIMIT_MASK       (THRESHOLD_MAX_CODE <<
> \
> > +                                               THRESHOLD_MIN_LIMIT_SHIFT)
> > +#define THRESHOLD_UPPER_LIMIT_MASK     (THRESHOLD_MAX_CODE
> << \
> > +                                               THRESHOLD_UPPER_LIMIT_SHIFT)
> > +#define THRESHOLD_LOWER_LIMIT_MASK     (THRESHOLD_MAX_CODE
> << \
> > +                                               THRESHOLD_LOWER_LIMIT_SHIFT)
> >
> >  /* Initial temperature threshold values */
> > -#define LOWER_LIMIT_TH         0x50
> > -#define UPPER_LIMIT_TH         0xdf
> > +#define LOWER_LIMIT_TH_8960    0x50
> > +#define UPPER_LIMIT_TH_8960    0xdf
> > +#define LOWER_LIMIT_TH_8064    0x9d /* 95C */
> > +#define UPPER_LIMIT_TH_8064    0xa6 /* 105C */
> >  #define MIN_LIMIT_TH           0x0
> >  #define MAX_LIMIT_TH           0xff
> >
> > @@ -57,6 +69,170 @@
> >  #define TRDY_MASK              BIT(7)
> >  #define TIMEOUT_US             100
> >
> > +#define TSENS_EN               BIT(0)
> > +#define TSENS_SW_RST           BIT(1)
> > +#define TSENS_ADC_CLK_SEL      BIT(2)
> > +#define SENSOR0_EN             BIT(3)
> > +#define SENSOR1_EN             BIT(4)
> > +#define SENSOR2_EN             BIT(5)
> > +#define SENSOR3_EN             BIT(6)
> > +#define SENSOR4_EN             BIT(7)
> > +#define SENSORS_EN             (SENSOR0_EN | SENSOR1_EN | \
> > +                               SENSOR2_EN | SENSOR3_EN | SENSOR4_EN)
> > +#define TSENS_8064_SENSOR5_EN                          BIT(8)
> > +#define TSENS_8064_SENSOR6_EN                          BIT(9)
> > +#define TSENS_8064_SENSOR7_EN                          BIT(10)
> > +#define TSENS_8064_SENSOR8_EN                          BIT(11)
> > +#define TSENS_8064_SENSOR9_EN                          BIT(12)
> > +#define TSENS_8064_SENSOR10_EN                         BIT(13)
> > +#define TSENS_8064_SENSORS_EN                          (SENSORS_EN | \
> > +                                               TSENS_8064_SENSOR5_EN | \
> > +                                               TSENS_8064_SENSOR6_EN | \
> > +                                               TSENS_8064_SENSOR7_EN | \
> > +                                               TSENS_8064_SENSOR8_EN | \
> > +                                               TSENS_8064_SENSOR9_EN | \
> > +                                               TSENS_8064_SENSOR10_EN)
> > +
> > +u32 tsens_8960_slope[] = {
> > +                       1176, 1176, 1154, 1176,
> > +                       1111, 1132, 1132, 1199,
> > +                       1132, 1199, 1132
> > +                       };
> > +
> > +/* 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 void notify_uspace_tsens_fn(struct work_struct *work)
> > +{
> > +       struct tsens_sensor *s = container_of(work, struct tsens_sensor,
> > +                                                               notify_work);
> > +
> > +       sysfs_notify(&s->tzd->device.kobj, NULL, "type");
> > +}
> > +
> > +static void tsens_scheduler_fn(struct work_struct *work)
> > +{
> > +       struct tsens_priv *priv =
> > +               container_of(work, struct tsens_priv, tsens_work);
> > +       unsigned int threshold, threshold_low, code, reg, sensor;
> > +       unsigned long mask;
> > +       bool upper_th_x, lower_th_x;
> > +       int ret;
> > +
> > +       ret = regmap_read(priv->tm_map, STATUS_CNTL_ADDR_8064,
> &reg);
> > +       if (ret)
> > +               return;
> > +       reg = reg | LOWER_STATUS_CLR | UPPER_STATUS_CLR;
> > +       ret = regmap_write(priv->tm_map, STATUS_CNTL_ADDR_8064, reg);
> > +       if (ret)
> > +               return;
> > +
> > +       mask = ~(LOWER_STATUS_CLR | UPPER_STATUS_CLR);
> > +       ret = regmap_read(priv->tm_map, THRESHOLD_ADDR, &threshold);
> > +       if (ret)
> > +               return;
> > +       threshold_low = (threshold & THRESHOLD_LOWER_LIMIT_MASK) >>
> > +                       THRESHOLD_LOWER_LIMIT_SHIFT;
> > +       threshold = (threshold & THRESHOLD_UPPER_LIMIT_MASK) >>
> > +                   THRESHOLD_UPPER_LIMIT_SHIFT;
> > +
> > +       ret = regmap_read(priv->tm_map, STATUS_CNTL_ADDR_8064,
> &reg);
> > +       if (ret)
> > +               return;
> > +
> > +       ret = regmap_read(priv->tm_map, CNTL_ADDR, &sensor);
> > +       if (ret)
> > +               return;
> > +       sensor &= (uint32_t)TSENS_8064_SENSORS_EN;
> > +       sensor >>= SENSOR0_SHIFT;
> > +
> > +       /* 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.
> > +        */
> > +
> > +       /* Skip if the sensor is disabled */
> > +       if (sensor & 1) {
> > +               ret = regmap_read(priv->tm_map, priv->sensor[0].status,
> &code);
> > +               if (ret)
> > +                       return;
> > +               upper_th_x = code >= threshold;
> > +               lower_th_x = code <= threshold_low;
> > +               if (upper_th_x)
> > +                       mask |= UPPER_STATUS_CLR;
> > +               if (lower_th_x)
> > +                       mask |= LOWER_STATUS_CLR;
> > +               if (upper_th_x || lower_th_x) {
> > +                       /* Notify user space */
> > +                       schedule_work(&priv->sensor[0].notify_work);
> > +                       pr_debug("Trigger (%d degrees) for sensor %d\n",
> > +                                code_to_mdegC(code, &priv->sensor[0]), 0);
> > +               }
> > +       }
> > +       regmap_write(priv->tm_map, STATUS_CNTL_ADDR_8064, reg &
> mask);
> > +}
> > +
> > +static irqreturn_t tsens_isr(int irq, void *data)
> > +{
> > +       struct tsens_priv *priv = data;
> > +
> > +       schedule_work(&priv->tsens_work);
> > +       return IRQ_HANDLED;
> 
> 
> Have you considered trying to reuse the regmap and interrupt handling
> infrastructure in tsens.c that I used to convert over everything after
> IP version 0.1?
> 
> I started converting over 8960 but never managed to finish testing
> this[1]. I'd be happy for you to take this over and get it working so
> the 8960 doesn't end up being a completely separate driver from the
> other platforms.
> 
> [1]
> https://git.linaro.org/people/amit.kucheria/kernel.git/log/?h=wrk3/tsens-
> 8960-breakage
> 

Thanks a lot for the link. I started doing some test and I think the only general
code we will be able to use will be the init_common. The get temp and 
the function to convert code to decg are very different from the one used in 
8960.  Do you think keep a custom get temp function is good or not?


> > +}
> > +
> > +static void hw_init(struct tsens_priv *priv)
> > +{
> > +       int ret;
> > +       unsigned int reg_cntl = 0, reg_cfg = 0, reg_thr = 0;
> > +       unsigned int reg_status_cntl = 0;
> > +
> > +       regmap_read(priv->tm_map, CNTL_ADDR, &reg_cntl);
> > +       regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl |
> TSENS_SW_RST);
> > +
> > +       reg_cntl |= SLP_CLK_ENA | (MEASURE_PERIOD << 18) |
> > +                   (((1 << priv->num_sensors) - 1) << SENSOR0_SHIFT);
> > +       regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
> > +       regmap_read(priv->tm_map, STATUS_CNTL_ADDR_8064,
> &reg_status_cntl);
> > +       reg_status_cntl |= LOWER_STATUS_CLR | UPPER_STATUS_CLR |
> > +                          MIN_STATUS_MASK | MAX_STATUS_MASK;
> > +       regmap_write(priv->tm_map, STATUS_CNTL_ADDR_8064,
> reg_status_cntl);
> > +       reg_cntl |= TSENS_EN;
> > +       regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
> > +
> > +       regmap_read(priv->tm_map, CONFIG_ADDR, &reg_cfg);
> > +       if (priv->num_sensors > 1)
> > +               reg_cfg = (reg_cfg & ~CONFIG_MASK) | CONFIG;
> > +       else
> > +               reg_cfg = (reg_cfg & ~CONFIG_MASK) |
> > +                         (CONFIG << CONFIG_SHIFT_8660);
> > +       regmap_write(priv->tm_map, CONFIG_ADDR, reg_cfg);
> > +
> > +       reg_thr |= (LOWER_LIMIT_TH_8064 <<
> THRESHOLD_LOWER_LIMIT_SHIFT) |
> > +                  (UPPER_LIMIT_TH_8064 << THRESHOLD_UPPER_LIMIT_SHIFT)
> |
> > +                  (MIN_LIMIT_TH << THRESHOLD_MIN_LIMIT_SHIFT) |
> > +                  (MAX_LIMIT_TH << THRESHOLD_MAX_LIMIT_SHIFT);
> > +
> > +       regmap_write(priv->tm_map, THRESHOLD_ADDR, reg_thr);
> > +
> > +       ret = devm_request_irq(priv->dev, priv->tsens_irq, tsens_isr,
> > +                              IRQF_TRIGGER_RISING, "tsens_interrupt", priv);
> > +       if (ret < 0) {
> > +               dev_err(priv->dev, "request_irq FAIL: %d", ret);
> > +               return;
> > +       }
> > +
> > +       INIT_WORK(&priv->tsens_work, tsens_scheduler_fn);
> > +}
> > +
> >  static int suspend_8960(struct tsens_priv *priv)
> >  {
> >         int ret;
> > @@ -191,6 +367,8 @@ static int init_8960(struct tsens_priv *priv)
> >                 if (i >= 5)
> >                         priv->sensor[i].status = S0_STATUS_ADDR + 40;
> >                 priv->sensor[i].status += i * 4;
> > +               priv->sensor[i].slope = tsens_8960_slope[i];
> > +               INIT_WORK(&priv->sensor[i].notify_work,
> notify_uspace_tsens_fn);
> >         }
> >
> >         reg_cntl = SW_RST;
> > @@ -241,18 +419,9 @@ static int calibrate_8960(struct tsens_priv
> *priv)
> >
> >         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;
> > +       hw_init(priv);
> >
> > -       slope = thermal_zone_get_slope(s->tzd);
> > -       offset = CAL_MDEGC - slope * s->offset;
> > -
> > -       return adc_code * slope + offset;
> 
> This code move hunk belongs in a separate patch.
> 
> > +       return 0;
> >  }
> >
> >  static int get_temp_8960(const struct tsens_sensor *s, int *temp)
> > diff --git a/drivers/thermal/qcom/tsens.h
> b/drivers/thermal/qcom/tsens.h
> > index 59d01162c66a..e66048fabcc7 100644
> > --- a/drivers/thermal/qcom/tsens.h
> > +++ b/drivers/thermal/qcom/tsens.h
> > @@ -48,6 +48,7 @@ enum tsens_irq_type {
> >  struct tsens_sensor {
> >         struct tsens_priv               *priv;
> >         struct thermal_zone_device      *tzd;
> > +       struct work_struct              notify_work;
> >         int                             offset;
> >         unsigned int                    hw_id;
> >         int                             slope;
> > @@ -559,6 +560,7 @@ struct tsens_priv {
> >         struct regmap                   *tm_map;
> >         struct regmap                   *srot_map;
> >         u32                             tm_offset;
> > +       u32                             tsens_irq;
> >
> >         /* lock for upper/lower threshold interrupts */
> >         spinlock_t                      ul_lock;
> > @@ -568,6 +570,7 @@ struct tsens_priv {
> >         struct tsens_features           *feat;
> >         const struct reg_field          *fields;
> >         const struct tsens_ops          *ops;
> > +       struct work_struct              tsens_work;
> >
> >         struct dentry                   *debug_root;
> >         struct dentry                   *debug;
> > --
> > 2.27.0
> >





[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]


  Powered by Linux