diff options
| author | Xie Xiaobo <X.Xie@freescale.com> | 2012-03-23 05:02:20 -0400 |
|---|---|---|
| committer | Jean Delvare <khali@endymion.delvare> | 2012-03-23 05:02:20 -0400 |
| commit | 5510e62a66bad22b104d5d854445523d7f5754f7 (patch) | |
| tree | a580bd3fff0831628bc0d525d975853bbf25a86d | |
| parent | 0c2732152a5813a870d0b96f0844f4dfe1436519 (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/mcp3021 | 22 | ||||
| -rw-r--r-- | drivers/hwmon/Kconfig | 10 | ||||
| -rw-r--r-- | drivers/hwmon/Makefile | 1 | ||||
| -rw-r--r-- | drivers/hwmon/mcp3021.c | 171 |
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 @@ | |||
| 1 | Kernel driver MCP3021 | ||
| 2 | ====================== | ||
| 3 | |||
| 4 | Supported chips: | ||
| 5 | * Microchip Technology MCP3021 | ||
| 6 | Prefix: 'mcp3021' | ||
| 7 | Datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/21805a.pdf | ||
| 8 | |||
| 9 | Author: Mingkai Hu | ||
| 10 | |||
| 11 | Description | ||
| 12 | ----------- | ||
| 13 | |||
| 14 | This driver implements support for the Microchip Technology MCP3021 chip. | ||
| 15 | |||
| 16 | The Microchip Technology Inc. MCP3021 is a successive approximation A/D | ||
| 17 | converter (ADC) with 10-bit resolution. | ||
| 18 | This device provides one single-ended input with very low power consumption. | ||
| 19 | Communication to the MCP3021 is performed using a 2-wire I2C compatible | ||
| 20 | interface. Standard (100 kHz) and Fast (400 kHz) I2C modes are available. | ||
| 21 | The default I2C device address is 0x4d (contact the Microchip factory for | ||
| 22 | additional 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 | ||
| 816 | config 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 | |||
| 816 | config SENSORS_NTC_THERMISTOR | 826 | config 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 | |||
| 95 | obj-$(CONFIG_SENSORS_MAX6642) += max6642.o | 95 | obj-$(CONFIG_SENSORS_MAX6642) += max6642.o |
| 96 | obj-$(CONFIG_SENSORS_MAX6650) += max6650.o | 96 | obj-$(CONFIG_SENSORS_MAX6650) += max6650.o |
| 97 | obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o | 97 | obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o |
| 98 | obj-$(CONFIG_SENSORS_MCP3021) += mcp3021.o | ||
| 98 | obj-$(CONFIG_SENSORS_NTC_THERMISTOR) += ntc_thermistor.o | 99 | obj-$(CONFIG_SENSORS_NTC_THERMISTOR) += ntc_thermistor.o |
| 99 | obj-$(CONFIG_SENSORS_PC87360) += pc87360.o | 100 | obj-$(CONFIG_SENSORS_PC87360) += pc87360.o |
| 100 | obj-$(CONFIG_SENSORS_PC87427) += pc87427.o | 101 | obj-$(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 | */ | ||
| 40 | struct mcp3021_data { | ||
| 41 | struct device *hwmon_dev; | ||
| 42 | u32 vdd; /* device power supply */ | ||
| 43 | }; | ||
| 44 | |||
| 45 | static 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 | |||
| 69 | static 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 | |||
| 80 | static 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 | |||
| 95 | static DEVICE_ATTR(in0_input, S_IRUGO, show_in_input, NULL); | ||
| 96 | |||
| 97 | static 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 | |||
| 134 | exit_remove: | ||
| 135 | sysfs_remove_file(&client->dev.kobj, &dev_attr_in0_input.attr); | ||
| 136 | exit_free: | ||
| 137 | kfree(data); | ||
| 138 | return err; | ||
| 139 | } | ||
| 140 | |||
| 141 | static 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 | |||
| 152 | static const struct i2c_device_id mcp3021_id[] = { | ||
| 153 | { "mcp3021", 0 }, | ||
| 154 | { } | ||
| 155 | }; | ||
| 156 | MODULE_DEVICE_TABLE(i2c, mcp3021_id); | ||
| 157 | |||
| 158 | static 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 | |||
| 167 | module_i2c_driver(mcp3021_driver); | ||
| 168 | |||
| 169 | MODULE_AUTHOR("Mingkai Hu <Mingkai.hu@freescale.com>"); | ||
| 170 | MODULE_DESCRIPTION("Microchip MCP3021 driver"); | ||
| 171 | MODULE_LICENSE("GPL"); | ||
