mail archive of the barebox mailing list
 help / color / mirror / Atom feed
From: Sascha Hauer <s.hauer@pengutronix.de>
To: Barebox List <barebox@lists.infradead.org>
Subject: [PATCH 3/4] misc: Add Microchip MCP342x support
Date: Tue,  8 Dec 2015 10:05:38 +0100	[thread overview]
Message-ID: <1449565539-29374-4-git-send-email-s.hauer@pengutronix.de> (raw)
In-Reply-To: <1449565539-29374-1-git-send-email-s.hauer@pengutronix.de>

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/misc/Kconfig   |   5 +
 drivers/misc/Makefile  |   2 +
 drivers/misc/mcp342x.c | 259 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 266 insertions(+)
 create mode 100644 drivers/misc/mcp342x.c

diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index b95a7f6..8d44a5c 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -27,4 +27,9 @@ config LM75
 	depends on I2C
 	depends on IODEVICE
 
+config MCP342X
+	tristate "Microchip MCP342x ADC driver"
+	depends on I2C
+	depends on IODEVICE
+
 endmenu
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index a257dfb..6680334 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -7,3 +7,5 @@ obj-$(CONFIG_SRAM)		+= sram.o
 obj-$(CONFIG_STATE_DRV)		+= state.o
 obj-$(CONFIG_IODEVICE)		+= iodevice.o
 obj-$(CONFIG_LM75)		+= lm75.o
+obj-$(CONFIG_IODEVICE)		+= iodevice.o
+obj-$(CONFIG_MCP342X)		+= mcp342x.o
diff --git a/drivers/misc/mcp342x.c b/drivers/misc/mcp342x.c
new file mode 100644
index 0000000..e498078
--- /dev/null
+++ b/drivers/misc/mcp342x.c
@@ -0,0 +1,259 @@
+/*
+ * mcp3422.c - driver for the Microchip mcp3422/3/4/6/7/8 chip family
+ *
+ * Copyright (C) 2013, Angelo Compagnucci
+ * Author: Angelo Compagnucci <angelo.compagnucci@gmail.com>
+ *
+ * Datasheet: http://ww1.microchip.com/downloads/en/devicedoc/22088b.pdf
+ *            http://ww1.microchip.com/downloads/en/DeviceDoc/22226a.pdf
+ *
+ * This driver exports the value of analog input voltage to sysfs, the
+ * voltage unit is nV.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <common.h>
+#include <init.h>
+#include <iodevice.h>
+#include <malloc.h>
+#include <driver.h>
+#include <xfuncs.h>
+#include <i2c/i2c.h>
+
+/* Masks */
+#define MCP3422_CHANNEL_MASK	0x60
+#define MCP3422_PGA_MASK	0x03
+#define MCP3422_SRATE_MASK	0x0C
+#define MCP3422_SRATE_240	0x0
+#define MCP3422_SRATE_60	0x1
+#define MCP3422_SRATE_15	0x2
+#define MCP3422_SRATE_3		0x3
+#define MCP3422_PGA_1	0
+#define MCP3422_PGA_2	1
+#define MCP3422_PGA_4	2
+#define MCP3422_PGA_8	3
+#define MCP3422_CONT_SAMPLING	0x10
+
+#define MCP3422_CHANNEL(config)	(((config) & MCP3422_CHANNEL_MASK) >> 5)
+#define MCP3422_PGA(config)	((config) & MCP3422_PGA_MASK)
+#define MCP3422_SAMPLE_RATE(config)	(((config) & MCP3422_SRATE_MASK) >> 2)
+
+#define MCP3422_CHANNEL_VALUE(value) (((value) << 5) & MCP3422_CHANNEL_MASK)
+#define MCP3422_PGA_VALUE(value) ((value) & MCP3422_PGA_MASK)
+#define MCP3422_SAMPLE_RATE_VALUE(value) ((value << 2) & MCP3422_SRATE_MASK)
+
+/* Constant msleep times for data acquisitions */
+static const int mcp3422_read_times[4] = {
+	[MCP3422_SRATE_240] = 1000 / 240,
+	[MCP3422_SRATE_60] = 1000 / 60,
+	[MCP3422_SRATE_15] = 1000 / 15,
+	[MCP3422_SRATE_3] = 1000 / 3 };
+
+static const int mcp3422_sample_rate_scales[4] = {
+	[MCP3422_SRATE_240] = 8000,
+	[MCP3422_SRATE_60] = 2000,
+	[MCP3422_SRATE_15] = 500,
+	[MCP3422_SRATE_3] =  125};
+
+static const char *mcp342x_sample_rate_str[] = {
+	"240", "60", "15", "3"
+};
+
+static const char *mcp342x_gain_str[] = {
+	"1", "2", "4", "8"
+};
+
+/* sample rates to sign extension table */
+static const int mcp3422_sign_extend[4] = {
+	[MCP3422_SRATE_240] = 11,
+	[MCP3422_SRATE_60] = 13,
+	[MCP3422_SRATE_15] = 15,
+	[MCP3422_SRATE_3] = 17 };
+
+struct mcp342x_channel {
+	int num;
+	int voltage;
+	int temp;
+	struct mcp342x *mcp342x;
+	struct iochannel iochan;
+	unsigned int gain;
+};
+
+struct mcp342x {
+	struct i2c_client *i2c;
+	struct iodevice iodev;
+	unsigned int sps;
+	u8 id;
+	u8 config;
+	u8 pga[4];
+	int num_channels;
+	struct mcp342x_channel *channel[4];
+	char *unit;
+};
+
+static int mcp3422_update_config(struct mcp342x *adc, u8 newconfig)
+{
+	int ret;
+
+	ret = i2c_master_send(adc->i2c, &newconfig, 1);
+	if (ret > 0) {
+		adc->config = newconfig;
+		ret = 0;
+	}
+
+	return ret;
+}
+
+static int mcp3422_read(struct mcp342x_channel *channel)
+{
+	struct mcp342x *adc = channel->mcp342x;
+	int ret = 0;
+	u8 sample_rate = MCP3422_SAMPLE_RATE(adc->config);
+	u8 buf[4] = {0, 0, 0, 0};
+	u32 temp;
+
+	if (sample_rate == MCP3422_SRATE_3) {
+		ret = i2c_master_recv(adc->i2c, buf, 4);
+		temp = buf[0] << 16 | buf[1] << 8 | buf[2];
+	} else {
+		ret = i2c_master_recv(adc->i2c, buf, 3);
+		temp = buf[0] << 8 | buf[1];
+	}
+
+	channel->voltage = sign_extend32(temp, mcp3422_sign_extend[sample_rate]) *
+			mcp3422_sample_rate_scales[sample_rate] / (1 << channel->gain) / 8;
+
+	return ret;
+}
+
+static int mcp342x_get_voltage(struct iochannel *iochan, int *value)
+{
+	struct mcp342x_channel *channel = container_of(iochan, struct mcp342x_channel, iochan);
+	struct mcp342x *adc = channel->mcp342x;
+	u8 config;
+	int ret;
+
+	config = MCP3422_CONT_SAMPLING |
+		MCP3422_CHANNEL_VALUE(channel->num) |
+		MCP3422_PGA_VALUE(channel->gain) |
+		MCP3422_SAMPLE_RATE_VALUE(adc->sps);
+
+	if (config != adc->config) {
+		ret = mcp3422_update_config(adc, config);
+		if (ret < 0)
+			return ret;
+
+		mdelay(mcp3422_read_times[MCP3422_SAMPLE_RATE(adc->config)]);
+	}
+
+	mcp3422_read(channel);
+
+	*value = channel->voltage;
+
+	return 0;
+}
+
+static int mcp342x_probe(struct device_d *dev)
+{
+	struct mcp342x *adc;
+	int id , ret, i, num_channels;
+
+	ret = dev_get_drvdata(dev, (const void **)&id);
+	if (ret)
+		return ret;
+
+	adc = xzalloc(sizeof(*adc));
+
+	adc->i2c = to_i2c_client(dev);
+	adc->id = id;
+	adc->unit = "uV";
+
+	switch (id) {
+	case 1:
+		num_channels = 1;
+		break;
+	case 2:
+	case 3:
+	case 6:
+	case 7:
+		num_channels = 2;
+		break;
+	case 4:
+	case 8:
+		num_channels = 4;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	adc->num_channels = num_channels;
+
+	adc->sps = MCP3422_SRATE_15;
+
+	adc->iodev.hwdev = dev;
+
+	adc->iodev.channels = xmalloc(sizeof(void *) * num_channels);
+	adc->iodev.num_channels = num_channels;
+	adc->iodev.read = mcp342x_get_voltage;
+
+	for (i = 0; i < num_channels; i++) {
+		struct mcp342x_channel *channel;
+
+		channel = xzalloc(sizeof(*channel));
+		adc->iodev.channels[i] = &channel->iochan;
+		channel->iochan.unit = "uV";
+		adc->channel[i] = channel;
+		channel->num = i;
+		channel->mcp342x = adc;
+	}
+
+	ret = iodevice_register(&adc->iodev);
+	if (ret)
+		return ret;
+
+	dev_add_param_enum(&adc->iodev.dev, "in_sps", NULL, NULL, &adc->sps,
+			   mcp342x_sample_rate_str,
+			   ARRAY_SIZE(mcp342x_sample_rate_str), NULL);
+
+	for (i = 0; i < num_channels; i++) {
+		struct mcp342x_channel *channel = adc->channel[i];
+		char *name;
+
+		name = asprintf("in_gain%d", i);
+		dev_add_param_enum(&adc->iodev.dev, name, NULL, NULL, &channel->gain,
+			   mcp342x_gain_str,
+			   ARRAY_SIZE(mcp342x_gain_str), NULL);
+		free(name);
+	}
+
+	return 0;
+}
+
+static const struct platform_device_id mcp342x_ids[] = {
+	{ "mcp3421", 1 },
+	{ "mcp3422", 2 },
+	{ "mcp3423", 3 },
+	{ "mcp3424", 4 },
+	{ "mcp3426", 6 },
+	{ "mcp3427", 7 },
+	{ "mcp3428", 8 },
+	{ }
+};
+
+static struct driver_d mcp342x_driver = {
+	.name  = "mcp342x",
+	.probe = mcp342x_probe,
+	.id_table = mcp342x_ids,
+};
+
+static int mcp342x_init(void)
+{
+	i2c_driver_register(&mcp342x_driver);
+	return 0;
+}
+
+device_initcall(mcp342x_init);
-- 
2.6.2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

  parent reply	other threads:[~2015-12-08  9:05 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-12-08  9:05 [RFC] iodevice support Sascha Hauer
2015-12-08  9:05 ` [PATCH 1/4] misc: Add " Sascha Hauer
2015-12-10 20:42   ` Trent Piepho
2015-12-11  7:37     ` Sascha Hauer
2015-12-08  9:05 ` [PATCH 2/4] misc: Add basic LM75 temperature driver Sascha Hauer
2015-12-08  9:05 ` Sascha Hauer [this message]
2015-12-08  9:05 ` [PATCH 4/4] misc: Add PT100 temperature sensor support Sascha Hauer
2015-12-10  6:24 ` [RFC] iodevice support Andrey Smirnov
2015-12-10 10:25   ` Sascha Hauer

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1449565539-29374-4-git-send-email-s.hauer@pengutronix.de \
    --to=s.hauer@pengutronix.de \
    --cc=barebox@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox