Blame view
drivers/hwmon/mcp3021.c
4.94 KB
2874c5fd2 treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-or-later |
5510e62a6 hwmon: Add MCP302... |
2 |
/* |
592758b12 hwmon: (mcp3021) ... |
3 |
* mcp3021.c - driver for Microchip MCP3021 and MCP3221 |
5510e62a6 hwmon: Add MCP302... |
4 5 6 |
* * Copyright (C) 2008-2009, 2012 Freescale Semiconductor, Inc. * Author: Mingkai Hu <Mingkai.hu@freescale.com> |
8b662f38e hwmon: (mcp3021) ... |
7 |
* Reworked by Sven Schuchmann <schuchmann@schleissheimer.de> |
f4dc811c1 hwmon: (mcp3021) ... |
8 |
* DT support added by Clemens Gruber <clemens.gruber@pqgruber.com> |
5510e62a6 hwmon: Add MCP302... |
9 10 11 12 |
* * This driver export the value of analog input voltage to sysfs, the * voltage unit is mV. Through the sysfs interface, lm-sensors tool * can also display the input voltage. |
5510e62a6 hwmon: Add MCP302... |
13 14 15 16 17 18 19 20 21 |
*/ #include <linux/kernel.h> #include <linux/module.h> #include <linux/hwmon.h> #include <linux/slab.h> #include <linux/i2c.h> #include <linux/err.h> #include <linux/device.h> |
f4dc811c1 hwmon: (mcp3021) ... |
22 23 |
#include <linux/of.h> #include <linux/of_device.h> |
5510e62a6 hwmon: Add MCP302... |
24 |
|
f4dc811c1 hwmon: (mcp3021) ... |
25 26 27 28 |
/* Vdd / reference voltage in millivolt */ #define MCP3021_VDD_REF_MAX 5500 #define MCP3021_VDD_REF_MIN 2700 #define MCP3021_VDD_REF_DEFAULT 3300 |
5510e62a6 hwmon: Add MCP302... |
29 30 31 32 |
/* output format */ #define MCP3021_SAR_SHIFT 2 #define MCP3021_SAR_MASK 0x3ff |
5510e62a6 hwmon: Add MCP302... |
33 |
#define MCP3021_OUTPUT_RES 10 /* 10-bit resolution */ |
5510e62a6 hwmon: Add MCP302... |
34 |
|
592758b12 hwmon: (mcp3021) ... |
35 36 37 |
#define MCP3221_SAR_SHIFT 0 #define MCP3221_SAR_MASK 0xfff #define MCP3221_OUTPUT_RES 12 /* 12-bit resolution */ |
592758b12 hwmon: (mcp3021) ... |
38 |
|
8b662f38e hwmon: (mcp3021) ... |
39 |
enum chips { |
592758b12 hwmon: (mcp3021) ... |
40 41 |
mcp3021, mcp3221 |
8b662f38e hwmon: (mcp3021) ... |
42 |
}; |
592758b12 hwmon: (mcp3021) ... |
43 |
|
5510e62a6 hwmon: Add MCP302... |
44 45 46 47 48 |
/* * Client data (each client gets its own) */ struct mcp3021_data { struct device *hwmon_dev; |
f4dc811c1 hwmon: (mcp3021) ... |
49 |
u32 vdd; /* supply and reference voltage in millivolt */ |
8b662f38e hwmon: (mcp3021) ... |
50 51 52 |
u16 sar_shift; u16 sar_mask; u8 output_res; |
5510e62a6 hwmon: Add MCP302... |
53 54 55 56 |
}; static int mcp3021_read16(struct i2c_client *client) { |
8b662f38e hwmon: (mcp3021) ... |
57 |
struct mcp3021_data *data = i2c_get_clientdata(client); |
5510e62a6 hwmon: Add MCP302... |
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
int ret; u16 reg; __be16 buf; ret = i2c_master_recv(client, (char *)&buf, 2); if (ret < 0) return ret; if (ret != 2) return -EIO; /* The output code of the MCP3021 is transmitted with MSB first. */ reg = be16_to_cpu(buf); /* * 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. */ |
8b662f38e hwmon: (mcp3021) ... |
75 |
reg = (reg >> data->sar_shift) & data->sar_mask; |
5510e62a6 hwmon: Add MCP302... |
76 77 78 |
return reg; } |
8b662f38e hwmon: (mcp3021) ... |
79 |
static inline u16 volts_from_reg(struct mcp3021_data *data, u16 val) |
5510e62a6 hwmon: Add MCP302... |
80 |
{ |
347d7e45b hwmon: (mcp3021) ... |
81 |
return DIV_ROUND_CLOSEST(data->vdd * val, 1 << data->output_res); |
5510e62a6 hwmon: Add MCP302... |
82 |
} |
5c2f0dd57 hwmon: (mcp3021) ... |
83 84 |
static ssize_t in0_input_show(struct device *dev, struct device_attribute *attr, char *buf) |
5510e62a6 hwmon: Add MCP302... |
85 86 87 88 89 90 91 92 |
{ struct i2c_client *client = to_i2c_client(dev); struct mcp3021_data *data = i2c_get_clientdata(client); int reg, in_input; reg = mcp3021_read16(client); if (reg < 0) return reg; |
8b662f38e hwmon: (mcp3021) ... |
93 |
in_input = volts_from_reg(data, reg); |
5510e62a6 hwmon: Add MCP302... |
94 95 96 |
return sprintf(buf, "%d ", in_input); } |
5c2f0dd57 hwmon: (mcp3021) ... |
97 |
static DEVICE_ATTR_RO(in0_input); |
5510e62a6 hwmon: Add MCP302... |
98 |
|
674870385 hwmon: use simple... |
99 100 101 |
static const struct i2c_device_id mcp3021_id[]; static int mcp3021_probe(struct i2c_client *client) |
5510e62a6 hwmon: Add MCP302... |
102 103 104 |
{ int err; struct mcp3021_data *data = NULL; |
f4dc811c1 hwmon: (mcp3021) ... |
105 |
struct device_node *np = client->dev.of_node; |
5510e62a6 hwmon: Add MCP302... |
106 107 108 |
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) return -ENODEV; |
79831fd4e hwmon: (mcp3021) ... |
109 110 |
data = devm_kzalloc(&client->dev, sizeof(struct mcp3021_data), GFP_KERNEL); |
5510e62a6 hwmon: Add MCP302... |
111 112 113 114 |
if (!data) return -ENOMEM; i2c_set_clientdata(client, data); |
f4dc811c1 hwmon: (mcp3021) ... |
115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
if (np) { if (!of_property_read_u32(np, "reference-voltage-microvolt", &data->vdd)) data->vdd /= 1000; else data->vdd = MCP3021_VDD_REF_DEFAULT; } else { u32 *pdata = dev_get_platdata(&client->dev); if (pdata) data->vdd = *pdata; else data->vdd = MCP3021_VDD_REF_DEFAULT; } |
674870385 hwmon: use simple... |
129 |
switch (i2c_match_id(mcp3021_id, client)->driver_data) { |
8b662f38e hwmon: (mcp3021) ... |
130 131 132 133 |
case mcp3021: data->sar_shift = MCP3021_SAR_SHIFT; data->sar_mask = MCP3021_SAR_MASK; data->output_res = MCP3021_OUTPUT_RES; |
8b662f38e hwmon: (mcp3021) ... |
134 |
break; |
592758b12 hwmon: (mcp3021) ... |
135 136 137 138 139 |
case mcp3221: data->sar_shift = MCP3221_SAR_SHIFT; data->sar_mask = MCP3221_SAR_MASK; data->output_res = MCP3221_OUTPUT_RES; |
592758b12 hwmon: (mcp3021) ... |
140 |
break; |
8b662f38e hwmon: (mcp3021) ... |
141 |
} |
f4dc811c1 hwmon: (mcp3021) ... |
142 143 |
if (data->vdd > MCP3021_VDD_REF_MAX || data->vdd < MCP3021_VDD_REF_MIN) return -EINVAL; |
5510e62a6 hwmon: Add MCP302... |
144 145 146 |
err = sysfs_create_file(&client->dev.kobj, &dev_attr_in0_input.attr); if (err) |
79831fd4e hwmon: (mcp3021) ... |
147 |
return err; |
5510e62a6 hwmon: Add MCP302... |
148 149 150 151 152 153 154 155 156 157 158 |
data->hwmon_dev = hwmon_device_register(&client->dev); if (IS_ERR(data->hwmon_dev)) { err = PTR_ERR(data->hwmon_dev); goto exit_remove; } return 0; exit_remove: sysfs_remove_file(&client->dev.kobj, &dev_attr_in0_input.attr); |
5510e62a6 hwmon: Add MCP302... |
159 160 161 162 163 164 165 166 167 |
return err; } static int mcp3021_remove(struct i2c_client *client) { struct mcp3021_data *data = i2c_get_clientdata(client); hwmon_device_unregister(data->hwmon_dev); sysfs_remove_file(&client->dev.kobj, &dev_attr_in0_input.attr); |
5510e62a6 hwmon: Add MCP302... |
168 169 170 171 172 |
return 0; } static const struct i2c_device_id mcp3021_id[] = { |
8b662f38e hwmon: (mcp3021) ... |
173 |
{ "mcp3021", mcp3021 }, |
592758b12 hwmon: (mcp3021) ... |
174 |
{ "mcp3221", mcp3221 }, |
5510e62a6 hwmon: Add MCP302... |
175 176 177 |
{ } }; MODULE_DEVICE_TABLE(i2c, mcp3021_id); |
f4dc811c1 hwmon: (mcp3021) ... |
178 179 180 181 182 183 184 185 |
#ifdef CONFIG_OF static const struct of_device_id of_mcp3021_match[] = { { .compatible = "microchip,mcp3021", .data = (void *)mcp3021 }, { .compatible = "microchip,mcp3221", .data = (void *)mcp3221 }, { } }; MODULE_DEVICE_TABLE(of, of_mcp3021_match); #endif |
5510e62a6 hwmon: Add MCP302... |
186 187 188 |
static struct i2c_driver mcp3021_driver = { .driver = { .name = "mcp3021", |
f4dc811c1 hwmon: (mcp3021) ... |
189 |
.of_match_table = of_match_ptr(of_mcp3021_match), |
5510e62a6 hwmon: Add MCP302... |
190 |
}, |
674870385 hwmon: use simple... |
191 |
.probe_new = mcp3021_probe, |
5510e62a6 hwmon: Add MCP302... |
192 193 194 195 196 197 198 |
.remove = mcp3021_remove, .id_table = mcp3021_id, }; module_i2c_driver(mcp3021_driver); MODULE_AUTHOR("Mingkai Hu <Mingkai.hu@freescale.com>"); |
592758b12 hwmon: (mcp3021) ... |
199 |
MODULE_DESCRIPTION("Microchip MCP3021/MCP3221 driver"); |
5510e62a6 hwmon: Add MCP302... |
200 |
MODULE_LICENSE("GPL"); |