brintos

brintos / linux-shallow public Read only

0
0
Text · 5.1 KiB · 7353484 Raw
221 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 *4 * x9250.c  --  Renesas X9250 potentiometers IIO driver5 *6 * Copyright 2023 CS GROUP France7 *8 * Author: Herve Codina <herve.codina@bootlin.com>9 */10 11#include <linux/delay.h>12#include <linux/gpio/consumer.h>13#include <linux/iio/iio.h>14#include <linux/limits.h>15#include <linux/module.h>16#include <linux/regulator/consumer.h>17#include <linux/slab.h>18#include <linux/spi/spi.h>19 20struct x9250_cfg {21	const char *name;22	int kohms;23};24 25struct x9250 {26	struct spi_device *spi;27	const struct x9250_cfg *cfg;28	struct gpio_desc *wp_gpio;29};30 31#define X9250_ID		0x5032#define X9250_CMD_RD_WCR(_p)    (0x90 | (_p))33#define X9250_CMD_WR_WCR(_p)    (0xa0 | (_p))34 35static int x9250_write8(struct x9250 *x9250, u8 cmd, u8 val)36{37	u8 txbuf[3];38 39	txbuf[0] = X9250_ID;40	txbuf[1] = cmd;41	txbuf[2] = val;42 43	return spi_write_then_read(x9250->spi, txbuf, ARRAY_SIZE(txbuf), NULL, 0);44}45 46static int x9250_read8(struct x9250 *x9250, u8 cmd, u8 *val)47{48	u8 txbuf[2];49 50	txbuf[0] = X9250_ID;51	txbuf[1] = cmd;52 53	return spi_write_then_read(x9250->spi, txbuf, ARRAY_SIZE(txbuf), val, 1);54}55 56#define X9250_CHANNEL(ch) {						\57	.type = IIO_RESISTANCE,						\58	.indexed = 1,							\59	.output = 1,							\60	.channel = (ch),						\61	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),			\62	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),		\63	.info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_RAW),	\64}65 66static const struct iio_chan_spec x9250_channels[] = {67	X9250_CHANNEL(0),68	X9250_CHANNEL(1),69	X9250_CHANNEL(2),70	X9250_CHANNEL(3),71};72 73static int x9250_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan,74			  int *val, int *val2, long mask)75{76	struct x9250 *x9250 = iio_priv(indio_dev);77	int ch = chan->channel;78	int ret;79	u8 v;80 81	switch (mask) {82	case IIO_CHAN_INFO_RAW:83		ret = x9250_read8(x9250, X9250_CMD_RD_WCR(ch), &v);84		if (ret)85			return ret;86		*val = v;87		return IIO_VAL_INT;88 89	case IIO_CHAN_INFO_SCALE:90		*val = 1000 * x9250->cfg->kohms;91		*val2 = U8_MAX;92		return IIO_VAL_FRACTIONAL;93	}94 95	return -EINVAL;96}97 98static int x9250_read_avail(struct iio_dev *indio_dev, struct iio_chan_spec const *chan,99			    const int **vals, int *type, int *length, long mask)100{101	static const int range[] = {0, 1, 255}; /* min, step, max */102 103	switch (mask) {104	case IIO_CHAN_INFO_RAW:105		*length = ARRAY_SIZE(range);106		*vals = range;107		*type = IIO_VAL_INT;108		return IIO_AVAIL_RANGE;109	}110 111	return -EINVAL;112}113 114static int x9250_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan,115			   int val, int val2, long mask)116{117	struct x9250 *x9250 = iio_priv(indio_dev);118	int ch = chan->channel;119	int ret;120 121	if (mask != IIO_CHAN_INFO_RAW)122		return -EINVAL;123 124	if (val > U8_MAX || val < 0)125		return -EINVAL;126 127	gpiod_set_value_cansleep(x9250->wp_gpio, 0);128	ret = x9250_write8(x9250, X9250_CMD_WR_WCR(ch), val);129	gpiod_set_value_cansleep(x9250->wp_gpio, 1);130 131	return ret;132}133 134static const struct iio_info x9250_info = {135	.read_raw = x9250_read_raw,136	.read_avail = x9250_read_avail,137	.write_raw = x9250_write_raw,138};139 140enum x9250_type {141	X9250T,142	X9250U,143};144 145static const struct x9250_cfg x9250_cfg[] = {146	[X9250T] = { .name = "x9250t", .kohms =  100, },147	[X9250U] = { .name = "x9250u", .kohms =  50, },148};149 150static const char *const x9250_regulator_names[] = {151	"vcc",152	"avp",153	"avn",154};155 156static int x9250_probe(struct spi_device *spi)157{158	struct iio_dev *indio_dev;159	struct x9250 *x9250;160	int ret;161 162	ret = devm_regulator_bulk_get_enable(&spi->dev, ARRAY_SIZE(x9250_regulator_names),163					     x9250_regulator_names);164	if (ret)165		return dev_err_probe(&spi->dev, ret, "Failed to get regulators\n");166 167	/*168	 * The x9250 needs a 5ms maximum delay after the power-supplies are set169	 * before performing the first write (1ms for the first read).170	 */171	usleep_range(5000, 6000);172 173	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*x9250));174	if (!indio_dev)175		return -ENOMEM;176 177	x9250 = iio_priv(indio_dev);178	x9250->spi = spi;179	x9250->cfg = spi_get_device_match_data(spi);180	x9250->wp_gpio = devm_gpiod_get_optional(&spi->dev, "wp", GPIOD_OUT_LOW);181	if (IS_ERR(x9250->wp_gpio))182		return dev_err_probe(&spi->dev, PTR_ERR(x9250->wp_gpio),183				     "failed to get wp gpio\n");184 185	indio_dev->info = &x9250_info;186	indio_dev->channels = x9250_channels;187	indio_dev->num_channels = ARRAY_SIZE(x9250_channels);188	indio_dev->name = x9250->cfg->name;189 190	return devm_iio_device_register(&spi->dev, indio_dev);191}192 193static const struct of_device_id x9250_of_match[] = {194	{ .compatible = "renesas,x9250t", .data = &x9250_cfg[X9250T]},195	{ .compatible = "renesas,x9250u", .data = &x9250_cfg[X9250U]},196	{ }197};198MODULE_DEVICE_TABLE(of, x9250_of_match);199 200static const struct spi_device_id x9250_id_table[] = {201	{ "x9250t", (kernel_ulong_t)&x9250_cfg[X9250T] },202	{ "x9250u", (kernel_ulong_t)&x9250_cfg[X9250U] },203	{ }204};205MODULE_DEVICE_TABLE(spi, x9250_id_table);206 207static struct spi_driver x9250_spi_driver = {208	.driver  = {209		.name = "x9250",210		.of_match_table = x9250_of_match,211	},212	.id_table = x9250_id_table,213	.probe  = x9250_probe,214};215 216module_spi_driver(x9250_spi_driver);217 218MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>");219MODULE_DESCRIPTION("X9250 ALSA SoC driver");220MODULE_LICENSE("GPL");221