0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/module.h>
0012 #include <linux/slab.h>
0013 #include <linux/io.h>
0014 #include <linux/init.h>
0015 #include <linux/err.h>
0016 #include <linux/clk.h>
0017 #include <linux/interrupt.h>
0018 #include <linux/platform_device.h>
0019
0020 #include <linux/hwmon.h>
0021 #include <linux/hwmon-sysfs.h>
0022
0023 #include <linux/soc/samsung/s3c-adc.h>
0024 #include <linux/platform_data/hwmon-s3c.h>
0025
0026 struct s3c_hwmon_attr {
0027 struct sensor_device_attribute in;
0028 struct sensor_device_attribute label;
0029 char in_name[12];
0030 char label_name[12];
0031 };
0032
0033
0034
0035
0036
0037
0038
0039
0040 struct s3c_hwmon {
0041 struct mutex lock;
0042 struct s3c_adc_client *client;
0043 struct device *hwmon_dev;
0044
0045 struct s3c_hwmon_attr attrs[8];
0046 };
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058 static int s3c_hwmon_read_ch(struct device *dev,
0059 struct s3c_hwmon *hwmon, int channel)
0060 {
0061 int ret;
0062
0063 ret = mutex_lock_interruptible(&hwmon->lock);
0064 if (ret < 0)
0065 return ret;
0066
0067 dev_dbg(dev, "reading channel %d\n", channel);
0068
0069 ret = s3c_adc_read(hwmon->client, channel);
0070 mutex_unlock(&hwmon->lock);
0071
0072 return ret;
0073 }
0074
0075 #ifdef CONFIG_SENSORS_S3C_RAW
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086 static ssize_t s3c_hwmon_show_raw(struct device *dev,
0087 struct device_attribute *attr, char *buf)
0088 {
0089 struct s3c_hwmon *adc = dev_get_drvdata(dev);
0090 struct sensor_device_attribute *sa = to_sensor_dev_attr(attr);
0091 int ret;
0092
0093 ret = s3c_hwmon_read_ch(dev, adc, sa->index);
0094
0095 return (ret < 0) ? ret : snprintf(buf, PAGE_SIZE, "%d\n", ret);
0096 }
0097
0098 static SENSOR_DEVICE_ATTR(adc0_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 0);
0099 static SENSOR_DEVICE_ATTR(adc1_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 1);
0100 static SENSOR_DEVICE_ATTR(adc2_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 2);
0101 static SENSOR_DEVICE_ATTR(adc3_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 3);
0102 static SENSOR_DEVICE_ATTR(adc4_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 4);
0103 static SENSOR_DEVICE_ATTR(adc5_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 5);
0104 static SENSOR_DEVICE_ATTR(adc6_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 6);
0105 static SENSOR_DEVICE_ATTR(adc7_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 7);
0106
0107 static struct attribute *s3c_hwmon_attrs[9] = {
0108 &sensor_dev_attr_adc0_raw.dev_attr.attr,
0109 &sensor_dev_attr_adc1_raw.dev_attr.attr,
0110 &sensor_dev_attr_adc2_raw.dev_attr.attr,
0111 &sensor_dev_attr_adc3_raw.dev_attr.attr,
0112 &sensor_dev_attr_adc4_raw.dev_attr.attr,
0113 &sensor_dev_attr_adc5_raw.dev_attr.attr,
0114 &sensor_dev_attr_adc6_raw.dev_attr.attr,
0115 &sensor_dev_attr_adc7_raw.dev_attr.attr,
0116 NULL,
0117 };
0118
0119 static struct attribute_group s3c_hwmon_attrgroup = {
0120 .attrs = s3c_hwmon_attrs,
0121 };
0122
0123 static inline int s3c_hwmon_add_raw(struct device *dev)
0124 {
0125 return sysfs_create_group(&dev->kobj, &s3c_hwmon_attrgroup);
0126 }
0127
0128 static inline void s3c_hwmon_remove_raw(struct device *dev)
0129 {
0130 sysfs_remove_group(&dev->kobj, &s3c_hwmon_attrgroup);
0131 }
0132
0133 #else
0134
0135 static inline int s3c_hwmon_add_raw(struct device *dev) { return 0; }
0136 static inline void s3c_hwmon_remove_raw(struct device *dev) { }
0137
0138 #endif
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150 static ssize_t s3c_hwmon_ch_show(struct device *dev,
0151 struct device_attribute *attr,
0152 char *buf)
0153 {
0154 struct sensor_device_attribute *sen_attr = to_sensor_dev_attr(attr);
0155 struct s3c_hwmon *hwmon = dev_get_drvdata(dev);
0156 struct s3c_hwmon_pdata *pdata = dev_get_platdata(dev);
0157 struct s3c_hwmon_chcfg *cfg;
0158 int ret;
0159
0160 cfg = pdata->in[sen_attr->index];
0161
0162 ret = s3c_hwmon_read_ch(dev, hwmon, sen_attr->index);
0163 if (ret < 0)
0164 return ret;
0165
0166 ret *= cfg->mult;
0167 ret = DIV_ROUND_CLOSEST(ret, cfg->div);
0168
0169 return sysfs_emit(buf, "%d\n", ret);
0170 }
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180 static ssize_t s3c_hwmon_label_show(struct device *dev,
0181 struct device_attribute *attr,
0182 char *buf)
0183 {
0184 struct sensor_device_attribute *sen_attr = to_sensor_dev_attr(attr);
0185 struct s3c_hwmon_pdata *pdata = dev_get_platdata(dev);
0186 struct s3c_hwmon_chcfg *cfg;
0187
0188 cfg = pdata->in[sen_attr->index];
0189
0190 return sysfs_emit(buf, "%s\n", cfg->name);
0191 }
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206
0207 static int s3c_hwmon_create_attr(struct device *dev,
0208 struct s3c_hwmon_chcfg *cfg,
0209 struct s3c_hwmon_attr *attrs,
0210 int channel)
0211 {
0212 struct sensor_device_attribute *attr;
0213 int ret;
0214
0215 snprintf(attrs->in_name, sizeof(attrs->in_name), "in%d_input", channel);
0216
0217 attr = &attrs->in;
0218 attr->index = channel;
0219 sysfs_attr_init(&attr->dev_attr.attr);
0220 attr->dev_attr.attr.name = attrs->in_name;
0221 attr->dev_attr.attr.mode = S_IRUGO;
0222 attr->dev_attr.show = s3c_hwmon_ch_show;
0223
0224 ret = device_create_file(dev, &attr->dev_attr);
0225 if (ret < 0) {
0226 dev_err(dev, "failed to create input attribute\n");
0227 return ret;
0228 }
0229
0230
0231 if (cfg->name) {
0232 snprintf(attrs->label_name, sizeof(attrs->label_name),
0233 "in%d_label", channel);
0234
0235 attr = &attrs->label;
0236 attr->index = channel;
0237 sysfs_attr_init(&attr->dev_attr.attr);
0238 attr->dev_attr.attr.name = attrs->label_name;
0239 attr->dev_attr.attr.mode = S_IRUGO;
0240 attr->dev_attr.show = s3c_hwmon_label_show;
0241
0242 ret = device_create_file(dev, &attr->dev_attr);
0243 if (ret < 0) {
0244 device_remove_file(dev, &attrs->in.dev_attr);
0245 dev_err(dev, "failed to create label attribute\n");
0246 }
0247 }
0248
0249 return ret;
0250 }
0251
0252 static void s3c_hwmon_remove_attr(struct device *dev,
0253 struct s3c_hwmon_attr *attrs)
0254 {
0255 device_remove_file(dev, &attrs->in.dev_attr);
0256 device_remove_file(dev, &attrs->label.dev_attr);
0257 }
0258
0259
0260
0261
0262
0263 static int s3c_hwmon_probe(struct platform_device *dev)
0264 {
0265 struct s3c_hwmon_pdata *pdata = dev_get_platdata(&dev->dev);
0266 struct s3c_hwmon *hwmon;
0267 int ret = 0;
0268 int i;
0269
0270 if (!pdata) {
0271 dev_err(&dev->dev, "no platform data supplied\n");
0272 return -EINVAL;
0273 }
0274
0275 hwmon = devm_kzalloc(&dev->dev, sizeof(struct s3c_hwmon), GFP_KERNEL);
0276 if (hwmon == NULL)
0277 return -ENOMEM;
0278
0279 platform_set_drvdata(dev, hwmon);
0280
0281 mutex_init(&hwmon->lock);
0282
0283
0284
0285 hwmon->client = s3c_adc_register(dev, NULL, NULL, 0);
0286 if (IS_ERR(hwmon->client)) {
0287 dev_err(&dev->dev, "cannot register adc\n");
0288 return PTR_ERR(hwmon->client);
0289 }
0290
0291
0292
0293 ret = s3c_hwmon_add_raw(&dev->dev);
0294 if (ret)
0295 goto err_registered;
0296
0297
0298
0299 hwmon->hwmon_dev = hwmon_device_register(&dev->dev);
0300 if (IS_ERR(hwmon->hwmon_dev)) {
0301 dev_err(&dev->dev, "error registering with hwmon\n");
0302 ret = PTR_ERR(hwmon->hwmon_dev);
0303 goto err_raw_attribute;
0304 }
0305
0306 for (i = 0; i < ARRAY_SIZE(pdata->in); i++) {
0307 struct s3c_hwmon_chcfg *cfg = pdata->in[i];
0308
0309 if (!cfg)
0310 continue;
0311
0312 if (cfg->mult >= 0x10000)
0313 dev_warn(&dev->dev,
0314 "channel %d multiplier too large\n",
0315 i);
0316
0317 if (cfg->div == 0) {
0318 dev_err(&dev->dev, "channel %d divider zero\n", i);
0319 continue;
0320 }
0321
0322 ret = s3c_hwmon_create_attr(&dev->dev, pdata->in[i],
0323 &hwmon->attrs[i], i);
0324 if (ret) {
0325 dev_err(&dev->dev,
0326 "error creating channel %d\n", i);
0327
0328 for (i--; i >= 0; i--)
0329 s3c_hwmon_remove_attr(&dev->dev,
0330 &hwmon->attrs[i]);
0331
0332 goto err_hwmon_register;
0333 }
0334 }
0335
0336 return 0;
0337
0338 err_hwmon_register:
0339 hwmon_device_unregister(hwmon->hwmon_dev);
0340
0341 err_raw_attribute:
0342 s3c_hwmon_remove_raw(&dev->dev);
0343
0344 err_registered:
0345 s3c_adc_release(hwmon->client);
0346
0347 return ret;
0348 }
0349
0350 static int s3c_hwmon_remove(struct platform_device *dev)
0351 {
0352 struct s3c_hwmon *hwmon = platform_get_drvdata(dev);
0353 int i;
0354
0355 s3c_hwmon_remove_raw(&dev->dev);
0356
0357 for (i = 0; i < ARRAY_SIZE(hwmon->attrs); i++)
0358 s3c_hwmon_remove_attr(&dev->dev, &hwmon->attrs[i]);
0359
0360 hwmon_device_unregister(hwmon->hwmon_dev);
0361 s3c_adc_release(hwmon->client);
0362
0363 return 0;
0364 }
0365
0366 static struct platform_driver s3c_hwmon_driver = {
0367 .driver = {
0368 .name = "s3c-hwmon",
0369 },
0370 .probe = s3c_hwmon_probe,
0371 .remove = s3c_hwmon_remove,
0372 };
0373
0374 module_platform_driver(s3c_hwmon_driver);
0375
0376 MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
0377 MODULE_DESCRIPTION("S3C ADC HWMon driver");
0378 MODULE_LICENSE("GPL v2");
0379 MODULE_ALIAS("platform:s3c-hwmon");