Skip to content

Commit

Permalink
hwmon: (lm75) add I3C support for P3T1755
Browse files Browse the repository at this point in the history
Introduce I3C support by defining I3C accessors for regmap and
implementing an I3C driver. Enable I3C for the NXP P3T1755.

Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Link: https://lore.kernel.org/r/20241220093635.11218-1-wsa+renesas@sang-engineering.com
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
  • Loading branch information
Wolfram Sang authored and Guenter Roeck committed Dec 22, 2024
1 parent bc96dc1 commit 6071d10
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 4 deletions.
2 changes: 2 additions & 0 deletions drivers/hwmon/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -1412,7 +1412,9 @@ config SENSORS_LM73
config SENSORS_LM75
tristate "National Semiconductor LM75 and compatibles"
depends on I2C
depends on I3C || !I3C
select REGMAP_I2C
select REGMAP_I3C if I3C
help
If you say yes here you get support for one common type of
temperature sensor chip, with models including:
Expand Down
121 changes: 117 additions & 4 deletions drivers/hwmon/lm75.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/i3c/device.h>
#include <linux/hwmon.h>
#include <linux/err.h>
#include <linux/of.h>
Expand Down Expand Up @@ -112,6 +113,8 @@ struct lm75_data {
unsigned int sample_time; /* In ms */
enum lm75_type kind;
const struct lm75_params *params;
u8 reg_buf[1];
u8 val_buf[3];
};

/*-----------------------------------------------------------------------*/
Expand Down Expand Up @@ -606,6 +609,77 @@ static const struct regmap_bus lm75_i2c_regmap_bus = {
.reg_write = lm75_i2c_reg_write,
};

static int lm75_i3c_reg_read(void *context, unsigned int reg, unsigned int *val)
{
struct i3c_device *i3cdev = context;
struct lm75_data *data = i3cdev_get_drvdata(i3cdev);
struct i3c_priv_xfer xfers[] = {
{
.rnw = false,
.len = 1,
.data.out = data->reg_buf,
},
{
.rnw = true,
.len = 2,
.data.out = data->val_buf,
},
};
int ret;

data->reg_buf[0] = reg;

if (reg == LM75_REG_CONF && !data->params->config_reg_16bits)
xfers[1].len--;

ret = i3c_device_do_priv_xfers(i3cdev, xfers, 2);
if (ret < 0)
return ret;

if (reg == LM75_REG_CONF && !data->params->config_reg_16bits)
*val = data->val_buf[0];
else if (reg == LM75_REG_CONF)
*val = data->val_buf[0] | (data->val_buf[1] << 8);
else
*val = data->val_buf[1] | (data->val_buf[0] << 8);

return 0;
}

static int lm75_i3c_reg_write(void *context, unsigned int reg, unsigned int val)
{
struct i3c_device *i3cdev = context;
struct lm75_data *data = i3cdev_get_drvdata(i3cdev);
struct i3c_priv_xfer xfers[] = {
{
.rnw = false,
.len = 3,
.data.out = data->val_buf,
},
};

data->val_buf[0] = reg;

if (reg == PCT2075_REG_IDLE ||
(reg == LM75_REG_CONF && !data->params->config_reg_16bits)) {
xfers[0].len--;
data->val_buf[1] = val & 0xff;
} else if (reg == LM75_REG_CONF) {
data->val_buf[1] = val & 0xff;
data->val_buf[2] = (val >> 8) & 0xff;
} else {
data->val_buf[1] = (val >> 8) & 0xff;
data->val_buf[2] = val & 0xff;
}

return i3c_device_do_priv_xfers(i3cdev, xfers, 1);
}

static const struct regmap_bus lm75_i3c_regmap_bus = {
.reg_read = lm75_i3c_reg_read,
.reg_write = lm75_i3c_reg_write,
};

static const struct regmap_config lm75_regmap_config = {
.reg_bits = 8,
.val_bits = 16,
Expand All @@ -626,7 +700,7 @@ static void lm75_remove(void *data)
}

static int lm75_generic_probe(struct device *dev, const char *name,
const void *kind_ptr, int irq, struct regmap *regmap)
enum lm75_type kind, int irq, struct regmap *regmap)
{
struct device *hwmon_dev;
struct lm75_data *data;
Expand All @@ -639,7 +713,7 @@ static int lm75_generic_probe(struct device *dev, const char *name,
/* needed by custom regmap callbacks */
dev_set_drvdata(dev, data);

data->kind = (uintptr_t)kind_ptr;
data->kind = kind;
data->regmap = regmap;

err = devm_regulator_get_enable(dev, "vs");
Expand Down Expand Up @@ -711,7 +785,7 @@ static int lm75_i2c_probe(struct i2c_client *client)
if (IS_ERR(regmap))
return PTR_ERR(regmap);

return lm75_generic_probe(dev, client->name, i2c_get_match_data(client),
return lm75_generic_probe(dev, client->name, (uintptr_t)i2c_get_match_data(client),
client->irq, regmap);
}

Expand Down Expand Up @@ -750,6 +824,37 @@ static const struct i2c_device_id lm75_i2c_ids[] = {
};
MODULE_DEVICE_TABLE(i2c, lm75_i2c_ids);

struct lm75_i3c_device {
enum lm75_type type;
const char *name;
};

static const struct lm75_i3c_device lm75_i3c_p3t1755 = {
.name = "p3t1755",
.type = p3t1755,
};

static const struct i3c_device_id lm75_i3c_ids[] = {
I3C_DEVICE(0x011b, 0x152a, &lm75_i3c_p3t1755),
{ /* LIST END */ }
};
MODULE_DEVICE_TABLE(i3c, lm75_i3c_ids);

static int lm75_i3c_probe(struct i3c_device *i3cdev)
{
struct device *dev = i3cdev_to_dev(i3cdev);
const struct lm75_i3c_device *id_data;
struct regmap *regmap;

regmap = devm_regmap_init(dev, &lm75_i3c_regmap_bus, i3cdev, &lm75_regmap_config);
if (IS_ERR(regmap))
return PTR_ERR(regmap);

id_data = i3c_device_match_id(i3cdev, lm75_i3c_ids)->data;

return lm75_generic_probe(dev, id_data->name, id_data->type, 0, regmap);
}

static const struct of_device_id __maybe_unused lm75_of_match[] = {
{
.compatible = "adi,adt75",
Expand Down Expand Up @@ -1008,7 +1113,15 @@ static struct i2c_driver lm75_i2c_driver = {
.address_list = normal_i2c,
};

module_i2c_driver(lm75_i2c_driver);
static struct i3c_driver lm75_i3c_driver = {
.driver = {
.name = "lm75_i3c",
},
.probe = lm75_i3c_probe,
.id_table = lm75_i3c_ids,
};

module_i3c_i2c_driver(lm75_i3c_driver, &lm75_i2c_driver)

MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>");
MODULE_DESCRIPTION("LM75 driver");
Expand Down

0 comments on commit 6071d10

Please sign in to comment.