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 + * Reworked by Sven Schuchmann * * 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);