diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-02 00:50:06 +0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-02 00:50:06 +0400 |
commit | cc150a2861e744d8f574d571762cc7e9f928abb3 (patch) | |
tree | a1567d76fc52dc56ba483d7dafa82fada5fc28ba /drivers/hwmon/mcp3021.c | |
parent | d9a807461fc8cc0d6ba589ea0730d139122af012 (diff) | |
parent | 592758b12f2e327bb5902dabd3d36b2e86049871 (diff) | |
download | linux-cc150a2861e744d8f574d571762cc7e9f928abb3.tar.xz |
Merge tag 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging
Pull hwmon updates from Guenter Roeck:
"New drivers for: MCP3221, ADT7410, MAX197
Chip support added to existing drivers: LM71, LM74, MAX1110, MAX1112,
MAX1113, INA220, INA230, MCP3221
Cleanup: Use devm_ functions, fixed build warnings, removed deprecated
sysfs attributes, code simplifications, dropped dependencies on
EXPERIMENTAL"
* tag 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging: (64 commits)
hwmon: (mcp3021) Add MCP3221 support
hwmon: (mcp3021) Prepare MCP3021 driver to support other chips
hwmon: (w83791d) Drop unnecessary compare statements
hwmon: (lm93) Drop unnecessary compare statement
hwmon: (lm70) Simplify show_name function
hwmon: (adcxx) Simplify show_name function
hwmon: Drop dependencies on EXPERIMENTAL
hwmon: (it87) Fix Kconfig for IT87 driver
hwmon: (sht15) move header to linux/platform_data/
hwmon: (asus_atk0110) Remove useless kfree
hwmon: (ina2xx) Add support for INA220 and INA230
hwmon: (ina2xx) Use structure array to distinguish chip types
hwmon: (max1111) Add support for MAX1110, MAX1112, and MAX1113
hwmon: (lm70) Add support for LM71 and LM74
hwmon: (Documentation) Update feature-removal-schedule.txt
hwmon: (w83793) Remove legacy chassis intrusion detection sysfs attributes
hwmon: (w83792d) Remove legacy chassis intrusion detection attributes
hwmon: (adm9240) Remove legacy chassis intrusion detection sysfs attribute
hwmon: (lm70) Allow 4wire SPI bus with LM70
hwmon: (sht15) remove multiple driver registration
...
Diffstat (limited to 'drivers/hwmon/mcp3021.c')
-rw-r--r-- | drivers/hwmon/mcp3021.c | 67 |
1 files changed, 48 insertions, 19 deletions
diff --git a/drivers/hwmon/mcp3021.c b/drivers/hwmon/mcp3021.c index d0afc0cd3ff4..eedb32292d6d 100644 --- a/drivers/hwmon/mcp3021.c +++ b/drivers/hwmon/mcp3021.c @@ -1,8 +1,9 @@ /* - * mcp3021.c - driver for the Microchip MCP3021 chip + * mcp3021.c - driver for Microchip MCP3021 and MCP3221 * * 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,31 @@ #define MCP3021_OUTPUT_RES 10 /* 10-bit resolution */ #define MCP3021_OUTPUT_SCALE 4 +#define MCP3221_SAR_SHIFT 0 +#define MCP3221_SAR_MASK 0xfff +#define MCP3221_OUTPUT_RES 12 /* 12-bit resolution */ +#define MCP3221_OUTPUT_SCALE 1 + +enum chips { + mcp3021, + mcp3221 +}; + /* * 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 +77,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 +104,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); } @@ -103,25 +120,39 @@ static int mcp3021_probe(struct i2c_client *client, if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) return -ENODEV; - data = kzalloc(sizeof(struct mcp3021_data), GFP_KERNEL); + data = devm_kzalloc(&client->dev, sizeof(struct mcp3021_data), + GFP_KERNEL); if (!data) return -ENOMEM; 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; + + case mcp3221: + data->sar_shift = MCP3221_SAR_SHIFT; + data->sar_mask = MCP3221_SAR_MASK; + data->output_res = MCP3221_OUTPUT_RES; + data->output_scale = MCP3221_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) { - err = -EINVAL; - goto exit_free; - } + if (data->vdd > MCP3021_VDD_MAX || data->vdd < MCP3021_VDD_MIN) + return -EINVAL; } else data->vdd = MCP3021_VDD_REF; err = sysfs_create_file(&client->dev.kobj, &dev_attr_in0_input.attr); if (err) - goto exit_free; + return err; data->hwmon_dev = hwmon_device_register(&client->dev); if (IS_ERR(data->hwmon_dev)) { @@ -133,8 +164,6 @@ static int mcp3021_probe(struct i2c_client *client, exit_remove: sysfs_remove_file(&client->dev.kobj, &dev_attr_in0_input.attr); -exit_free: - kfree(data); return err; } @@ -144,13 +173,13 @@ static int mcp3021_remove(struct i2c_client *client) hwmon_device_unregister(data->hwmon_dev); sysfs_remove_file(&client->dev.kobj, &dev_attr_in0_input.attr); - kfree(data); return 0; } static const struct i2c_device_id mcp3021_id[] = { - { "mcp3021", 0 }, + { "mcp3021", mcp3021 }, + { "mcp3221", mcp3221 }, { } }; MODULE_DEVICE_TABLE(i2c, mcp3021_id); @@ -167,5 +196,5 @@ static struct i2c_driver mcp3021_driver = { module_i2c_driver(mcp3021_driver); MODULE_AUTHOR("Mingkai Hu <Mingkai.hu@freescale.com>"); -MODULE_DESCRIPTION("Microchip MCP3021 driver"); +MODULE_DESCRIPTION("Microchip MCP3021/MCP3221 driver"); MODULE_LICENSE("GPL"); |