]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
hwmon: (spd5118) Split into common and I2C specific code
authorGuenter Roeck <linux@roeck-us.net>
Wed, 19 Jun 2024 15:53:56 +0000 (08:53 -0700)
committerGuenter Roeck <linux@roeck-us.net>
Wed, 23 Apr 2025 14:18:27 +0000 (07:18 -0700)
Split spd5118 driver into common and I2C specific code to enable
adding support for I3C.

Signed-off-by: Guenter Roeck <linux@roeck-us.net>
drivers/hwmon/spd5118.c

index 358152868d961b8a37d481abf500b694f3f5540e..02eb21684c3a6614449f481291201162bf9c64c9 100644 (file)
@@ -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, &regval);
+       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, &regval);
+       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, &regval);
-       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>");