brintos

brintos / linux-shallow public Read only

0
0
Text · 4.8 KiB · bcddf68 Raw
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