linux/drivers/hwmon/max127.c
Stephen Kitt deeab9ea40 hwmon: use simple i2c probe
All these drivers have an i2c probe function which doesn't use the
"struct i2c_device_id *id" parameter, so they can trivially be
converted to the "probe_new" style of probe with a single argument.

This is part of an ongoing transition to single-argument i2c probe
functions. Old-style probe functions involve a call to i2c_match_id:
in drivers/i2c/i2c-core-base.c,

         /*
          * When there are no more users of probe(),
          * rename probe_new to probe.
          */
         if (driver->probe_new)
                 status = driver->probe_new(client);
         else if (driver->probe)
                 status = driver->probe(client,
                                        i2c_match_id(driver->id_table, client));
         else
                 status = -EINVAL;

Drivers which don't need the second parameter can be declared using
probe_new instead, avoiding the call to i2c_match_id. Drivers which do
can still be converted to probe_new-style, calling i2c_match_id
themselves (as is done currently for of_match_id).

This change was done using the following Coccinelle script, and fixed
up for whitespace changes:

@ rule1 @
identifier fn;
identifier client, id;
@@

- static int fn(struct i2c_client *client, const struct i2c_device_id *id)
+ static int fn(struct i2c_client *client)
{
...when != id
}

@ rule2 depends on rule1 @
identifier rule1.fn;
identifier driver;
@@

struct i2c_driver driver = {
-       .probe
+       .probe_new
                =
(
                   fn
|
-                  &fn
+                  fn
)
                ,
};

Signed-off-by: Stephen Kitt <steve@sk2.org>
Link: https://lore.kernel.org/r/20221011143309.3141267-1-steve@sk2.org
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2022-12-04 16:45:02 -08:00

352 lines
7.5 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// SPDX-License-Identifier: GPL-2.0+
/*
* Hardware monitoring driver for MAX127.
*
* Copyright (c) 2020 Facebook Inc.
*/
#include <linux/err.h>
#include <linux/hwmon.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/module.h>
/*
* MAX127 Control Byte. Refer to MAX127 datasheet, Table 1 "Control-Byte
* Format" for details.
*/
#define MAX127_CTRL_START BIT(7)
#define MAX127_CTRL_SEL_SHIFT 4
#define MAX127_CTRL_RNG BIT(3)
#define MAX127_CTRL_BIP BIT(2)
#define MAX127_CTRL_PD1 BIT(1)
#define MAX127_CTRL_PD0 BIT(0)
#define MAX127_NUM_CHANNELS 8
#define MAX127_SET_CHANNEL(ch) (((ch) & 7) << MAX127_CTRL_SEL_SHIFT)
/*
* MAX127 channel input ranges. Refer to MAX127 datasheet, Table 3 "Range
* and Polarity Selection" for details.
*/
#define MAX127_FULL_RANGE 10000 /* 10V */
#define MAX127_HALF_RANGE 5000 /* 5V */
/*
* MAX127 returns 2 bytes at read:
* - the first byte contains data[11:4].
* - the second byte contains data[3:0] (MSB) and 4 dummy 0s (LSB).
* Refer to MAX127 datasheet, "Read a Conversion (Read Cycle)" section
* for details.
*/
#define MAX127_DATA_LEN 2
#define MAX127_DATA_SHIFT 4
#define MAX127_SIGN_BIT BIT(11)
struct max127_data {
struct mutex lock;
struct i2c_client *client;
u8 ctrl_byte[MAX127_NUM_CHANNELS];
};
static int max127_select_channel(struct i2c_client *client, u8 ctrl_byte)
{
int status;
struct i2c_msg msg = {
.addr = client->addr,
.flags = 0,
.len = sizeof(ctrl_byte),
.buf = &ctrl_byte,
};
status = i2c_transfer(client->adapter, &msg, 1);
if (status < 0)
return status;
if (status != 1)
return -EIO;
return 0;
}
static int max127_read_channel(struct i2c_client *client, long *val)
{
int status;
u8 i2c_data[MAX127_DATA_LEN];
struct i2c_msg msg = {
.addr = client->addr,
.flags = I2C_M_RD,
.len = sizeof(i2c_data),
.buf = i2c_data,
};
status = i2c_transfer(client->adapter, &msg, 1);
if (status < 0)
return status;
if (status != 1)
return -EIO;
*val = (i2c_data[1] >> MAX127_DATA_SHIFT) |
((u16)i2c_data[0] << MAX127_DATA_SHIFT);
return 0;
}
static long max127_process_raw(u8 ctrl_byte, long raw)
{
long scale, weight;
/*
* MAX127's data coding is binary in unipolar mode with 1 LSB =
* (Full-Scale/4096) and twos complement binary in bipolar mode
* with 1 LSB = [(2 x |FS|)/4096].
* Refer to MAX127 datasheet, "Transfer Function" section for
* details.
*/
scale = (ctrl_byte & MAX127_CTRL_RNG) ? MAX127_FULL_RANGE :
MAX127_HALF_RANGE;
if (ctrl_byte & MAX127_CTRL_BIP) {
weight = (raw & MAX127_SIGN_BIT);
raw &= ~MAX127_SIGN_BIT;
raw -= weight;
raw *= 2;
}
return raw * scale / 4096;
}
static int max127_read_input(struct max127_data *data, int channel, long *val)
{
long raw;
int status;
struct i2c_client *client = data->client;
u8 ctrl_byte = data->ctrl_byte[channel];
mutex_lock(&data->lock);
status = max127_select_channel(client, ctrl_byte);
if (status)
goto exit;
status = max127_read_channel(client, &raw);
if (status)
goto exit;
*val = max127_process_raw(ctrl_byte, raw);
exit:
mutex_unlock(&data->lock);
return status;
}
static int max127_read_min(struct max127_data *data, int channel, long *val)
{
u8 rng_bip = (data->ctrl_byte[channel] >> 2) & 3;
static const int min_input_map[4] = {
0, /* RNG=0, BIP=0 */
-MAX127_HALF_RANGE, /* RNG=0, BIP=1 */
0, /* RNG=1, BIP=0 */
-MAX127_FULL_RANGE, /* RNG=1, BIP=1 */
};
*val = min_input_map[rng_bip];
return 0;
}
static int max127_read_max(struct max127_data *data, int channel, long *val)
{
u8 rng_bip = (data->ctrl_byte[channel] >> 2) & 3;
static const int max_input_map[4] = {
MAX127_HALF_RANGE, /* RNG=0, BIP=0 */
MAX127_HALF_RANGE, /* RNG=0, BIP=1 */
MAX127_FULL_RANGE, /* RNG=1, BIP=0 */
MAX127_FULL_RANGE, /* RNG=1, BIP=1 */
};
*val = max_input_map[rng_bip];
return 0;
}
static int max127_write_min(struct max127_data *data, int channel, long val)
{
u8 ctrl;
mutex_lock(&data->lock);
ctrl = data->ctrl_byte[channel];
if (val <= -MAX127_FULL_RANGE) {
ctrl |= (MAX127_CTRL_RNG | MAX127_CTRL_BIP);
} else if (val < 0) {
ctrl |= MAX127_CTRL_BIP;
ctrl &= ~MAX127_CTRL_RNG;
} else {
ctrl &= ~MAX127_CTRL_BIP;
}
data->ctrl_byte[channel] = ctrl;
mutex_unlock(&data->lock);
return 0;
}
static int max127_write_max(struct max127_data *data, int channel, long val)
{
mutex_lock(&data->lock);
if (val >= MAX127_FULL_RANGE)
data->ctrl_byte[channel] |= MAX127_CTRL_RNG;
else
data->ctrl_byte[channel] &= ~MAX127_CTRL_RNG;
mutex_unlock(&data->lock);
return 0;
}
static umode_t max127_is_visible(const void *_data,
enum hwmon_sensor_types type,
u32 attr, int channel)
{
if (type == hwmon_in) {
switch (attr) {
case hwmon_in_input:
return 0444;
case hwmon_in_min:
case hwmon_in_max:
return 0644;
default:
break;
}
}
return 0;
}
static int max127_read(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long *val)
{
int status;
struct max127_data *data = dev_get_drvdata(dev);
if (type != hwmon_in)
return -EOPNOTSUPP;
switch (attr) {
case hwmon_in_input:
status = max127_read_input(data, channel, val);
break;
case hwmon_in_min:
status = max127_read_min(data, channel, val);
break;
case hwmon_in_max:
status = max127_read_max(data, channel, val);
break;
default:
status = -EOPNOTSUPP;
break;
}
return status;
}
static int max127_write(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long val)
{
int status;
struct max127_data *data = dev_get_drvdata(dev);
if (type != hwmon_in)
return -EOPNOTSUPP;
switch (attr) {
case hwmon_in_min:
status = max127_write_min(data, channel, val);
break;
case hwmon_in_max:
status = max127_write_max(data, channel, val);
break;
default:
status = -EOPNOTSUPP;
break;
}
return status;
}
static const struct hwmon_ops max127_hwmon_ops = {
.is_visible = max127_is_visible,
.read = max127_read,
.write = max127_write,
};
static const struct hwmon_channel_info *max127_info[] = {
HWMON_CHANNEL_INFO(in,
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX,
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX,
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX,
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX,
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX,
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX,
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX,
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX),
NULL,
};
static const struct hwmon_chip_info max127_chip_info = {
.ops = &max127_hwmon_ops,
.info = max127_info,
};
static int max127_probe(struct i2c_client *client)
{
int i;
struct device *hwmon_dev;
struct max127_data *data;
struct device *dev = &client->dev;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->client = client;
mutex_init(&data->lock);
for (i = 0; i < ARRAY_SIZE(data->ctrl_byte); i++)
data->ctrl_byte[i] = (MAX127_CTRL_START |
MAX127_SET_CHANNEL(i));
hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name,
data,
&max127_chip_info,
NULL);
return PTR_ERR_OR_ZERO(hwmon_dev);
}
static const struct i2c_device_id max127_id[] = {
{ "max127", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, max127_id);
static struct i2c_driver max127_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "max127",
},
.probe_new = max127_probe,
.id_table = max127_id,
};
module_i2c_driver(max127_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Mike Choi <mikechoi@fb.com>");
MODULE_AUTHOR("Tao Ren <rentao.bupt@gmail.com>");
MODULE_DESCRIPTION("MAX127 Hardware Monitoring driver");