aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorXie Xiaobo <X.Xie@freescale.com>2012-03-23 05:02:20 -0400
committerJean Delvare <khali@endymion.delvare>2012-03-23 05:02:20 -0400
commit5510e62a66bad22b104d5d854445523d7f5754f7 (patch)
treea580bd3fff0831628bc0d525d975853bbf25a86d
parent0c2732152a5813a870d0b96f0844f4dfe1436519 (diff)
hwmon: Add MCP3021 ADC driver
Add I2C driver for MCP3021 that is an ADC chip from Microchip. The MCP3021 is a successive approximation A/D converter (ADC) with 10-bit resolution. The driver export the value of Vin to sysfs, the voltage unit is mV. Through the sysfs interface, lm-sensors tool can also display Vin voltage. Signed-off-by: Mingkai Hu <Mingkai.hu@freescale.com> Signed-off-by: Xie Xiaobo <X.Xie@freescale.com> Signed-off-by: Jean Delvare <khali@linux-fr.org>
-rw-r--r--Documentation/hwmon/mcp302122
-rw-r--r--drivers/hwmon/Kconfig10
-rw-r--r--drivers/hwmon/Makefile1
-rw-r--r--drivers/hwmon/mcp3021.c171
4 files changed, 204 insertions, 0 deletions
diff --git a/Documentation/hwmon/mcp3021 b/Documentation/hwmon/mcp3021
new file mode 100644
index 000000000000..325fd87e81b2
--- /dev/null
+++ b/Documentation/hwmon/mcp3021
@@ -0,0 +1,22 @@
1Kernel driver MCP3021
2======================
3
4Supported chips:
5 * Microchip Technology MCP3021
6 Prefix: 'mcp3021'
7 Datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/21805a.pdf
8
9Author: Mingkai Hu
10
11Description
12-----------
13
14This driver implements support for the Microchip Technology MCP3021 chip.
15
16The Microchip Technology Inc. MCP3021 is a successive approximation A/D
17converter (ADC) with 10-bit resolution.
18This device provides one single-ended input with very low power consumption.
19Communication to the MCP3021 is performed using a 2-wire I2C compatible
20interface. Standard (100 kHz) and Fast (400 kHz) I2C modes are available.
21The default I2C device address is 0x4d (contact the Microchip factory for
22additional address options).
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 7190a3f4a827..5b32d56dbb4d 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -813,6 +813,16 @@ config SENSORS_MAX6650
813 This driver can also be built as a module. If so, the module 813 This driver can also be built as a module. If so, the module
814 will be called max6650. 814 will be called max6650.
815 815
816config SENSORS_MCP3021
817 tristate "Microchip MCP3021"
818 depends on I2C && EXPERIMENTAL
819 help
820 If you say yes here you get support for the MCP3021 chip
821 that is a A/D converter (ADC) with 10-bit resolution.
822
823 This driver can also be built as a module. If so, the module
824 will be called mcp3021.
825
816config SENSORS_NTC_THERMISTOR 826config SENSORS_NTC_THERMISTOR
817 tristate "NTC thermistor support" 827 tristate "NTC thermistor support"
818 depends on EXPERIMENTAL 828 depends on EXPERIMENTAL
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 8251ce8cd035..6d3f11f71815 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -95,6 +95,7 @@ obj-$(CONFIG_SENSORS_MAX6639) += max6639.o
95obj-$(CONFIG_SENSORS_MAX6642) += max6642.o 95obj-$(CONFIG_SENSORS_MAX6642) += max6642.o
96obj-$(CONFIG_SENSORS_MAX6650) += max6650.o 96obj-$(CONFIG_SENSORS_MAX6650) += max6650.o
97obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o 97obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o
98obj-$(CONFIG_SENSORS_MCP3021) += mcp3021.o
98obj-$(CONFIG_SENSORS_NTC_THERMISTOR) += ntc_thermistor.o 99obj-$(CONFIG_SENSORS_NTC_THERMISTOR) += ntc_thermistor.o
99obj-$(CONFIG_SENSORS_PC87360) += pc87360.o 100obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
100obj-$(CONFIG_SENSORS_PC87427) += pc87427.o 101obj-$(CONFIG_SENSORS_PC87427) += pc87427.o
diff --git a/drivers/hwmon/mcp3021.c b/drivers/hwmon/mcp3021.c
new file mode 100644
index 000000000000..d0afc0cd3ff4
--- /dev/null
+++ b/drivers/hwmon/mcp3021.c
@@ -0,0 +1,171 @@
1/*
2 * mcp3021.c - driver for the Microchip MCP3021 chip
3 *
4 * Copyright (C) 2008-2009, 2012 Freescale Semiconductor, Inc.
5 * Author: Mingkai Hu <Mingkai.hu@freescale.com>
6 *
7 * This driver export the value of analog input voltage to sysfs, the
8 * voltage unit is mV. Through the sysfs interface, lm-sensors tool
9 * can also display the input voltage.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 */
16
17#include <linux/kernel.h>
18#include <linux/module.h>
19#include <linux/hwmon.h>
20#include <linux/slab.h>
21#include <linux/i2c.h>
22#include <linux/err.h>
23#include <linux/device.h>
24
25/* Vdd info */
26#define MCP3021_VDD_MAX 5500
27#define MCP3021_VDD_MIN 2700
28#define MCP3021_VDD_REF 3300
29
30/* output format */
31#define MCP3021_SAR_SHIFT 2
32#define MCP3021_SAR_MASK 0x3ff
33
34#define MCP3021_OUTPUT_RES 10 /* 10-bit resolution */
35#define MCP3021_OUTPUT_SCALE 4
36
37/*
38 * Client data (each client gets its own)
39 */
40struct mcp3021_data {
41 struct device *hwmon_dev;
42 u32 vdd; /* device power supply */
43};
44
45static int mcp3021_read16(struct i2c_client *client)
46{
47 int ret;
48 u16 reg;
49 __be16 buf;
50
51 ret = i2c_master_recv(client, (char *)&buf, 2);
52 if (ret < 0)
53 return ret;
54 if (ret != 2)
55 return -EIO;
56
57 /* The output code of the MCP3021 is transmitted with MSB first. */
58 reg = be16_to_cpu(buf);
59
60 /*
61 * The ten-bit output code is composed of the lower 4-bit of the
62 * first byte and the upper 6-bit of the second byte.
63 */
64 reg = (reg >> MCP3021_SAR_SHIFT) & MCP3021_SAR_MASK;
65
66 return reg;
67}
68
69static inline u16 volts_from_reg(u16 vdd, u16 val)
70{
71 if (val == 0)
72 return 0;
73
74 val = val * MCP3021_OUTPUT_SCALE - MCP3021_OUTPUT_SCALE / 2;
75
76 return val * DIV_ROUND_CLOSEST(vdd,
77 (1 << MCP3021_OUTPUT_RES) * MCP3021_OUTPUT_SCALE);
78}
79
80static ssize_t show_in_input(struct device *dev, struct device_attribute *attr,
81 char *buf)
82{
83 struct i2c_client *client = to_i2c_client(dev);
84 struct mcp3021_data *data = i2c_get_clientdata(client);
85 int reg, in_input;
86
87 reg = mcp3021_read16(client);
88 if (reg < 0)
89 return reg;
90
91 in_input = volts_from_reg(data->vdd, reg);
92 return sprintf(buf, "%d\n", in_input);
93}
94
95static DEVICE_ATTR(in0_input, S_IRUGO, show_in_input, NULL);
96
97static int mcp3021_probe(struct i2c_client *client,
98 const struct i2c_device_id *id)
99{
100 int err;
101 struct mcp3021_data *data = NULL;
102
103 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
104 return -ENODEV;
105
106 data = kzalloc(sizeof(struct mcp3021_data), GFP_KERNEL);
107 if (!data)
108 return -ENOMEM;
109
110 i2c_set_clientdata(client, data);
111
112 if (client->dev.platform_data) {
113 data->vdd = *(u32 *)client->dev.platform_data;
114 if (data->vdd > MCP3021_VDD_MAX ||
115 data->vdd < MCP3021_VDD_MIN) {
116 err = -EINVAL;
117 goto exit_free;
118 }
119 } else
120 data->vdd = MCP3021_VDD_REF;
121
122 err = sysfs_create_file(&client->dev.kobj, &dev_attr_in0_input.attr);
123 if (err)
124 goto exit_free;
125
126 data->hwmon_dev = hwmon_device_register(&client->dev);
127 if (IS_ERR(data->hwmon_dev)) {
128 err = PTR_ERR(data->hwmon_dev);
129 goto exit_remove;
130 }
131
132 return 0;
133
134exit_remove:
135 sysfs_remove_file(&client->dev.kobj, &dev_attr_in0_input.attr);
136exit_free:
137 kfree(data);
138 return err;
139}
140
141static int mcp3021_remove(struct i2c_client *client)
142{
143 struct mcp3021_data *data = i2c_get_clientdata(client);
144
145 hwmon_device_unregister(data->hwmon_dev);
146 sysfs_remove_file(&client->dev.kobj, &dev_attr_in0_input.attr);
147 kfree(data);
148
149 return 0;
150}
151
152static const struct i2c_device_id mcp3021_id[] = {
153 { "mcp3021", 0 },
154 { }
155};
156MODULE_DEVICE_TABLE(i2c, mcp3021_id);
157
158static struct i2c_driver mcp3021_driver = {
159 .driver = {
160 .name = "mcp3021",
161 },
162 .probe = mcp3021_probe,
163 .remove = mcp3021_remove,
164 .id_table = mcp3021_id,
165};
166
167module_i2c_driver(mcp3021_driver);
168
169MODULE_AUTHOR("Mingkai Hu <Mingkai.hu@freescale.com>");
170MODULE_DESCRIPTION("Microchip MCP3021 driver");
171MODULE_LICENSE("GPL");