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
6264#define SFCTEMP_K1000 81100L
6365
6466struct 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
9799static 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+
106113static 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
116126static 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+
126166static 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