brintos

brintos / linux-shallow public Read only

0
0
Text · 5.1 KiB · ae53bac Raw
250 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 *  m62332.c - Support for Mitsubishi m62332 DAC4 *5 *  Copyright (c) 2014 Dmitry Eremin-Solenikov6 *7 *  Based on max517 driver:8 *  Copyright (C) 2010, 2011 Roland Stigge <stigge@antcom.de>9 */10 11#include <linux/module.h>12#include <linux/slab.h>13#include <linux/i2c.h>14#include <linux/err.h>15 16#include <linux/iio/iio.h>17#include <linux/iio/driver.h>18 19#include <linux/regulator/consumer.h>20 21#define M62332_CHANNELS 222 23struct m62332_data {24	struct i2c_client	*client;25	struct regulator	*vcc;26	struct mutex		mutex;27	u8			raw[M62332_CHANNELS];28	u8			save[M62332_CHANNELS];29};30 31static int m62332_set_value(struct iio_dev *indio_dev, u8 val, int channel)32{33	struct m62332_data *data = iio_priv(indio_dev);34	struct i2c_client *client = data->client;35	u8 outbuf[2];36	int res;37 38	if (val == data->raw[channel])39		return 0;40 41	outbuf[0] = channel;42	outbuf[1] = val;43 44	mutex_lock(&data->mutex);45 46	if (val) {47		res = regulator_enable(data->vcc);48		if (res)49			goto out;50	}51 52	res = i2c_master_send(client, outbuf, ARRAY_SIZE(outbuf));53	if (res >= 0 && res != ARRAY_SIZE(outbuf))54		res = -EIO;55	if (res < 0)56		goto out;57 58	data->raw[channel] = val;59 60	if (!val)61		regulator_disable(data->vcc);62 63	mutex_unlock(&data->mutex);64 65	return 0;66 67out:68	mutex_unlock(&data->mutex);69 70	return res;71}72 73static int m62332_read_raw(struct iio_dev *indio_dev,74			   struct iio_chan_spec const *chan,75			   int *val,76			   int *val2,77			   long mask)78{79	struct m62332_data *data = iio_priv(indio_dev);80	int ret;81 82	switch (mask) {83	case IIO_CHAN_INFO_SCALE:84		/* Corresponds to Vref / 2^(bits) */85		ret = regulator_get_voltage(data->vcc);86		if (ret < 0)87			return ret;88 89		*val = ret / 1000; /* mV */90		*val2 = 8;91 92		return IIO_VAL_FRACTIONAL_LOG2;93	case IIO_CHAN_INFO_RAW:94		*val = data->raw[chan->channel];95 96		return IIO_VAL_INT;97	case IIO_CHAN_INFO_OFFSET:98		*val = 1;99 100		return IIO_VAL_INT;101	default:102		break;103	}104 105	return -EINVAL;106}107 108static int m62332_write_raw(struct iio_dev *indio_dev,109			    struct iio_chan_spec const *chan, int val, int val2,110			    long mask)111{112	switch (mask) {113	case IIO_CHAN_INFO_RAW:114		if (val < 0 || val > 255)115			return -EINVAL;116 117		return m62332_set_value(indio_dev, val, chan->channel);118	default:119		break;120	}121 122	return -EINVAL;123}124 125static int m62332_suspend(struct device *dev)126{127	struct i2c_client *client = to_i2c_client(dev);128	struct iio_dev *indio_dev = i2c_get_clientdata(client);129	struct m62332_data *data = iio_priv(indio_dev);130	int ret;131 132	data->save[0] = data->raw[0];133	data->save[1] = data->raw[1];134 135	ret = m62332_set_value(indio_dev, 0, 0);136	if (ret < 0)137		return ret;138 139	return m62332_set_value(indio_dev, 0, 1);140}141 142static int m62332_resume(struct device *dev)143{144	struct i2c_client *client = to_i2c_client(dev);145	struct iio_dev *indio_dev = i2c_get_clientdata(client);146	struct m62332_data *data = iio_priv(indio_dev);147	int ret;148 149	ret = m62332_set_value(indio_dev, data->save[0], 0);150	if (ret < 0)151		return ret;152 153	return m62332_set_value(indio_dev, data->save[1], 1);154}155 156static DEFINE_SIMPLE_DEV_PM_OPS(m62332_pm_ops, m62332_suspend, m62332_resume);157 158static const struct iio_info m62332_info = {159	.read_raw = m62332_read_raw,160	.write_raw = m62332_write_raw,161};162 163#define M62332_CHANNEL(chan) {					\164	.type = IIO_VOLTAGE,					\165	.indexed = 1,						\166	.output = 1,						\167	.channel = (chan),					\168	.datasheet_name = "CH" #chan,				\169	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\170	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |	\171				    BIT(IIO_CHAN_INFO_OFFSET),	\172}173 174static const struct iio_chan_spec m62332_channels[M62332_CHANNELS] = {175	M62332_CHANNEL(0),176	M62332_CHANNEL(1)177};178 179static int m62332_probe(struct i2c_client *client)180{181	struct m62332_data *data;182	struct iio_dev *indio_dev;183	int ret;184 185	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));186	if (!indio_dev)187		return -ENOMEM;188 189	data = iio_priv(indio_dev);190	i2c_set_clientdata(client, indio_dev);191	data->client = client;192 193	mutex_init(&data->mutex);194 195	data->vcc = devm_regulator_get(&client->dev, "VCC");196	if (IS_ERR(data->vcc))197		return PTR_ERR(data->vcc);198 199	indio_dev->num_channels = ARRAY_SIZE(m62332_channels);200	indio_dev->channels = m62332_channels;201	indio_dev->modes = INDIO_DIRECT_MODE;202	indio_dev->info = &m62332_info;203 204	ret = iio_map_array_register(indio_dev, client->dev.platform_data);205	if (ret < 0)206		return ret;207 208	ret = iio_device_register(indio_dev);209	if (ret < 0)210		goto err;211 212	return 0;213 214err:215	iio_map_array_unregister(indio_dev);216 217	return ret;218}219 220static void m62332_remove(struct i2c_client *client)221{222	struct iio_dev *indio_dev = i2c_get_clientdata(client);223 224	iio_device_unregister(indio_dev);225	iio_map_array_unregister(indio_dev);226	m62332_set_value(indio_dev, 0, 0);227	m62332_set_value(indio_dev, 0, 1);228}229 230static const struct i2c_device_id m62332_id[] = {231	{ "m62332", },232	{ }233};234MODULE_DEVICE_TABLE(i2c, m62332_id);235 236static struct i2c_driver m62332_driver = {237	.driver = {238		.name	= "m62332",239		.pm	= pm_sleep_ptr(&m62332_pm_ops),240	},241	.probe		= m62332_probe,242	.remove		= m62332_remove,243	.id_table	= m62332_id,244};245module_i2c_driver(m62332_driver);246 247MODULE_AUTHOR("Dmitry Eremin-Solenikov");248MODULE_DESCRIPTION("M62332 8-bit DAC");249MODULE_LICENSE("GPL v2");250