209 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * mcp3021.c - driver for Microchip MCP3021 and MCP32214 *5 * Copyright (C) 2008-2009, 2012 Freescale Semiconductor, Inc.6 * Author: Mingkai Hu <Mingkai.hu@freescale.com>7 * Reworked by Sven Schuchmann <schuchmann@schleissheimer.de>8 * DT support added by Clemens Gruber <clemens.gruber@pqgruber.com>9 *10 * This driver exports the value of analog input voltage to sysfs, the11 * voltage unit is mV. Through the sysfs interface, lm-sensors tool12 * can also display the input voltage.13 */14 15#include <linux/kernel.h>16#include <linux/module.h>17#include <linux/hwmon.h>18#include <linux/slab.h>19#include <linux/i2c.h>20#include <linux/err.h>21#include <linux/device.h>22#include <linux/of.h>23 24/* Vdd / reference voltage in millivolt */25#define MCP3021_VDD_REF_MAX 550026#define MCP3021_VDD_REF_MIN 270027#define MCP3021_VDD_REF_DEFAULT 330028 29/* output format */30#define MCP3021_SAR_SHIFT 231#define MCP3021_SAR_MASK 0x3ff32#define MCP3021_OUTPUT_RES 10 /* 10-bit resolution */33 34#define MCP3221_SAR_SHIFT 035#define MCP3221_SAR_MASK 0xfff36#define MCP3221_OUTPUT_RES 12 /* 12-bit resolution */37 38enum chips {39 mcp3021,40 mcp322141};42 43/*44 * Client data (each client gets its own)45 */46struct mcp3021_data {47 struct i2c_client *client;48 u32 vdd; /* supply and reference voltage in millivolt */49 u16 sar_shift;50 u16 sar_mask;51 u8 output_res;52};53 54static inline u16 volts_from_reg(struct mcp3021_data *data, u16 val)55{56 return DIV_ROUND_CLOSEST(data->vdd * val, 1 << data->output_res);57}58 59static int mcp3021_read(struct device *dev, enum hwmon_sensor_types type,60 u32 attr, int channel, long *val)61{62 struct mcp3021_data *data = dev_get_drvdata(dev);63 struct i2c_client *client = data->client;64 __be16 buf;65 u16 reg;66 int ret;67 68 if (type != hwmon_in)69 return -EOPNOTSUPP;70 71 ret = i2c_master_recv(client, (char *)&buf, 2);72 if (ret < 0)73 return ret;74 if (ret != 2)75 return -EIO;76 77 /* The output code of the MCP3021 is transmitted with MSB first. */78 reg = be16_to_cpu(buf);79 80 /*81 * The ten-bit output code is composed of the lower 4-bit of the82 * first byte and the upper 6-bit of the second byte.83 */84 reg = (reg >> data->sar_shift) & data->sar_mask;85 86 *val = volts_from_reg(data, reg);87 88 return 0;89}90 91static umode_t mcp3021_is_visible(const void *_data,92 enum hwmon_sensor_types type,93 u32 attr, int channel)94{95 if (type != hwmon_in)96 return 0;97 98 if (attr != hwmon_in_input)99 return 0;100 101 return 0444;102}103 104static const struct hwmon_channel_info * const mcp3021_info[] = {105 HWMON_CHANNEL_INFO(in, HWMON_I_INPUT),106 NULL107};108 109static const struct hwmon_ops mcp3021_hwmon_ops = {110 .is_visible = mcp3021_is_visible,111 .read = mcp3021_read,112};113 114static const struct hwmon_chip_info mcp3021_chip_info = {115 .ops = &mcp3021_hwmon_ops,116 .info = mcp3021_info,117};118 119static int mcp3021_probe(struct i2c_client *client)120{121 struct mcp3021_data *data = NULL;122 struct device_node *np = client->dev.of_node;123 struct device *hwmon_dev;124 enum chips type;125 126 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))127 return -ENODEV;128 129 data = devm_kzalloc(&client->dev, sizeof(struct mcp3021_data),130 GFP_KERNEL);131 if (!data)132 return -ENOMEM;133 134 i2c_set_clientdata(client, data);135 136 if (np) {137 if (!of_property_read_u32(np, "reference-voltage-microvolt",138 &data->vdd))139 data->vdd /= 1000;140 else141 data->vdd = MCP3021_VDD_REF_DEFAULT;142 } else {143 u32 *pdata = dev_get_platdata(&client->dev);144 145 if (pdata)146 data->vdd = *pdata;147 else148 data->vdd = MCP3021_VDD_REF_DEFAULT;149 }150 151 type = (uintptr_t)i2c_get_match_data(client);152 switch (type) {153 case mcp3021:154 data->sar_shift = MCP3021_SAR_SHIFT;155 data->sar_mask = MCP3021_SAR_MASK;156 data->output_res = MCP3021_OUTPUT_RES;157 break;158 159 case mcp3221:160 data->sar_shift = MCP3221_SAR_SHIFT;161 data->sar_mask = MCP3221_SAR_MASK;162 data->output_res = MCP3221_OUTPUT_RES;163 break;164 }165 166 data->client = client;167 168 if (data->vdd > MCP3021_VDD_REF_MAX || data->vdd < MCP3021_VDD_REF_MIN)169 return -EINVAL;170 171 hwmon_dev = devm_hwmon_device_register_with_info(&client->dev,172 client->name,173 data,174 &mcp3021_chip_info,175 NULL);176 return PTR_ERR_OR_ZERO(hwmon_dev);177}178 179static const struct i2c_device_id mcp3021_id[] = {180 { "mcp3021", mcp3021 },181 { "mcp3221", mcp3221 },182 { }183};184MODULE_DEVICE_TABLE(i2c, mcp3021_id);185 186#ifdef CONFIG_OF187static const struct of_device_id of_mcp3021_match[] = {188 { .compatible = "microchip,mcp3021", .data = (void *)mcp3021 },189 { .compatible = "microchip,mcp3221", .data = (void *)mcp3221 },190 { }191};192MODULE_DEVICE_TABLE(of, of_mcp3021_match);193#endif194 195static struct i2c_driver mcp3021_driver = {196 .driver = {197 .name = "mcp3021",198 .of_match_table = of_match_ptr(of_mcp3021_match),199 },200 .probe = mcp3021_probe,201 .id_table = mcp3021_id,202};203 204module_i2c_driver(mcp3021_driver);205 206MODULE_AUTHOR("Mingkai Hu <Mingkai.hu@freescale.com>");207MODULE_DESCRIPTION("Microchip MCP3021/MCP3221 driver");208MODULE_LICENSE("GPL");209