Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
s3c-hwmon.c
Go to the documentation of this file.
1 /* linux/drivers/hwmon/s3c-hwmon.c
2  *
3  * Copyright (C) 2005, 2008, 2009 Simtec Electronics
4  * http://armlinux.simtec.co.uk/
5  * Ben Dooks <[email protected]>
6  *
7  * S3C24XX/S3C64XX ADC hwmon support
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License version 2 as
11  * published by the Free Software Foundation.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22 
23 #include <linux/module.h>
24 #include <linux/slab.h>
25 #include <linux/io.h>
26 #include <linux/init.h>
27 #include <linux/err.h>
28 #include <linux/clk.h>
29 #include <linux/interrupt.h>
30 #include <linux/platform_device.h>
31 
32 #include <linux/hwmon.h>
33 #include <linux/hwmon-sysfs.h>
34 
35 #include <plat/adc.h>
37 
41  char in_name[12];
42  char label_name[12];
43 };
44 
52 struct s3c_hwmon {
53  struct mutex lock;
55  struct device *hwmon_dev;
56 
57  struct s3c_hwmon_attr attrs[8];
58 };
59 
70 static int s3c_hwmon_read_ch(struct device *dev,
71  struct s3c_hwmon *hwmon, int channel)
72 {
73  int ret;
74 
75  ret = mutex_lock_interruptible(&hwmon->lock);
76  if (ret < 0)
77  return ret;
78 
79  dev_dbg(dev, "reading channel %d\n", channel);
80 
81  ret = s3c_adc_read(hwmon->client, channel);
82  mutex_unlock(&hwmon->lock);
83 
84  return ret;
85 }
86 
87 #ifdef CONFIG_SENSORS_S3C_RAW
88 
98 static ssize_t s3c_hwmon_show_raw(struct device *dev,
99  struct device_attribute *attr, char *buf)
100 {
101  struct s3c_hwmon *adc = platform_get_drvdata(to_platform_device(dev));
103  int ret;
104 
105  ret = s3c_hwmon_read_ch(dev, adc, sa->index);
106 
107  return (ret < 0) ? ret : snprintf(buf, PAGE_SIZE, "%d\n", ret);
108 }
109 
110 #define DEF_ADC_ATTR(x) \
111  static SENSOR_DEVICE_ATTR(adc##x##_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, x)
112 
113 DEF_ADC_ATTR(0);
114 DEF_ADC_ATTR(1);
115 DEF_ADC_ATTR(2);
116 DEF_ADC_ATTR(3);
117 DEF_ADC_ATTR(4);
118 DEF_ADC_ATTR(5);
119 DEF_ADC_ATTR(6);
120 DEF_ADC_ATTR(7);
121 
122 static struct attribute *s3c_hwmon_attrs[9] = {
123  &sensor_dev_attr_adc0_raw.dev_attr.attr,
124  &sensor_dev_attr_adc1_raw.dev_attr.attr,
125  &sensor_dev_attr_adc2_raw.dev_attr.attr,
126  &sensor_dev_attr_adc3_raw.dev_attr.attr,
127  &sensor_dev_attr_adc4_raw.dev_attr.attr,
128  &sensor_dev_attr_adc5_raw.dev_attr.attr,
129  &sensor_dev_attr_adc6_raw.dev_attr.attr,
130  &sensor_dev_attr_adc7_raw.dev_attr.attr,
131  NULL,
132 };
133 
134 static struct attribute_group s3c_hwmon_attrgroup = {
135  .attrs = s3c_hwmon_attrs,
136 };
137 
138 static inline int s3c_hwmon_add_raw(struct device *dev)
139 {
140  return sysfs_create_group(&dev->kobj, &s3c_hwmon_attrgroup);
141 }
142 
143 static inline void s3c_hwmon_remove_raw(struct device *dev)
144 {
145  sysfs_remove_group(&dev->kobj, &s3c_hwmon_attrgroup);
146 }
147 
148 #else
149 
150 static inline int s3c_hwmon_add_raw(struct device *dev) { return 0; }
151 static inline void s3c_hwmon_remove_raw(struct device *dev) { }
152 
153 #endif /* CONFIG_SENSORS_S3C_RAW */
154 
165 static ssize_t s3c_hwmon_ch_show(struct device *dev,
166  struct device_attribute *attr,
167  char *buf)
168 {
169  struct sensor_device_attribute *sen_attr = to_sensor_dev_attr(attr);
170  struct s3c_hwmon *hwmon = platform_get_drvdata(to_platform_device(dev));
171  struct s3c_hwmon_pdata *pdata = dev->platform_data;
172  struct s3c_hwmon_chcfg *cfg;
173  int ret;
174 
175  cfg = pdata->in[sen_attr->index];
176 
177  ret = s3c_hwmon_read_ch(dev, hwmon, sen_attr->index);
178  if (ret < 0)
179  return ret;
180 
181  ret *= cfg->mult;
182  ret = DIV_ROUND_CLOSEST(ret, cfg->div);
183 
184  return snprintf(buf, PAGE_SIZE, "%d\n", ret);
185 }
186 
195 static ssize_t s3c_hwmon_label_show(struct device *dev,
196  struct device_attribute *attr,
197  char *buf)
198 {
199  struct sensor_device_attribute *sen_attr = to_sensor_dev_attr(attr);
200  struct s3c_hwmon_pdata *pdata = dev->platform_data;
201  struct s3c_hwmon_chcfg *cfg;
202 
203  cfg = pdata->in[sen_attr->index];
204 
205  return snprintf(buf, PAGE_SIZE, "%s\n", cfg->name);
206 }
207 
222 static int s3c_hwmon_create_attr(struct device *dev,
223  struct s3c_hwmon_chcfg *cfg,
224  struct s3c_hwmon_attr *attrs,
225  int channel)
226 {
228  int ret;
229 
230  snprintf(attrs->in_name, sizeof(attrs->in_name), "in%d_input", channel);
231 
232  attr = &attrs->in;
233  attr->index = channel;
234  sysfs_attr_init(&attr->dev_attr.attr);
235  attr->dev_attr.attr.name = attrs->in_name;
236  attr->dev_attr.attr.mode = S_IRUGO;
237  attr->dev_attr.show = s3c_hwmon_ch_show;
238 
239  ret = device_create_file(dev, &attr->dev_attr);
240  if (ret < 0) {
241  dev_err(dev, "failed to create input attribute\n");
242  return ret;
243  }
244 
245  /* if this has a name, add a label */
246  if (cfg->name) {
247  snprintf(attrs->label_name, sizeof(attrs->label_name),
248  "in%d_label", channel);
249 
250  attr = &attrs->label;
251  attr->index = channel;
252  sysfs_attr_init(&attr->dev_attr.attr);
253  attr->dev_attr.attr.name = attrs->label_name;
254  attr->dev_attr.attr.mode = S_IRUGO;
255  attr->dev_attr.show = s3c_hwmon_label_show;
256 
257  ret = device_create_file(dev, &attr->dev_attr);
258  if (ret < 0) {
259  device_remove_file(dev, &attrs->in.dev_attr);
260  dev_err(dev, "failed to create label attribute\n");
261  }
262  }
263 
264  return ret;
265 }
266 
267 static void s3c_hwmon_remove_attr(struct device *dev,
268  struct s3c_hwmon_attr *attrs)
269 {
270  device_remove_file(dev, &attrs->in.dev_attr);
271  device_remove_file(dev, &attrs->label.dev_attr);
272 }
273 
278 static int __devinit s3c_hwmon_probe(struct platform_device *dev)
279 {
280  struct s3c_hwmon_pdata *pdata = dev->dev.platform_data;
281  struct s3c_hwmon *hwmon;
282  int ret = 0;
283  int i;
284 
285  if (!pdata) {
286  dev_err(&dev->dev, "no platform data supplied\n");
287  return -EINVAL;
288  }
289 
290  hwmon = devm_kzalloc(&dev->dev, sizeof(struct s3c_hwmon), GFP_KERNEL);
291  if (hwmon == NULL) {
292  dev_err(&dev->dev, "no memory\n");
293  return -ENOMEM;
294  }
295 
296  platform_set_drvdata(dev, hwmon);
297 
298  mutex_init(&hwmon->lock);
299 
300  /* Register with the core ADC driver. */
301 
302  hwmon->client = s3c_adc_register(dev, NULL, NULL, 0);
303  if (IS_ERR(hwmon->client)) {
304  dev_err(&dev->dev, "cannot register adc\n");
305  return PTR_ERR(hwmon->client);
306  }
307 
308  /* add attributes for our adc devices. */
309 
310  ret = s3c_hwmon_add_raw(&dev->dev);
311  if (ret)
312  goto err_registered;
313 
314  /* register with the hwmon core */
315 
316  hwmon->hwmon_dev = hwmon_device_register(&dev->dev);
317  if (IS_ERR(hwmon->hwmon_dev)) {
318  dev_err(&dev->dev, "error registering with hwmon\n");
319  ret = PTR_ERR(hwmon->hwmon_dev);
320  goto err_raw_attribute;
321  }
322 
323  for (i = 0; i < ARRAY_SIZE(pdata->in); i++) {
324  struct s3c_hwmon_chcfg *cfg = pdata->in[i];
325 
326  if (!cfg)
327  continue;
328 
329  if (cfg->mult >= 0x10000)
330  dev_warn(&dev->dev,
331  "channel %d multiplier too large\n",
332  i);
333 
334  if (cfg->div == 0) {
335  dev_err(&dev->dev, "channel %d divider zero\n", i);
336  continue;
337  }
338 
339  ret = s3c_hwmon_create_attr(&dev->dev, pdata->in[i],
340  &hwmon->attrs[i], i);
341  if (ret) {
342  dev_err(&dev->dev,
343  "error creating channel %d\n", i);
344 
345  for (i--; i >= 0; i--)
346  s3c_hwmon_remove_attr(&dev->dev,
347  &hwmon->attrs[i]);
348 
349  goto err_hwmon_register;
350  }
351  }
352 
353  return 0;
354 
355  err_hwmon_register:
357 
358  err_raw_attribute:
359  s3c_hwmon_remove_raw(&dev->dev);
360 
361  err_registered:
362  s3c_adc_release(hwmon->client);
363 
364  return ret;
365 }
366 
367 static int __devexit s3c_hwmon_remove(struct platform_device *dev)
368 {
369  struct s3c_hwmon *hwmon = platform_get_drvdata(dev);
370  int i;
371 
372  s3c_hwmon_remove_raw(&dev->dev);
373 
374  for (i = 0; i < ARRAY_SIZE(hwmon->attrs); i++)
375  s3c_hwmon_remove_attr(&dev->dev, &hwmon->attrs[i]);
376 
378  s3c_adc_release(hwmon->client);
379 
380  return 0;
381 }
382 
383 static struct platform_driver s3c_hwmon_driver = {
384  .driver = {
385  .name = "s3c-hwmon",
386  .owner = THIS_MODULE,
387  },
388  .probe = s3c_hwmon_probe,
389  .remove = __devexit_p(s3c_hwmon_remove),
390 };
391 
392 module_platform_driver(s3c_hwmon_driver);
393 
394 MODULE_AUTHOR("Ben Dooks <[email protected]>");
395 MODULE_DESCRIPTION("S3C ADC HWMon driver");
396 MODULE_LICENSE("GPL v2");
397 MODULE_ALIAS("platform:s3c-hwmon");