regmap-sccb.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. // SPDX-License-Identifier: GPL-2.0
  2. // Register map access API - SCCB support
  3. #include <linux/i2c.h>
  4. #include <linux/module.h>
  5. #include <linux/regmap.h>
  6. #include "internal.h"
  7. /**
  8. * sccb_is_available - Check if the adapter supports SCCB protocol
  9. * @adap: I2C adapter
  10. *
  11. * Return true if the I2C adapter is capable of using SCCB helper functions,
  12. * false otherwise.
  13. */
  14. static bool sccb_is_available(struct i2c_adapter *adap)
  15. {
  16. u32 needed_funcs = I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA;
  17. /*
  18. * If we ever want support for hardware doing SCCB natively, we will
  19. * introduce a sccb_xfer() callback to struct i2c_algorithm and check
  20. * for it here.
  21. */
  22. return (i2c_get_functionality(adap) & needed_funcs) == needed_funcs;
  23. }
  24. /**
  25. * regmap_sccb_read - Read data from SCCB slave device
  26. * @context: Device that will be interacted with
  27. * @reg: Register to be read from
  28. * @val: Pointer to store read value
  29. *
  30. * This executes the 2-phase write transmission cycle that is followed by a
  31. * 2-phase read transmission cycle, returning negative errno else zero on
  32. * success.
  33. */
  34. static int regmap_sccb_read(void *context, unsigned int reg, unsigned int *val)
  35. {
  36. struct device *dev = context;
  37. struct i2c_client *i2c = to_i2c_client(dev);
  38. int ret;
  39. union i2c_smbus_data data;
  40. i2c_lock_bus(i2c->adapter, I2C_LOCK_SEGMENT);
  41. ret = __i2c_smbus_xfer(i2c->adapter, i2c->addr, i2c->flags,
  42. I2C_SMBUS_WRITE, reg, I2C_SMBUS_BYTE, NULL);
  43. if (ret < 0)
  44. goto out;
  45. ret = __i2c_smbus_xfer(i2c->adapter, i2c->addr, i2c->flags,
  46. I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &data);
  47. if (ret < 0)
  48. goto out;
  49. *val = data.byte;
  50. out:
  51. i2c_unlock_bus(i2c->adapter, I2C_LOCK_SEGMENT);
  52. return ret;
  53. }
  54. /**
  55. * regmap_sccb_write - Write data to SCCB slave device
  56. * @context: Device that will be interacted with
  57. * @reg: Register to write to
  58. * @val: Value to be written
  59. *
  60. * This executes the SCCB 3-phase write transmission cycle, returning negative
  61. * errno else zero on success.
  62. */
  63. static int regmap_sccb_write(void *context, unsigned int reg, unsigned int val)
  64. {
  65. struct device *dev = context;
  66. struct i2c_client *i2c = to_i2c_client(dev);
  67. return i2c_smbus_write_byte_data(i2c, reg, val);
  68. }
  69. static const struct regmap_bus regmap_sccb_bus = {
  70. .reg_write = regmap_sccb_write,
  71. .reg_read = regmap_sccb_read,
  72. };
  73. static const struct regmap_bus *regmap_get_sccb_bus(struct i2c_client *i2c,
  74. const struct regmap_config *config)
  75. {
  76. if (config->val_bits == 8 && config->reg_bits == 8 &&
  77. sccb_is_available(i2c->adapter))
  78. return &regmap_sccb_bus;
  79. return ERR_PTR(-ENOTSUPP);
  80. }
  81. struct regmap *__regmap_init_sccb(struct i2c_client *i2c,
  82. const struct regmap_config *config,
  83. struct lock_class_key *lock_key,
  84. const char *lock_name)
  85. {
  86. const struct regmap_bus *bus = regmap_get_sccb_bus(i2c, config);
  87. if (IS_ERR(bus))
  88. return ERR_CAST(bus);
  89. return __regmap_init(&i2c->dev, bus, &i2c->dev, config,
  90. lock_key, lock_name);
  91. }
  92. EXPORT_SYMBOL_GPL(__regmap_init_sccb);
  93. struct regmap *__devm_regmap_init_sccb(struct i2c_client *i2c,
  94. const struct regmap_config *config,
  95. struct lock_class_key *lock_key,
  96. const char *lock_name)
  97. {
  98. const struct regmap_bus *bus = regmap_get_sccb_bus(i2c, config);
  99. if (IS_ERR(bus))
  100. return ERR_CAST(bus);
  101. return __devm_regmap_init(&i2c->dev, bus, &i2c->dev, config,
  102. lock_key, lock_name);
  103. }
  104. EXPORT_SYMBOL_GPL(__devm_regmap_init_sccb);
  105. MODULE_LICENSE("GPL v2");