summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSven Schuchmann <schuchmann@schleissheimer.de>2012-09-21 15:04:21 +0400
committerGuenter Roeck <linux@roeck-us.net>2012-09-24 08:08:36 +0400
commit8b662f38e066d8fc1b73a8655da547c348206904 (patch)
tree8b4098e594041bf1df6dbc3e6c34b56cf3cef17d
parenta91698135bef4e945b0eee1b676d6ea5085177dc (diff)
downloadlinux-8b662f38e066d8fc1b73a8655da547c348206904.tar.xz
hwmon: (mcp3021) Prepare MCP3021 driver to support other chips
This Patch is to prepare the MCP3021 driver to support other chips like the MCP3221. The hard defined chip data is now stored within the data struct of each chip. Signed-off-by: Sven Schuchmann <schuchmann@schleissheimer.de> Signed-off-by: Guenter Roeck <linux@roeck-us.net>
-rw-r--r--drivers/hwmon/mcp3021.c33
1 files changed, 26 insertions, 7 deletions
diff --git a/drivers/hwmon/mcp3021.c b/drivers/hwmon/mcp3021.c
index 5162bb95bc61..d700b9271174 100644
--- a/drivers/hwmon/mcp3021.c
+++ b/drivers/hwmon/mcp3021.c
@@ -3,6 +3,7 @@
*
* Copyright (C) 2008-2009, 2012 Freescale Semiconductor, Inc.
* Author: Mingkai Hu <Mingkai.hu@freescale.com>
+ * Reworked by Sven Schuchmann <schuchmann@schleissheimer.de>
*
* This driver export the value of analog input voltage to sysfs, the
* voltage unit is mV. Through the sysfs interface, lm-sensors tool
@@ -34,16 +35,24 @@
#define MCP3021_OUTPUT_RES 10 /* 10-bit resolution */
#define MCP3021_OUTPUT_SCALE 4
+enum chips {
+ mcp3021
+};
/*
* Client data (each client gets its own)
*/
struct mcp3021_data {
struct device *hwmon_dev;
u32 vdd; /* device power supply */
+ u16 sar_shift;
+ u16 sar_mask;
+ u8 output_res;
+ u8 output_scale;
};
static int mcp3021_read16(struct i2c_client *client)
{
+ struct mcp3021_data *data = i2c_get_clientdata(client);
int ret;
u16 reg;
__be16 buf;
@@ -61,20 +70,20 @@ static int mcp3021_read16(struct i2c_client *client)
* The ten-bit output code is composed of the lower 4-bit of the
* first byte and the upper 6-bit of the second byte.
*/
- reg = (reg >> MCP3021_SAR_SHIFT) & MCP3021_SAR_MASK;
+ reg = (reg >> data->sar_shift) & data->sar_mask;
return reg;
}
-static inline u16 volts_from_reg(u16 vdd, u16 val)
+static inline u16 volts_from_reg(struct mcp3021_data *data, u16 val)
{
if (val == 0)
return 0;
- val = val * MCP3021_OUTPUT_SCALE - MCP3021_OUTPUT_SCALE / 2;
+ val = val * data->output_scale - data->output_scale / 2;
- return val * DIV_ROUND_CLOSEST(vdd,
- (1 << MCP3021_OUTPUT_RES) * MCP3021_OUTPUT_SCALE);
+ return val * DIV_ROUND_CLOSEST(data->vdd,
+ (1 << data->output_res) * data->output_scale);
}
static ssize_t show_in_input(struct device *dev, struct device_attribute *attr,
@@ -88,7 +97,8 @@ static ssize_t show_in_input(struct device *dev, struct device_attribute *attr,
if (reg < 0)
return reg;
- in_input = volts_from_reg(data->vdd, reg);
+ in_input = volts_from_reg(data, reg);
+
return sprintf(buf, "%d\n", in_input);
}
@@ -110,6 +120,15 @@ static int mcp3021_probe(struct i2c_client *client,
i2c_set_clientdata(client, data);
+ switch (id->driver_data) {
+ case mcp3021:
+ data->sar_shift = MCP3021_SAR_SHIFT;
+ data->sar_mask = MCP3021_SAR_MASK;
+ data->output_res = MCP3021_OUTPUT_RES;
+ data->output_scale = MCP3021_OUTPUT_SCALE;
+ break;
+ }
+
if (client->dev.platform_data) {
data->vdd = *(u32 *)client->dev.platform_data;
if (data->vdd > MCP3021_VDD_MAX || data->vdd < MCP3021_VDD_MIN)
@@ -145,7 +164,7 @@ static int mcp3021_remove(struct i2c_client *client)
}
static const struct i2c_device_id mcp3021_id[] = {
- { "mcp3021", 0 },
+ { "mcp3021", mcp3021 },
{ }
};
MODULE_DEVICE_TABLE(i2c, mcp3021_id);