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 <ben@simtec.co.uk> 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/delay.h> 26#include <linux/io.h> 27#include <linux/init.h> 28#include <linux/err.h> 29#include <linux/clk.h> 30#include <linux/interrupt.h> 31#include <linux/platform_device.h> 32 33#include <linux/hwmon.h> 34#include <linux/hwmon-sysfs.h> 35 36#include <plat/adc.h> 37#include <plat/hwmon.h> 38 39struct s3c_hwmon_attr { 40 struct sensor_device_attribute in; 41 struct sensor_device_attribute label; 42 char in_name[12]; 43 char label_name[12]; 44}; 45 46/** 47 * struct s3c_hwmon - ADC hwmon client information 48 * @lock: Access lock to serialise the conversions. 49 * @client: The client we registered with the S3C ADC core. 50 * @hwmon_dev: The hwmon device we created. 51 * @attr: The holders for the channel attributes. 52*/ 53struct s3c_hwmon { 54 struct semaphore lock; 55 struct s3c_adc_client *client; 56 struct device *hwmon_dev; 57 58 struct s3c_hwmon_attr attrs[8]; 59}; 60 61/** 62 * s3c_hwmon_read_ch - read a value from a given adc channel. 63 * @dev: The device. 64 * @hwmon: Our state. 65 * @channel: The channel we're reading from. 66 * 67 * Read a value from the @channel with the proper locking and sleep until 68 * either the read completes or we timeout awaiting the ADC core to get 69 * back to us. 70 */ 71static int s3c_hwmon_read_ch(struct device *dev, 72 struct s3c_hwmon *hwmon, int channel) 73{ 74 int ret; 75 76 ret = down_interruptible(&hwmon->lock); 77 if (ret < 0) 78 return ret; 79 80 dev_dbg(dev, "reading channel %d\n", channel); 81 82 ret = s3c_adc_read(hwmon->client, channel); 83 up(&hwmon->lock); 84 85 return ret; 86} 87 88#ifdef CONFIG_SENSORS_S3C_RAW 89/** 90 * s3c_hwmon_show_raw - show a conversion from the raw channel number. 91 * @dev: The device that the attribute belongs to. 92 * @attr: The attribute being read. 93 * @buf: The result buffer. 94 * 95 * This show deals with the raw attribute, registered for each possible 96 * ADC channel. This does a conversion and returns the raw (un-scaled) 97 * value returned from the hardware. 98 */ 99static ssize_t s3c_hwmon_show_raw(struct device *dev, 100 struct device_attribute *attr, char *buf) 101{ 102 struct s3c_hwmon *adc = platform_get_drvdata(to_platform_device(dev)); 103 struct sensor_device_attribute *sa = to_sensor_dev_attr(attr); 104 int ret; 105 106 ret = s3c_hwmon_read_ch(dev, adc, sa->index); 107 108 return (ret < 0) ? ret : snprintf(buf, PAGE_SIZE, "%d\n", ret); 109} 110 111#define DEF_ADC_ATTR(x) \ 112 static SENSOR_DEVICE_ATTR(adc##x##_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, x) 113 114DEF_ADC_ATTR(0); 115DEF_ADC_ATTR(1); 116DEF_ADC_ATTR(2); 117DEF_ADC_ATTR(3); 118DEF_ADC_ATTR(4); 119DEF_ADC_ATTR(5); 120DEF_ADC_ATTR(6); 121DEF_ADC_ATTR(7); 122 123static struct attribute *s3c_hwmon_attrs[9] = { 124 &sensor_dev_attr_adc0_raw.dev_attr.attr, 125 &sensor_dev_attr_adc1_raw.dev_attr.attr, 126 &sensor_dev_attr_adc2_raw.dev_attr.attr, 127 &sensor_dev_attr_adc3_raw.dev_attr.attr, 128 &sensor_dev_attr_adc4_raw.dev_attr.attr, 129 &sensor_dev_attr_adc5_raw.dev_attr.attr, 130 &sensor_dev_attr_adc6_raw.dev_attr.attr, 131 &sensor_dev_attr_adc7_raw.dev_attr.attr, 132 NULL, 133}; 134 135static struct attribute_group s3c_hwmon_attrgroup = { 136 .attrs = s3c_hwmon_attrs, 137}; 138 139static inline int s3c_hwmon_add_raw(struct device *dev) 140{ 141 return sysfs_create_group(&dev->kobj, &s3c_hwmon_attrgroup); 142} 143 144static inline void s3c_hwmon_remove_raw(struct device *dev) 145{ 146 sysfs_remove_group(&dev->kobj, &s3c_hwmon_attrgroup); 147} 148 149#else 150 151static inline int s3c_hwmon_add_raw(struct device *dev) { return 0; } 152static inline void s3c_hwmon_remove_raw(struct device *dev) { } 153 154#endif /* CONFIG_SENSORS_S3C_RAW */ 155 156/** 157 * s3c_hwmon_ch_show - show value of a given channel 158 * @dev: The device that the attribute belongs to. 159 * @attr: The attribute being read. 160 * @buf: The result buffer. 161 * 162 * Read a value from the ADC and scale it before returning it to the 163 * caller. The scale factor is gained from the channel configuration 164 * passed via the platform data when the device was registered. 165 */ 166static ssize_t s3c_hwmon_ch_show(struct device *dev, 167 struct device_attribute *attr, 168 char *buf) 169{ 170 struct sensor_device_attribute *sen_attr = to_sensor_dev_attr(attr); 171 struct s3c_hwmon *hwmon = platform_get_drvdata(to_platform_device(dev)); 172 struct s3c_hwmon_pdata *pdata = dev->platform_data; 173 struct s3c_hwmon_chcfg *cfg; 174 int ret; 175 176 cfg = pdata->in[sen_attr->index]; 177 178 ret = s3c_hwmon_read_ch(dev, hwmon, sen_attr->index); 179 if (ret < 0) 180 return ret; 181 182 ret *= cfg->mult; 183 ret = DIV_ROUND_CLOSEST(ret, cfg->div); 184 185 return snprintf(buf, PAGE_SIZE, "%d\n", ret); 186} 187 188/** 189 * s3c_hwmon_label_show - show label name of the given channel. 190 * @dev: The device that the attribute belongs to. 191 * @attr: The attribute being read. 192 * @buf: The result buffer. 193 * 194 * Return the label name of a given channel 195 */ 196static ssize_t s3c_hwmon_label_show(struct device *dev, 197 struct device_attribute *attr, 198 char *buf) 199{ 200 struct sensor_device_attribute *sen_attr = to_sensor_dev_attr(attr); 201 struct s3c_hwmon_pdata *pdata = dev->platform_data; 202 struct s3c_hwmon_chcfg *cfg; 203 204 cfg = pdata->in[sen_attr->index]; 205 206 return snprintf(buf, PAGE_SIZE, "%s\n", cfg->name); 207} 208 209/** 210 * s3c_hwmon_create_attr - create hwmon attribute for given channel. 211 * @dev: The device to create the attribute on. 212 * @cfg: The channel configuration passed from the platform data. 213 * @channel: The ADC channel number to process. 214 * 215 * Create the scaled attribute for use with hwmon from the specified 216 * platform data in @pdata. The sysfs entry is handled by the routine 217 * s3c_hwmon_ch_show(). 218 * 219 * The attribute name is taken from the configuration data if present 220 * otherwise the name is taken by concatenating in_ with the channel 221 * number. 222 */ 223static int s3c_hwmon_create_attr(struct device *dev, 224 struct s3c_hwmon_chcfg *cfg, 225 struct s3c_hwmon_attr *attrs, 226 int channel) 227{ 228 struct sensor_device_attribute *attr; 229 int ret; 230 231 snprintf(attrs->in_name, sizeof(attrs->in_name), "in%d_input", channel); 232 233 attr = &attrs->in; 234 attr->index = channel; 235 attr->dev_attr.attr.name = attrs->in_name; 236 attr->dev_attr.attr.mode = S_IRUGO; 237 attr->dev_attr.attr.owner = THIS_MODULE; 238 attr->dev_attr.show = s3c_hwmon_ch_show; 239 240 ret = device_create_file(dev, &attr->dev_attr); 241 if (ret < 0) { 242 dev_err(dev, "failed to create input attribute\n"); 243 return ret; 244 } 245 246 /* if this has a name, add a label */ 247 if (cfg->name) { 248 snprintf(attrs->label_name, sizeof(attrs->label_name), 249 "in%d_label", channel); 250 251 attr = &attrs->label; 252 attr->index = channel; 253 attr->dev_attr.attr.name = attrs->label_name; 254 attr->dev_attr.attr.mode = S_IRUGO; 255 attr->dev_attr.attr.owner = THIS_MODULE; 256 attr->dev_attr.show = s3c_hwmon_label_show; 257 258 ret = device_create_file(dev, &attr->dev_attr); 259 if (ret < 0) { 260 device_remove_file(dev, &attrs->in.dev_attr); 261 dev_err(dev, "failed to create label attribute\n"); 262 } 263 } 264 265 return ret; 266} 267 268static void s3c_hwmon_remove_attr(struct device *dev, 269 struct s3c_hwmon_attr *attrs) 270{ 271 device_remove_file(dev, &attrs->in.dev_attr); 272 device_remove_file(dev, &attrs->label.dev_attr); 273} 274 275/** 276 * s3c_hwmon_probe - device probe entry. 277 * @dev: The device being probed. 278*/ 279static int __devinit s3c_hwmon_probe(struct platform_device *dev) 280{ 281 struct s3c_hwmon_pdata *pdata = dev->dev.platform_data; 282 struct s3c_hwmon *hwmon; 283 int ret = 0; 284 int i; 285 286 if (!pdata) { 287 dev_err(&dev->dev, "no platform data supplied\n"); 288 return -EINVAL; 289 } 290 291 hwmon = kzalloc(sizeof(struct s3c_hwmon), GFP_KERNEL); 292 if (hwmon == NULL) { 293 dev_err(&dev->dev, "no memory\n"); 294 return -ENOMEM; 295 } 296 297 platform_set_drvdata(dev, hwmon); 298 299 init_MUTEX(&hwmon->lock); 300 301 /* Register with the core ADC driver. */ 302 303 hwmon->client = s3c_adc_register(dev, NULL, NULL, 0); 304 if (IS_ERR(hwmon->client)) { 305 dev_err(&dev->dev, "cannot register adc\n"); 306 ret = PTR_ERR(hwmon->client); 307 goto err_mem; 308 } 309 310 /* add attributes for our adc devices. */ 311 312 ret = s3c_hwmon_add_raw(&dev->dev); 313 if (ret) 314 goto err_registered; 315 316 /* register with the hwmon core */ 317 318 hwmon->hwmon_dev = hwmon_device_register(&dev->dev); 319 if (IS_ERR(hwmon->hwmon_dev)) { 320 dev_err(&dev->dev, "error registering with hwmon\n"); 321 ret = PTR_ERR(hwmon->hwmon_dev); 322 goto err_raw_attribute; 323 } 324 325 for (i = 0; i < ARRAY_SIZE(pdata->in); i++) { 326 struct s3c_hwmon_chcfg *cfg = pdata->in[i]; 327 328 if (!cfg) 329 continue; 330 331 if (cfg->mult >= 0x10000) 332 dev_warn(&dev->dev, 333 "channel %d multiplier too large\n", 334 i); 335 336 if (cfg->div == 0) { 337 dev_err(&dev->dev, "channel %d divider zero\n", i); 338 continue; 339 } 340 341 ret = s3c_hwmon_create_attr(&dev->dev, pdata->in[i], 342 &hwmon->attrs[i], i); 343 if (ret) { 344 dev_err(&dev->dev, 345 "error creating channel %d\n", i); 346 347 for (i--; i >= 0; i--) 348 s3c_hwmon_remove_attr(&dev->dev, 349 &hwmon->attrs[i]); 350 351 goto err_hwmon_register; 352 } 353 } 354 355 return 0; 356 357 err_hwmon_register: 358 hwmon_device_unregister(hwmon->hwmon_dev); 359 360 err_raw_attribute: 361 s3c_hwmon_remove_raw(&dev->dev); 362 363 err_registered: 364 s3c_adc_release(hwmon->client); 365 366 err_mem: 367 kfree(hwmon); 368 return ret; 369} 370 371static int __devexit s3c_hwmon_remove(struct platform_device *dev) 372{ 373 struct s3c_hwmon *hwmon = platform_get_drvdata(dev); 374 int i; 375 376 s3c_hwmon_remove_raw(&dev->dev); 377 378 for (i = 0; i < ARRAY_SIZE(hwmon->attrs); i++) 379 s3c_hwmon_remove_attr(&dev->dev, &hwmon->attrs[i]); 380 381 hwmon_device_unregister(hwmon->hwmon_dev); 382 s3c_adc_release(hwmon->client); 383 384 return 0; 385} 386 387static struct platform_driver s3c_hwmon_driver = { 388 .driver = { 389 .name = "s3c-hwmon", 390 .owner = THIS_MODULE, 391 }, 392 .probe = s3c_hwmon_probe, 393 .remove = __devexit_p(s3c_hwmon_remove), 394}; 395 396static int __init s3c_hwmon_init(void) 397{ 398 return platform_driver_register(&s3c_hwmon_driver); 399} 400 401static void __exit s3c_hwmon_exit(void) 402{ 403 platform_driver_unregister(&s3c_hwmon_driver); 404} 405 406module_init(s3c_hwmon_init); 407module_exit(s3c_hwmon_exit); 408 409MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); 410MODULE_DESCRIPTION("S3C ADC HWMon driver"); 411MODULE_LICENSE("GPL v2"); 412MODULE_ALIAS("platform:s3c-hwmon"); 413