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