brintos

brintos / linux-shallow public Read only

0
0
Text · 8.5 KiB · bb30403 Raw
343 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Maxim MAX197 A/D Converter driver4 *5 * Copyright (c) 2012 Savoir-faire Linux Inc.6 *          Vivien Didelot <vivien.didelot@savoirfairelinux.com>7 *8 * For further information, see the Documentation/hwmon/max197.rst file.9 */10 11#include <linux/kernel.h>12#include <linux/module.h>13#include <linux/mod_devicetable.h>14#include <linux/init.h>15#include <linux/err.h>16#include <linux/slab.h>17#include <linux/mutex.h>18#include <linux/device.h>19#include <linux/sysfs.h>20#include <linux/hwmon.h>21#include <linux/hwmon-sysfs.h>22#include <linux/platform_device.h>23#include <linux/platform_data/max197.h>24 25#define MAX199_LIMIT	4000		/* 4V */26#define MAX197_LIMIT	10000		/* 10V */27 28#define MAX197_NUM_CH	8		/* 8 Analog Input Channels */29 30/* Control byte format */31#define MAX197_BIP	(1 << 3)	/* Bipolarity */32#define MAX197_RNG	(1 << 4)	/* Full range */33 34#define MAX197_SCALE	12207		/* Scale coefficient for raw data */35 36/* List of supported chips */37enum max197_chips { max197, max199 };38 39/**40 * struct max197_data - device instance specific data41 * @pdata:		Platform data.42 * @hwmon_dev:		The hwmon device.43 * @lock:		Read/Write mutex.44 * @limit:		Max range value (10V for MAX197, 4V for MAX199).45 * @scale:		Need to scale.46 * @ctrl_bytes:		Channels control byte.47 */48struct max197_data {49	struct max197_platform_data *pdata;50	struct device *hwmon_dev;51	struct mutex lock;52	int limit;53	bool scale;54	u8 ctrl_bytes[MAX197_NUM_CH];55};56 57static inline void max197_set_unipolarity(struct max197_data *data, int channel)58{59	data->ctrl_bytes[channel] &= ~MAX197_BIP;60}61 62static inline void max197_set_bipolarity(struct max197_data *data, int channel)63{64	data->ctrl_bytes[channel] |= MAX197_BIP;65}66 67static inline void max197_set_half_range(struct max197_data *data, int channel)68{69	data->ctrl_bytes[channel] &= ~MAX197_RNG;70}71 72static inline void max197_set_full_range(struct max197_data *data, int channel)73{74	data->ctrl_bytes[channel] |= MAX197_RNG;75}76 77static inline bool max197_is_bipolar(struct max197_data *data, int channel)78{79	return data->ctrl_bytes[channel] & MAX197_BIP;80}81 82static inline bool max197_is_full_range(struct max197_data *data, int channel)83{84	return data->ctrl_bytes[channel] & MAX197_RNG;85}86 87/* Function called on read access on in{0,1,2,3,4,5,6,7}_{min,max} */88static ssize_t max197_show_range(struct device *dev,89				 struct device_attribute *devattr, char *buf)90{91	struct max197_data *data = dev_get_drvdata(dev);92	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);93	int channel = attr->index;94	bool is_min = attr->nr;95	int range;96 97	if (mutex_lock_interruptible(&data->lock))98		return -ERESTARTSYS;99 100	range = max197_is_full_range(data, channel) ?101		data->limit : data->limit / 2;102	if (is_min) {103		if (max197_is_bipolar(data, channel))104			range = -range;105		else106			range = 0;107	}108 109	mutex_unlock(&data->lock);110 111	return sprintf(buf, "%d\n", range);112}113 114/* Function called on write access on in{0,1,2,3,4,5,6,7}_{min,max} */115static ssize_t max197_store_range(struct device *dev,116				  struct device_attribute *devattr,117				  const char *buf, size_t count)118{119	struct max197_data *data = dev_get_drvdata(dev);120	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);121	int channel = attr->index;122	bool is_min = attr->nr;123	long value;124	int half = data->limit / 2;125	int full = data->limit;126 127	if (kstrtol(buf, 10, &value))128		return -EINVAL;129 130	if (is_min) {131		if (value <= -full)132			value = -full;133		else if (value < 0)134			value = -half;135		else136			value = 0;137	} else {138		if (value >= full)139			value = full;140		else141			value = half;142	}143 144	if (mutex_lock_interruptible(&data->lock))145		return -ERESTARTSYS;146 147	if (value == 0) {148		/* We can deduce only the polarity */149		max197_set_unipolarity(data, channel);150	} else if (value == -half) {151		max197_set_bipolarity(data, channel);152		max197_set_half_range(data, channel);153	} else if (value == -full) {154		max197_set_bipolarity(data, channel);155		max197_set_full_range(data, channel);156	} else if (value == half) {157		/* We can deduce only the range */158		max197_set_half_range(data, channel);159	} else if (value == full) {160		/* We can deduce only the range */161		max197_set_full_range(data, channel);162	}163 164	mutex_unlock(&data->lock);165 166	return count;167}168 169/* Function called on read access on in{0,1,2,3,4,5,6,7}_input */170static ssize_t max197_show_input(struct device *dev,171				 struct device_attribute *devattr,172				 char *buf)173{174	struct max197_data *data = dev_get_drvdata(dev);175	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);176	int channel = attr->index;177	s32 value;178	int ret;179 180	if (mutex_lock_interruptible(&data->lock))181		return -ERESTARTSYS;182 183	ret = data->pdata->convert(data->ctrl_bytes[channel]);184	if (ret < 0) {185		dev_err(dev, "conversion failed\n");186		goto unlock;187	}188	value = ret;189 190	/*191	 * Coefficient to apply on raw value.192	 * See Table 1. Full Scale and Zero Scale in the MAX197 datasheet.193	 */194	if (data->scale) {195		value *= MAX197_SCALE;196		if (max197_is_full_range(data, channel))197			value *= 2;198		value /= 10000;199	}200 201	ret = sprintf(buf, "%d\n", value);202 203unlock:204	mutex_unlock(&data->lock);205	return ret;206}207 208static ssize_t name_show(struct device *dev, struct device_attribute *attr,209			 char *buf)210{211	struct platform_device *pdev = to_platform_device(dev);212	return sprintf(buf, "%s\n", pdev->name);213}214 215#define MAX197_SENSOR_DEVICE_ATTR_CH(chan)				\216	static SENSOR_DEVICE_ATTR(in##chan##_input, S_IRUGO,		\217				  max197_show_input, NULL, chan);	\218	static SENSOR_DEVICE_ATTR_2(in##chan##_min, S_IRUGO | S_IWUSR,	\219				    max197_show_range,			\220				    max197_store_range,			\221				    true, chan);			\222	static SENSOR_DEVICE_ATTR_2(in##chan##_max, S_IRUGO | S_IWUSR,	\223				    max197_show_range,			\224				    max197_store_range,			\225				    false, chan)226 227#define MAX197_SENSOR_DEV_ATTR_IN(chan)					\228	&sensor_dev_attr_in##chan##_input.dev_attr.attr,		\229	&sensor_dev_attr_in##chan##_max.dev_attr.attr,			\230	&sensor_dev_attr_in##chan##_min.dev_attr.attr231 232static DEVICE_ATTR_RO(name);233 234MAX197_SENSOR_DEVICE_ATTR_CH(0);235MAX197_SENSOR_DEVICE_ATTR_CH(1);236MAX197_SENSOR_DEVICE_ATTR_CH(2);237MAX197_SENSOR_DEVICE_ATTR_CH(3);238MAX197_SENSOR_DEVICE_ATTR_CH(4);239MAX197_SENSOR_DEVICE_ATTR_CH(5);240MAX197_SENSOR_DEVICE_ATTR_CH(6);241MAX197_SENSOR_DEVICE_ATTR_CH(7);242 243static const struct attribute_group max197_sysfs_group = {244	.attrs = (struct attribute *[]) {245		&dev_attr_name.attr,246		MAX197_SENSOR_DEV_ATTR_IN(0),247		MAX197_SENSOR_DEV_ATTR_IN(1),248		MAX197_SENSOR_DEV_ATTR_IN(2),249		MAX197_SENSOR_DEV_ATTR_IN(3),250		MAX197_SENSOR_DEV_ATTR_IN(4),251		MAX197_SENSOR_DEV_ATTR_IN(5),252		MAX197_SENSOR_DEV_ATTR_IN(6),253		MAX197_SENSOR_DEV_ATTR_IN(7),254		NULL255	},256};257 258static int max197_probe(struct platform_device *pdev)259{260	int ch, ret;261	struct max197_data *data;262	struct max197_platform_data *pdata = dev_get_platdata(&pdev->dev);263	enum max197_chips chip = platform_get_device_id(pdev)->driver_data;264 265	if (pdata == NULL) {266		dev_err(&pdev->dev, "no platform data supplied\n");267		return -EINVAL;268	}269 270	if (pdata->convert == NULL) {271		dev_err(&pdev->dev, "no convert function supplied\n");272		return -EINVAL;273	}274 275	data = devm_kzalloc(&pdev->dev, sizeof(struct max197_data), GFP_KERNEL);276	if (!data)277		return -ENOMEM;278 279	data->pdata = pdata;280	mutex_init(&data->lock);281 282	if (chip == max197) {283		data->limit = MAX197_LIMIT;284		data->scale = true;285	} else {286		data->limit = MAX199_LIMIT;287		data->scale = false;288	}289 290	for (ch = 0; ch < MAX197_NUM_CH; ch++)291		data->ctrl_bytes[ch] = (u8) ch;292 293	platform_set_drvdata(pdev, data);294 295	ret = sysfs_create_group(&pdev->dev.kobj, &max197_sysfs_group);296	if (ret) {297		dev_err(&pdev->dev, "sysfs create group failed\n");298		return ret;299	}300 301	data->hwmon_dev = hwmon_device_register(&pdev->dev);302	if (IS_ERR(data->hwmon_dev)) {303		ret = PTR_ERR(data->hwmon_dev);304		dev_err(&pdev->dev, "hwmon device register failed\n");305		goto error;306	}307 308	return 0;309 310error:311	sysfs_remove_group(&pdev->dev.kobj, &max197_sysfs_group);312	return ret;313}314 315static void max197_remove(struct platform_device *pdev)316{317	struct max197_data *data = platform_get_drvdata(pdev);318 319	hwmon_device_unregister(data->hwmon_dev);320	sysfs_remove_group(&pdev->dev.kobj, &max197_sysfs_group);321}322 323static const struct platform_device_id max197_device_ids[] = {324	{ "max197", max197 },325	{ "max199", max199 },326	{ }327};328MODULE_DEVICE_TABLE(platform, max197_device_ids);329 330static struct platform_driver max197_driver = {331	.driver = {332		.name = "max197",333	},334	.probe = max197_probe,335	.remove_new = max197_remove,336	.id_table = max197_device_ids,337};338module_platform_driver(max197_driver);339 340MODULE_LICENSE("GPL");341MODULE_AUTHOR("Savoir-faire Linux Inc. <kernel@savoirfairelinux.com>");342MODULE_DESCRIPTION("Maxim MAX197 A/D Converter driver");343