diff options
author | Guenter Roeck <linux@roeck-us.net> | 2024-06-19 08:53:56 -0700 |
---|---|---|
committer | Guenter Roeck <linux@roeck-us.net> | 2025-04-23 07:18:27 -0700 |
commit | 4cf1aab45cc56e9276924c21b79da42e2eac01df (patch) | |
tree | e7caa00e3e9d5a4a7dd1e660c995a37c9bae19fd | |
parent | e799657a8aac1d974c90a295dd88b1d95697d18d (diff) |
hwmon: (spd5118) Split into common and I2C specific code
Split spd5118 driver into common and I2C specific code to enable
adding support for I3C.
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
-rw-r--r-- | drivers/hwmon/spd5118.c | 277 |
1 files changed, 143 insertions, 134 deletions
diff --git a/drivers/hwmon/spd5118.c b/drivers/hwmon/spd5118.c index 358152868d96..02eb21684c3a 100644 --- a/drivers/hwmon/spd5118.c +++ b/drivers/hwmon/spd5118.c @@ -305,51 +305,6 @@ static bool spd5118_vendor_valid(u8 bank, u8 id) return id && id != 0x7f; } -/* Return 0 if detection is successful, -ENODEV otherwise */ -static int spd5118_detect(struct i2c_client *client, struct i2c_board_info *info) -{ - struct i2c_adapter *adapter = client->adapter; - int regval; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | - I2C_FUNC_SMBUS_WORD_DATA)) - return -ENODEV; - - regval = i2c_smbus_read_word_swapped(client, SPD5118_REG_TYPE); - if (regval != 0x5118) - return -ENODEV; - - regval = i2c_smbus_read_word_data(client, SPD5118_REG_VENDOR); - if (regval < 0 || !spd5118_vendor_valid(regval & 0xff, regval >> 8)) - return -ENODEV; - - regval = i2c_smbus_read_byte_data(client, SPD5118_REG_CAPABILITY); - if (regval < 0) - return -ENODEV; - if (!(regval & SPD5118_CAP_TS_SUPPORT) || (regval & 0xfc)) - return -ENODEV; - - regval = i2c_smbus_read_byte_data(client, SPD5118_REG_TEMP_CLR); - if (regval) - return -ENODEV; - regval = i2c_smbus_read_byte_data(client, SPD5118_REG_ERROR_CLR); - if (regval) - return -ENODEV; - - regval = i2c_smbus_read_byte_data(client, SPD5118_REG_REVISION); - if (regval < 0 || (regval & 0xc1)) - return -ENODEV; - - regval = i2c_smbus_read_byte_data(client, SPD5118_REG_TEMP_CONFIG); - if (regval < 0) - return -ENODEV; - if (regval & ~SPD5118_TS_DISABLE) - return -ENODEV; - - strscpy(info->type, "spd5118", I2C_NAME_SIZE); - return 0; -} - static const struct hwmon_channel_info *spd5118_info[] = { HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ), @@ -483,7 +438,7 @@ static bool spd5118_volatile_reg(struct device *dev, unsigned int reg) } } -static const struct regmap_range_cfg spd5118_regmap_range_cfg[] = { +static const struct regmap_range_cfg spd5118_i2c_regmap_range_cfg[] = { { .selector_reg = SPD5118_REG_I2C_LEGACY_MODE, .selector_mask = SPD5118_LEGACY_PAGE_MASK, @@ -495,7 +450,7 @@ static const struct regmap_range_cfg spd5118_regmap_range_cfg[] = { }, }; -static const struct regmap_config spd5118_regmap_config = { +static const struct regmap_config spd5118_i2c_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = 0x7ff, @@ -503,87 +458,62 @@ static const struct regmap_config spd5118_regmap_config = { .volatile_reg = spd5118_volatile_reg, .cache_type = REGCACHE_MAPLE, - .ranges = spd5118_regmap_range_cfg, - .num_ranges = ARRAY_SIZE(spd5118_regmap_range_cfg), + .ranges = spd5118_i2c_regmap_range_cfg, + .num_ranges = ARRAY_SIZE(spd5118_i2c_regmap_range_cfg), }; -static int spd5118_init(struct i2c_client *client) +static int spd5118_suspend(struct device *dev) { - struct i2c_adapter *adapter = client->adapter; - int err, regval, mode; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | - I2C_FUNC_SMBUS_WORD_DATA)) - return -ENODEV; - - regval = i2c_smbus_read_word_swapped(client, SPD5118_REG_TYPE); - if (regval < 0 || (regval && regval != 0x5118)) - return -ENODEV; + struct spd5118_data *data = dev_get_drvdata(dev); + struct regmap *regmap = data->regmap; + u32 regval; + int err; /* - * If the device type registers return 0, it is possible that the chip - * has a non-zero page selected and takes the specification literally, - * i.e. disables access to volatile registers besides the page register - * if the page is not 0. Try to identify such chips. + * Make sure the configuration register in the regmap cache is current + * before bypassing it. */ - if (!regval) { - /* Vendor ID registers must also be 0 */ - regval = i2c_smbus_read_word_data(client, SPD5118_REG_VENDOR); - if (regval) - return -ENODEV; - - /* The selected page in MR11 must not be 0 */ - mode = i2c_smbus_read_byte_data(client, SPD5118_REG_I2C_LEGACY_MODE); - if (mode < 0 || (mode & ~SPD5118_LEGACY_MODE_MASK) || - !(mode & SPD5118_LEGACY_PAGE_MASK)) - return -ENODEV; + err = regmap_read(regmap, SPD5118_REG_TEMP_CONFIG, ®val); + if (err < 0) + return err; - err = i2c_smbus_write_byte_data(client, SPD5118_REG_I2C_LEGACY_MODE, - mode & SPD5118_LEGACY_MODE_ADDR); - if (err) - return -ENODEV; + regcache_cache_bypass(regmap, true); + regmap_update_bits(regmap, SPD5118_REG_TEMP_CONFIG, SPD5118_TS_DISABLE, + SPD5118_TS_DISABLE); + regcache_cache_bypass(regmap, false); - /* - * If the device type registers are still bad after selecting - * page 0, this is not a SPD5118 device. Restore original - * legacy mode register value and abort. - */ - regval = i2c_smbus_read_word_swapped(client, SPD5118_REG_TYPE); - if (regval != 0x5118) { - i2c_smbus_write_byte_data(client, SPD5118_REG_I2C_LEGACY_MODE, mode); - return -ENODEV; - } - } + regcache_cache_only(regmap, true); + regcache_mark_dirty(regmap); - /* We are reasonably sure that this is really a SPD5118 hub controller */ return 0; } -static int spd5118_probe(struct i2c_client *client) +static int spd5118_resume(struct device *dev) { - struct device *dev = &client->dev; - unsigned int regval, revision, vendor, bank; + struct spd5118_data *data = dev_get_drvdata(dev); + struct regmap *regmap = data->regmap; + + regcache_cache_only(regmap, false); + return regcache_sync(regmap); +} + +static DEFINE_SIMPLE_DEV_PM_OPS(spd5118_pm_ops, spd5118_suspend, spd5118_resume); + +static int spd5118_common_probe(struct device *dev, struct regmap *regmap) +{ + unsigned int capability, revision, vendor, bank; struct spd5118_data *data; struct device *hwmon_dev; - struct regmap *regmap; int err; - err = spd5118_init(client); - if (err) - return err; - data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; - regmap = devm_regmap_init_i2c(client, &spd5118_regmap_config); - if (IS_ERR(regmap)) - return dev_err_probe(dev, PTR_ERR(regmap), "regmap init failed\n"); - - err = regmap_read(regmap, SPD5118_REG_CAPABILITY, ®val); + err = regmap_read(regmap, SPD5118_REG_CAPABILITY, &capability); if (err) return err; - if (!(regval & SPD5118_CAP_TS_SUPPORT)) + if (!(capability & SPD5118_CAP_TS_SUPPORT)) return -ENODEV; err = regmap_read(regmap, SPD5118_REG_REVISION, &revision); @@ -627,48 +557,127 @@ static int spd5118_probe(struct i2c_client *client) return 0; } -static int spd5118_suspend(struct device *dev) +/* I2C */ + +/* Return 0 if detection is successful, -ENODEV otherwise */ +static int spd5118_detect(struct i2c_client *client, struct i2c_board_info *info) { - struct spd5118_data *data = dev_get_drvdata(dev); - struct regmap *regmap = data->regmap; - u32 regval; - int err; + struct i2c_adapter *adapter = client->adapter; + int regval; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_WORD_DATA)) + return -ENODEV; + + regval = i2c_smbus_read_word_swapped(client, SPD5118_REG_TYPE); + if (regval != 0x5118) + return -ENODEV; + + regval = i2c_smbus_read_word_data(client, SPD5118_REG_VENDOR); + if (regval < 0 || !spd5118_vendor_valid(regval & 0xff, regval >> 8)) + return -ENODEV; + + regval = i2c_smbus_read_byte_data(client, SPD5118_REG_CAPABILITY); + if (regval < 0) + return -ENODEV; + if (!(regval & SPD5118_CAP_TS_SUPPORT) || (regval & 0xfc)) + return -ENODEV; + + regval = i2c_smbus_read_byte_data(client, SPD5118_REG_TEMP_CLR); + if (regval) + return -ENODEV; + regval = i2c_smbus_read_byte_data(client, SPD5118_REG_ERROR_CLR); + if (regval) + return -ENODEV; + + regval = i2c_smbus_read_byte_data(client, SPD5118_REG_REVISION); + if (regval < 0 || (regval & 0xc1)) + return -ENODEV; + + regval = i2c_smbus_read_byte_data(client, SPD5118_REG_TEMP_CONFIG); + if (regval < 0) + return -ENODEV; + if (regval & ~SPD5118_TS_DISABLE) + return -ENODEV; + + strscpy(info->type, "spd5118", I2C_NAME_SIZE); + return 0; +} + +static int spd5118_i2c_init(struct i2c_client *client) +{ + struct i2c_adapter *adapter = client->adapter; + int err, regval, mode; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_WORD_DATA)) + return -ENODEV; + + regval = i2c_smbus_read_word_swapped(client, SPD5118_REG_TYPE); + if (regval < 0 || (regval && regval != 0x5118)) + return -ENODEV; /* - * Make sure the configuration register in the regmap cache is current - * before bypassing it. + * If the device type registers return 0, it is possible that the chip + * has a non-zero page selected and takes the specification literally, + * i.e. disables access to volatile registers besides the page register + * if the page is not 0. Try to identify such chips. */ - err = regmap_read(regmap, SPD5118_REG_TEMP_CONFIG, ®val); - if (err < 0) - return err; + if (!regval) { + /* Vendor ID registers must also be 0 */ + regval = i2c_smbus_read_word_data(client, SPD5118_REG_VENDOR); + if (regval) + return -ENODEV; - regcache_cache_bypass(regmap, true); - regmap_update_bits(regmap, SPD5118_REG_TEMP_CONFIG, SPD5118_TS_DISABLE, - SPD5118_TS_DISABLE); - regcache_cache_bypass(regmap, false); + /* The selected page in MR11 must not be 0 */ + mode = i2c_smbus_read_byte_data(client, SPD5118_REG_I2C_LEGACY_MODE); + if (mode < 0 || (mode & ~SPD5118_LEGACY_MODE_MASK) || + !(mode & SPD5118_LEGACY_PAGE_MASK)) + return -ENODEV; - regcache_cache_only(regmap, true); - regcache_mark_dirty(regmap); + err = i2c_smbus_write_byte_data(client, SPD5118_REG_I2C_LEGACY_MODE, + mode & SPD5118_LEGACY_MODE_ADDR); + if (err) + return -ENODEV; + /* + * If the device type registers are still bad after selecting + * page 0, this is not a SPD5118 device. Restore original + * legacy mode register value and abort. + */ + regval = i2c_smbus_read_word_swapped(client, SPD5118_REG_TYPE); + if (regval != 0x5118) { + i2c_smbus_write_byte_data(client, SPD5118_REG_I2C_LEGACY_MODE, mode); + return -ENODEV; + } + } + + /* We are reasonably sure that this is really a SPD5118 hub controller */ return 0; } -static int spd5118_resume(struct device *dev) +static int spd5118_i2c_probe(struct i2c_client *client) { - struct spd5118_data *data = dev_get_drvdata(dev); - struct regmap *regmap = data->regmap; + struct device *dev = &client->dev; + struct regmap *regmap; + int err; - regcache_cache_only(regmap, false); - return regcache_sync(regmap); -} + err = spd5118_i2c_init(client); + if (err) + return err; -static DEFINE_SIMPLE_DEV_PM_OPS(spd5118_pm_ops, spd5118_suspend, spd5118_resume); + regmap = devm_regmap_init_i2c(client, &spd5118_i2c_regmap_config); + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), "regmap init failed\n"); + + return spd5118_common_probe(dev, regmap); +} -static const struct i2c_device_id spd5118_id[] = { +static const struct i2c_device_id spd5118_i2c_id[] = { { "spd5118" }, { } }; -MODULE_DEVICE_TABLE(i2c, spd5118_id); +MODULE_DEVICE_TABLE(i2c, spd5118_i2c_id); static const struct of_device_id spd5118_of_ids[] = { { .compatible = "jedec,spd5118", }, @@ -676,20 +685,20 @@ static const struct of_device_id spd5118_of_ids[] = { }; MODULE_DEVICE_TABLE(of, spd5118_of_ids); -static struct i2c_driver spd5118_driver = { +static struct i2c_driver spd5118_i2c_driver = { .class = I2C_CLASS_HWMON, .driver = { .name = "spd5118", .of_match_table = spd5118_of_ids, .pm = pm_sleep_ptr(&spd5118_pm_ops), }, - .probe = spd5118_probe, - .id_table = spd5118_id, + .probe = spd5118_i2c_probe, + .id_table = spd5118_i2c_id, .detect = IS_ENABLED(CONFIG_SENSORS_SPD5118_DETECT) ? spd5118_detect : NULL, .address_list = IS_ENABLED(CONFIG_SENSORS_SPD5118_DETECT) ? normal_i2c : NULL, }; -module_i2c_driver(spd5118_driver); +module_i2c_driver(spd5118_i2c_driver); MODULE_AUTHOR("RenĂ© Rebe <rene@exactcode.de>"); MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>"); |