Skip to content

Commit

Permalink
hwmon: (sfctemp) Do conversions on demand
Browse files Browse the repository at this point in the history
When the RUN bit is set comments suggests conversions are done every
8192 / (2MHz) ~= 4ms. Looking at /proc/interrupts without this patch
also shows a lot of interrupts from 124a0000.tmon.

Let's just do the a single conversion when prompted by userspace or the
thermal framework.

Signed-off-by: Emil Renner Berthing <[email protected]>
  • Loading branch information
esmil committed May 27, 2021
1 parent c20bfe0 commit 1d69957
Showing 1 changed file with 59 additions and 13 deletions.
72 changes: 59 additions & 13 deletions drivers/hwmon/sfctemp.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/hwmon.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/platform_device.h>

Expand Down Expand Up @@ -62,6 +64,8 @@
#define SFCTEMP_K1000 81100L

struct sfctemp {
struct mutex lock;
struct completion conversion_done;
void __iomem *regs;
u32 dout;
bool enabled;
Expand All @@ -72,7 +76,9 @@ static irqreturn_t sfctemp_isr(int irq, void *data)
struct sfctemp *sfctemp = data;
u32 reg = readl(sfctemp->regs);

writel(SFCTEMP_RSTN, sfctemp->regs);
sfctemp->dout = (reg & SFCTEMP_DOUT_Msk) >> SFCTEMP_DOUT_Pos;
complete(&sfctemp->conversion_done);
return IRQ_HANDLED;
}

Expand All @@ -88,10 +94,6 @@ static void sfctemp_power_up(struct sfctemp *sfctemp)
writel(SFCTEMP_RSTN, sfctemp->regs);
/* wait t_su(500ps) */
udelay(1);

writel(SFCTEMP_RSTN | SFCTEMP_RUN, sfctemp->regs);
/* wait 1st sample (8192 temp_sense clk: ~2MHz) */
msleep(10);
}

static void sfctemp_power_down(struct sfctemp *sfctemp)
Expand All @@ -103,26 +105,64 @@ static void sfctemp_power_down(struct sfctemp *sfctemp)
udelay(1);
}

static void sfctemp_run(struct sfctemp *sfctemp)
{
writel(SFCTEMP_RSTN | SFCTEMP_RUN, sfctemp->regs);
}

static int sfctemp_enable(struct sfctemp *sfctemp)
{
mutex_lock(&sfctemp->lock);
if (sfctemp->enabled)
return 0;
goto done;

sfctemp_power_up(sfctemp);
sfctemp->enabled = true;
done:
mutex_unlock(&sfctemp->lock);
return 0;
}

static int sfctemp_disable(struct sfctemp *sfctemp)
{
mutex_lock(&sfctemp->lock);
if (!sfctemp->enabled)
return 0;
goto done;

sfctemp_power_down(sfctemp);
sfctemp->enabled = false;
done:
mutex_unlock(&sfctemp->lock);
return 0;
}

static int sfctemp_convert(struct sfctemp *sfctemp, long *val)
{
long ret;

mutex_lock(&sfctemp->lock);
if (!sfctemp->enabled) {
ret = -ENODATA;
goto out;
}

sfctemp_run(sfctemp);

ret = wait_for_completion_interruptible_timeout(&sfctemp->conversion_done,
msecs_to_jiffies(10));
if (ret < 0)
goto out;

/* calculate temperature in milli Celcius */
*val = (SFCTEMP_Y1000 * (long)sfctemp->dout) / SFCTEMP_Z
- SFCTEMP_K1000;

ret = 0;
out:
mutex_unlock(&sfctemp->lock);
return ret;
}

static umode_t sfctemp_is_visible(const void *data, enum hwmon_sensor_types type,
u32 attr, int channel)
{
Expand Down Expand Up @@ -152,12 +192,7 @@ static int sfctemp_read(struct device *dev, enum hwmon_sensor_types type,
*val = sfctemp->enabled;
return 0;
case hwmon_temp_input:
if (!sfctemp->enabled)
return -ENODATA;
/* calculate temperature in milli Celcius */
*val = (SFCTEMP_Y1000 * (long)sfctemp->dout) / SFCTEMP_Z
- SFCTEMP_K1000;
return 0;
return sfctemp_convert(sfctemp, val);
}
return -EINVAL;
default:
Expand Down Expand Up @@ -209,6 +244,7 @@ static int sfctemp_probe(struct platform_device *pdev)
struct device *hwmon_dev;
struct resource *mem;
struct sfctemp *sfctemp;
long val;
int ret;

sfctemp = devm_kzalloc(dev, sizeof(*sfctemp), GFP_KERNEL);
Expand All @@ -217,6 +253,9 @@ static int sfctemp_probe(struct platform_device *pdev)

dev_set_drvdata(dev, sfctemp);

mutex_init(&sfctemp->lock);
init_completion(&sfctemp->conversion_done);

mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
sfctemp->regs = devm_ioremap_resource(dev, mem);
if (IS_ERR(sfctemp->regs))
Expand All @@ -242,7 +281,14 @@ static int sfctemp_probe(struct platform_device *pdev)
if (IS_ERR(hwmon_dev))
return PTR_ERR(hwmon_dev);

dev_info(dev, "%s: sensor '%s'\n", dev_name(hwmon_dev), pdev->name);
/* do a conversion to check everything works */
ret = sfctemp_convert(sfctemp, &val);
if (ret) {
hwmon_device_unregister(hwmon_dev);
return ret;
}

dev_info(dev, "%ld.%03ld C\n", val / 1000, val % 1000);
return 0;
}

Expand Down

0 comments on commit 1d69957

Please sign in to comment.