Skip to content

Commit 1d69957

Browse files
committed
hwmon: (sfctemp) Do conversions on demand
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 <kernel@esmil.dk>
1 parent c20bfe0 commit 1d69957

1 file changed

Lines changed: 59 additions & 13 deletions

File tree

drivers/hwmon/sfctemp.c

Lines changed: 59 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@
1111
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1212
* GNU General Public License for more details.
1313
*/
14+
#include <linux/completion.h>
1415
#include <linux/delay.h>
1516
#include <linux/hwmon.h>
1617
#include <linux/interrupt.h>
1718
#include <linux/module.h>
19+
#include <linux/mutex.h>
1820
#include <linux/of.h>
1921
#include <linux/platform_device.h>
2022

@@ -62,6 +64,8 @@
6264
#define SFCTEMP_K1000 81100L
6365

6466
struct sfctemp {
67+
struct mutex lock;
68+
struct completion conversion_done;
6569
void __iomem *regs;
6670
u32 dout;
6771
bool enabled;
@@ -72,7 +76,9 @@ static irqreturn_t sfctemp_isr(int irq, void *data)
7276
struct sfctemp *sfctemp = data;
7377
u32 reg = readl(sfctemp->regs);
7478

79+
writel(SFCTEMP_RSTN, sfctemp->regs);
7580
sfctemp->dout = (reg & SFCTEMP_DOUT_Msk) >> SFCTEMP_DOUT_Pos;
81+
complete(&sfctemp->conversion_done);
7682
return IRQ_HANDLED;
7783
}
7884

@@ -88,10 +94,6 @@ static void sfctemp_power_up(struct sfctemp *sfctemp)
8894
writel(SFCTEMP_RSTN, sfctemp->regs);
8995
/* wait t_su(500ps) */
9096
udelay(1);
91-
92-
writel(SFCTEMP_RSTN | SFCTEMP_RUN, sfctemp->regs);
93-
/* wait 1st sample (8192 temp_sense clk: ~2MHz) */
94-
msleep(10);
9597
}
9698

9799
static void sfctemp_power_down(struct sfctemp *sfctemp)
@@ -103,26 +105,64 @@ static void sfctemp_power_down(struct sfctemp *sfctemp)
103105
udelay(1);
104106
}
105107

108+
static void sfctemp_run(struct sfctemp *sfctemp)
109+
{
110+
writel(SFCTEMP_RSTN | SFCTEMP_RUN, sfctemp->regs);
111+
}
112+
106113
static int sfctemp_enable(struct sfctemp *sfctemp)
107114
{
115+
mutex_lock(&sfctemp->lock);
108116
if (sfctemp->enabled)
109-
return 0;
117+
goto done;
110118

111119
sfctemp_power_up(sfctemp);
112120
sfctemp->enabled = true;
121+
done:
122+
mutex_unlock(&sfctemp->lock);
113123
return 0;
114124
}
115125

116126
static int sfctemp_disable(struct sfctemp *sfctemp)
117127
{
128+
mutex_lock(&sfctemp->lock);
118129
if (!sfctemp->enabled)
119-
return 0;
130+
goto done;
120131

121132
sfctemp_power_down(sfctemp);
122133
sfctemp->enabled = false;
134+
done:
135+
mutex_unlock(&sfctemp->lock);
123136
return 0;
124137
}
125138

139+
static int sfctemp_convert(struct sfctemp *sfctemp, long *val)
140+
{
141+
long ret;
142+
143+
mutex_lock(&sfctemp->lock);
144+
if (!sfctemp->enabled) {
145+
ret = -ENODATA;
146+
goto out;
147+
}
148+
149+
sfctemp_run(sfctemp);
150+
151+
ret = wait_for_completion_interruptible_timeout(&sfctemp->conversion_done,
152+
msecs_to_jiffies(10));
153+
if (ret < 0)
154+
goto out;
155+
156+
/* calculate temperature in milli Celcius */
157+
*val = (SFCTEMP_Y1000 * (long)sfctemp->dout) / SFCTEMP_Z
158+
- SFCTEMP_K1000;
159+
160+
ret = 0;
161+
out:
162+
mutex_unlock(&sfctemp->lock);
163+
return ret;
164+
}
165+
126166
static umode_t sfctemp_is_visible(const void *data, enum hwmon_sensor_types type,
127167
u32 attr, int channel)
128168
{
@@ -152,12 +192,7 @@ static int sfctemp_read(struct device *dev, enum hwmon_sensor_types type,
152192
*val = sfctemp->enabled;
153193
return 0;
154194
case hwmon_temp_input:
155-
if (!sfctemp->enabled)
156-
return -ENODATA;
157-
/* calculate temperature in milli Celcius */
158-
*val = (SFCTEMP_Y1000 * (long)sfctemp->dout) / SFCTEMP_Z
159-
- SFCTEMP_K1000;
160-
return 0;
195+
return sfctemp_convert(sfctemp, val);
161196
}
162197
return -EINVAL;
163198
default:
@@ -209,6 +244,7 @@ static int sfctemp_probe(struct platform_device *pdev)
209244
struct device *hwmon_dev;
210245
struct resource *mem;
211246
struct sfctemp *sfctemp;
247+
long val;
212248
int ret;
213249

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

218254
dev_set_drvdata(dev, sfctemp);
219255

256+
mutex_init(&sfctemp->lock);
257+
init_completion(&sfctemp->conversion_done);
258+
220259
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
221260
sfctemp->regs = devm_ioremap_resource(dev, mem);
222261
if (IS_ERR(sfctemp->regs))
@@ -242,7 +281,14 @@ static int sfctemp_probe(struct platform_device *pdev)
242281
if (IS_ERR(hwmon_dev))
243282
return PTR_ERR(hwmon_dev);
244283

245-
dev_info(dev, "%s: sensor '%s'\n", dev_name(hwmon_dev), pdev->name);
284+
/* do a conversion to check everything works */
285+
ret = sfctemp_convert(sfctemp, &val);
286+
if (ret) {
287+
hwmon_device_unregister(hwmon_dev);
288+
return ret;
289+
}
290+
291+
dev_info(dev, "%ld.%03ld C\n", val / 1000, val % 1000);
246292
return 0;
247293
}
248294

0 commit comments

Comments
 (0)