Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6c536e4c authored by Michael Hennerich's avatar Michael Hennerich Committed by Linus Torvalds
Browse files

ad525x_dpot: add support for SPI parts



Split the bus logic out into separate files so that we can handle I2C and
SPI busses independently.  The new SPI bus logic brings in support for a
lot more parts:

	AD5160, AD5161, AD5162, AD5165, AD5200, AD5201, AD5203,
	AD5204, AD5206, AD5207, AD5231, AD5232, AD5233, AD5235,
	AD5260, AD5262, AD5263, AD5290, AD5291, AD5292, AD5293,
	AD7376, AD8400, AD8402, AD8403, ADN2850

[randy.dunlap@oracle.com: fix ad525X_dpot build]
Signed-off-by: default avatarMichael Hennerich <michael.hennerich@analog.com>
Signed-off-by: default avatarMike Frysinger <vapier@gentoo.org>
Signed-off-by: default avatarRandy Dunlap <randy.dunlap@oracle.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 0c53b9fb
Loading
Loading
Loading
Loading
+27 −3
Original line number Diff line number Diff line
@@ -14,11 +14,15 @@ menuconfig MISC_DEVICES
if MISC_DEVICES

config AD525X_DPOT
	tristate "Analog Devices AD525x Digital Potentiometers"
	depends on I2C && SYSFS
	tristate "Analog Devices Digital Potentiometers"
	depends on (I2C || SPI) && SYSFS
	help
	  If you say yes here, you get support for the Analog Devices
	  AD5258, AD5259, AD5251, AD5252, AD5253, AD5254 and AD5255
	  AD5258, AD5259, AD5251, AD5252, AD5253, AD5254, AD5255
	  AD5160, AD5161, AD5162, AD5165, AD5200, AD5201, AD5203,
	  AD5204, AD5206, AD5207, AD5231, AD5232, AD5233, AD5235,
	  AD5260, AD5262, AD5263, AD5290, AD5291, AD5292, AD5293,
	  AD7376, AD8400, AD8402, AD8403, ADN2850
	  digital potentiometer chips.

	  See Documentation/misc-devices/ad525x_dpot.txt for the
@@ -27,6 +31,26 @@ config AD525X_DPOT
	  This driver can also be built as a module.  If so, the module
	  will be called ad525x_dpot.

config AD525X_DPOT_I2C
	tristate "support I2C bus connection"
	depends on AD525X_DPOT && I2C
	help
	  Say Y here if you have a digital potentiometers hooked to an I2C bus.

	  To compile this driver as a module, choose M here: the
	  module will be called ad525x_dpot-i2c.

config AD525X_DPOT_SPI
	tristate "support SPI bus connection"
	depends on AD525X_DPOT && SPI_MASTER
	help
	  Say Y here if you have a digital potentiometers hooked to an SPI bus.

	  If unsure, say N (but it's safe to say "Y").

	  To compile this driver as a module, choose M here: the
	  module will be called ad525x_dpot-spi.

config ATMEL_PWM
	tristate "Atmel AT32/AT91 PWM support"
	depends on AVR32 || ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || ARCH_AT91CAP9
+2 −0
Original line number Diff line number Diff line
@@ -4,6 +4,8 @@

obj-$(CONFIG_IBM_ASM)		+= ibmasm/
obj-$(CONFIG_AD525X_DPOT)	+= ad525x_dpot.o
obj-$(CONFIG_AD525X_DPOT_I2C)	+= ad525x_dpot-i2c.o
obj-$(CONFIG_AD525X_DPOT_SPI)	+= ad525x_dpot-spi.o
obj-$(CONFIG_ATMEL_PWM)		+= atmel_pwm.o
obj-$(CONFIG_ATMEL_SSC)		+= atmel-ssc.o
obj-$(CONFIG_ATMEL_TCLIB)	+= atmel_tclib.o
+119 −0
Original line number Diff line number Diff line
/*
 * Driver for the Analog Devices digital potentiometers (I2C bus)
 *
 * Copyright (C) 2010 Michael Hennerich, Analog Devices Inc.
 *
 * Licensed under the GPL-2 or later.
 */

#include <linux/i2c.h>
#include <linux/module.h>

#include "ad525x_dpot.h"

/* ------------------------------------------------------------------------- */
/* I2C bus functions */
static int write_d8(void *client, u8 val)
{
	return i2c_smbus_write_byte(client, val);
}

static int write_r8d8(void *client, u8 reg, u8 val)
{
	return i2c_smbus_write_byte_data(client, reg, val);
}

static int write_r8d16(void *client, u8 reg, u16 val)
{
	return i2c_smbus_write_word_data(client, reg, val);
}

static int read_d8(void *client)
{
	return i2c_smbus_read_byte(client);
}

static int read_r8d8(void *client, u8 reg)
{
	return i2c_smbus_read_byte_data(client, reg);
}

static int read_r8d16(void *client, u8 reg)
{
	return i2c_smbus_read_word_data(client, reg);
}

static const struct ad_dpot_bus_ops bops = {
	.read_d8	= read_d8,
	.read_r8d8	= read_r8d8,
	.read_r8d16	= read_r8d16,
	.write_d8	= write_d8,
	.write_r8d8	= write_r8d8,
	.write_r8d16	= write_r8d16,
};

static int __devinit ad_dpot_i2c_probe(struct i2c_client *client,
				      const struct i2c_device_id *id)
{
	struct ad_dpot_bus_data bdata = {
		.client = client,
		.bops = &bops,
	};

	struct ad_dpot_id dpot_id = {
		.name = (char *) &id->name,
		.devid = id->driver_data,
	};

	if (!i2c_check_functionality(client->adapter,
				     I2C_FUNC_SMBUS_WORD_DATA)) {
		dev_err(&client->dev, "SMBUS Word Data not Supported\n");
		return -EIO;
	}

	return ad_dpot_probe(&client->dev, &bdata, &dpot_id);
}

static int __devexit ad_dpot_i2c_remove(struct i2c_client *client)
{
	return ad_dpot_remove(&client->dev);
}

static const struct i2c_device_id ad_dpot_id[] = {
	{"ad5258", AD5258_ID},
	{"ad5259", AD5259_ID},
	{"ad5251", AD5251_ID},
	{"ad5252", AD5252_ID},
	{"ad5253", AD5253_ID},
	{"ad5254", AD5254_ID},
	{"ad5255", AD5255_ID},
	{}
};
MODULE_DEVICE_TABLE(i2c, ad_dpot_id);

static struct i2c_driver ad_dpot_i2c_driver = {
	.driver = {
		.name	= "ad_dpot",
		.owner	= THIS_MODULE,
	},
	.probe		= ad_dpot_i2c_probe,
	.remove		= __devexit_p(ad_dpot_i2c_remove),
	.id_table	= ad_dpot_id,
};

static int __init ad_dpot_i2c_init(void)
{
	return i2c_add_driver(&ad_dpot_i2c_driver);
}
module_init(ad_dpot_i2c_init);

static void __exit ad_dpot_i2c_exit(void)
{
	i2c_del_driver(&ad_dpot_i2c_driver);
}
module_exit(ad_dpot_i2c_exit);

MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_DESCRIPTION("digital potentiometer I2C bus driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("i2c:ad_dpot");
+172 −0
Original line number Diff line number Diff line
/*
 * Driver for the Analog Devices digital potentiometers (SPI bus)
 *
 * Copyright (C) 2010 Michael Hennerich, Analog Devices Inc.
 *
 * Licensed under the GPL-2 or later.
 */

#include <linux/spi/spi.h>
#include <linux/module.h>

#include "ad525x_dpot.h"

static const struct ad_dpot_id ad_dpot_spi_devlist[] = {
	{.name = "ad5160", .devid = AD5160_ID},
	{.name = "ad5161", .devid = AD5161_ID},
	{.name = "ad5162", .devid = AD5162_ID},
	{.name = "ad5165", .devid = AD5165_ID},
	{.name = "ad5200", .devid = AD5200_ID},
	{.name = "ad5201", .devid = AD5201_ID},
	{.name = "ad5203", .devid = AD5203_ID},
	{.name = "ad5204", .devid = AD5204_ID},
	{.name = "ad5206", .devid = AD5206_ID},
	{.name = "ad5207", .devid = AD5207_ID},
	{.name = "ad5231", .devid = AD5231_ID},
	{.name = "ad5232", .devid = AD5232_ID},
	{.name = "ad5233", .devid = AD5233_ID},
	{.name = "ad5235", .devid = AD5235_ID},
	{.name = "ad5260", .devid = AD5260_ID},
	{.name = "ad5262", .devid = AD5262_ID},
	{.name = "ad5263", .devid = AD5263_ID},
	{.name = "ad5290", .devid = AD5290_ID},
	{.name = "ad5291", .devid = AD5291_ID},
	{.name = "ad5292", .devid = AD5292_ID},
	{.name = "ad5293", .devid = AD5293_ID},
	{.name = "ad7376", .devid = AD7376_ID},
	{.name = "ad8400", .devid = AD8400_ID},
	{.name = "ad8402", .devid = AD8402_ID},
	{.name = "ad8403", .devid = AD8403_ID},
	{.name = "adn2850", .devid = ADN2850_ID},
	{}
};

/* ------------------------------------------------------------------------- */

/* SPI bus functions */
static int write8(void *client, u8 val)
{
	u8 data = val;
	return spi_write(client, &data, 1);
}

static int write16(void *client, u8 reg, u8 val)
{
	u8 data[2] = {reg, val};
	return spi_write(client, data, 1);
}

static int write24(void *client, u8 reg, u16 val)
{
	u8 data[3] = {reg, val >> 8, val};
	return spi_write(client, data, 1);
}

static int read8(void *client)
{
	int ret;
	u8 data;
	ret = spi_read(client, &data, 1);
	if (ret < 0)
		return ret;

	return data;
}

static int read16(void *client, u8 reg)
{
	int ret;
	u8 buf_rx[2];

	write16(client, reg, 0);
	ret = spi_read(client, buf_rx, 2);
	if (ret < 0)
		return ret;

	return (buf_rx[0] << 8) |  buf_rx[1];
}

static int read24(void *client, u8 reg)
{
	int ret;
	u8 buf_rx[3];

	write24(client, reg, 0);
	ret = spi_read(client, buf_rx, 3);
	if (ret < 0)
		return ret;

	return (buf_rx[1] << 8) |  buf_rx[2];
}

static const struct ad_dpot_bus_ops bops = {
	.read_d8	= read8,
	.read_r8d8	= read16,
	.read_r8d16	= read24,
	.write_d8	= write8,
	.write_r8d8	= write16,
	.write_r8d16	= write24,
};

static const struct ad_dpot_id *dpot_match_id(const struct ad_dpot_id *id,
						char *name)
{
	while (id->name && id->name[0]) {
		if (strcmp(name, id->name) == 0)
			return id;
		id++;
	}
	return NULL;
}

static int __devinit ad_dpot_spi_probe(struct spi_device *spi)
{
	char *name = spi->dev.platform_data;
	const struct ad_dpot_id *dpot_id;

	struct ad_dpot_bus_data bdata = {
		.client = spi,
		.bops = &bops,
	};

	dpot_id = dpot_match_id(ad_dpot_spi_devlist, name);

	if (dpot_id == NULL) {
		dev_err(&spi->dev, "%s not in supported device list", name);
		return -ENODEV;
	}

	return ad_dpot_probe(&spi->dev, &bdata, dpot_id);
}

static int __devexit ad_dpot_spi_remove(struct spi_device *spi)
{
	return ad_dpot_remove(&spi->dev);
}

static struct spi_driver ad_dpot_spi_driver = {
	.driver = {
		.name	= "ad_dpot",
		.bus	= &spi_bus_type,
		.owner	= THIS_MODULE,
	},
	.probe		= ad_dpot_spi_probe,
	.remove		= __devexit_p(ad_dpot_spi_remove),
};

static int __init ad_dpot_spi_init(void)
{
	return spi_register_driver(&ad_dpot_spi_driver);
}
module_init(ad_dpot_spi_init);

static void __exit ad_dpot_spi_exit(void)
{
	spi_unregister_driver(&ad_dpot_spi_driver);
}
module_exit(ad_dpot_spi_exit);

MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_DESCRIPTION("digital potentiometer SPI bus driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("spi:ad_dpot");
+313 −316

File changed.

Preview size limit exceeded, changes collapsed.

Loading