aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAkinobu Mita <akinobu.mita@gmail.com>2018-07-16 11:47:48 -0400
committerMark Brown <broonie@kernel.org>2018-07-18 10:45:23 -0400
commitbcf7eac3d97f49d8400ba52c71bee5934bf20093 (patch)
treebfcce867a916da1d43c9c2cbbb78ed76ce226bc4
parentce397d215ccd07b8ae3f71db689aedb85d56ab40 (diff)
regmap: add SCCB support
This adds Serial Camera Control Bus (SCCB) support for regmap API that is intended to be used by some of Omnivision sensor drivers. The ov772x and ov9650 drivers are going to use this SCCB regmap API. The ov772x driver was previously only worked with the i2c controller drivers that support I2C_FUNC_PROTOCOL_MANGLING, because the ov772x device doesn't support repeated starts. After commit 0b964d183cbf ("media: ov772x: allow i2c controllers without I2C_FUNC_PROTOCOL_MANGLING"), reading ov772x register is replaced with issuing two separated i2c messages in order to avoid repeated start. Using this SCCB regmap hides the implementation detail. The ov9650 driver also issues two separated i2c messages to read the registers as the device doesn't support repeated start. So it can make use of this SCCB regmap. Cc: Mark Brown <broonie@kernel.org> Cc: Peter Rosin <peda@axentia.se> Cc: Sebastian Reichel <sebastian.reichel@collabora.co.uk> Cc: Wolfram Sang <wsa@the-dreams.de> Cc: Sylwester Nawrocki <s.nawrocki@samsung.com> Cc: Jacopo Mondi <jacopo+renesas@jmondi.org> Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Cc: Hans Verkuil <hans.verkuil@cisco.com> Cc: Sakari Ailus <sakari.ailus@linux.intel.com> Cc: Mauro Carvalho Chehab <mchehab@s-opensource.com> Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--drivers/base/regmap/Kconfig4
-rw-r--r--drivers/base/regmap/Makefile1
-rw-r--r--drivers/base/regmap/regmap-sccb.c128
-rw-r--r--include/linux/regmap.h35
4 files changed, 168 insertions, 0 deletions
diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig
index aff34c0c2a3e..6ad5ef48b61e 100644
--- a/drivers/base/regmap/Kconfig
+++ b/drivers/base/regmap/Kconfig
@@ -45,3 +45,7 @@ config REGMAP_IRQ
45config REGMAP_SOUNDWIRE 45config REGMAP_SOUNDWIRE
46 tristate 46 tristate
47 depends on SOUNDWIRE_BUS 47 depends on SOUNDWIRE_BUS
48
49config REGMAP_SCCB
50 tristate
51 depends on I2C
diff --git a/drivers/base/regmap/Makefile b/drivers/base/regmap/Makefile
index 5ed0023fabda..f5b4e8851d00 100644
--- a/drivers/base/regmap/Makefile
+++ b/drivers/base/regmap/Makefile
@@ -15,3 +15,4 @@ obj-$(CONFIG_REGMAP_MMIO) += regmap-mmio.o
15obj-$(CONFIG_REGMAP_IRQ) += regmap-irq.o 15obj-$(CONFIG_REGMAP_IRQ) += regmap-irq.o
16obj-$(CONFIG_REGMAP_W1) += regmap-w1.o 16obj-$(CONFIG_REGMAP_W1) += regmap-w1.o
17obj-$(CONFIG_REGMAP_SOUNDWIRE) += regmap-sdw.o 17obj-$(CONFIG_REGMAP_SOUNDWIRE) += regmap-sdw.o
18obj-$(CONFIG_REGMAP_SCCB) += regmap-sccb.o
diff --git a/drivers/base/regmap/regmap-sccb.c b/drivers/base/regmap/regmap-sccb.c
new file mode 100644
index 000000000000..b6eb876ea819
--- /dev/null
+++ b/drivers/base/regmap/regmap-sccb.c
@@ -0,0 +1,128 @@
1// SPDX-License-Identifier: GPL-2.0
2// Register map access API - SCCB support
3
4#include <linux/regmap.h>
5#include <linux/i2c.h>
6#include <linux/module.h>
7
8#include "internal.h"
9
10/**
11 * sccb_is_available - Check if the adapter supports SCCB protocol
12 * @adap: I2C adapter
13 *
14 * Return true if the I2C adapter is capable of using SCCB helper functions,
15 * false otherwise.
16 */
17static bool sccb_is_available(struct i2c_adapter *adap)
18{
19 u32 needed_funcs = I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA;
20
21 /*
22 * If we ever want support for hardware doing SCCB natively, we will
23 * introduce a sccb_xfer() callback to struct i2c_algorithm and check
24 * for it here.
25 */
26
27 return (i2c_get_functionality(adap) & needed_funcs) == needed_funcs;
28}
29
30/**
31 * regmap_sccb_read - Read data from SCCB slave device
32 * @context: Device that will be interacted wit
33 * @reg: Register to be read from
34 * @val: Pointer to store read value
35 *
36 * This executes the 2-phase write transmission cycle that is followed by a
37 * 2-phase read transmission cycle, returning negative errno else zero on
38 * success.
39 */
40static int regmap_sccb_read(void *context, unsigned int reg, unsigned int *val)
41{
42 struct device *dev = context;
43 struct i2c_client *i2c = to_i2c_client(dev);
44 int ret;
45 union i2c_smbus_data data;
46
47 i2c_lock_bus(i2c->adapter, I2C_LOCK_SEGMENT);
48
49 ret = __i2c_smbus_xfer(i2c->adapter, i2c->addr, i2c->flags,
50 I2C_SMBUS_WRITE, reg, I2C_SMBUS_BYTE, NULL);
51 if (ret < 0)
52 goto out;
53
54 ret = __i2c_smbus_xfer(i2c->adapter, i2c->addr, i2c->flags,
55 I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &data);
56 if (ret < 0)
57 goto out;
58
59 *val = data.byte;
60out:
61 i2c_unlock_bus(i2c->adapter, I2C_LOCK_SEGMENT);
62
63 return ret;
64}
65
66/**
67 * regmap_sccb_write - Write data to SCCB slave device
68 * @context: Device that will be interacted wit
69 * @reg: Register to write to
70 * @val: Value to be written
71 *
72 * This executes the SCCB 3-phase write transmission cycle, returning negative
73 * errno else zero on success.
74 */
75static int regmap_sccb_write(void *context, unsigned int reg, unsigned int val)
76{
77 struct device *dev = context;
78 struct i2c_client *i2c = to_i2c_client(dev);
79
80 return i2c_smbus_write_byte_data(i2c, reg, val);
81}
82
83static struct regmap_bus regmap_sccb_bus = {
84 .reg_write = regmap_sccb_write,
85 .reg_read = regmap_sccb_read,
86};
87
88static const struct regmap_bus *regmap_get_sccb_bus(struct i2c_client *i2c,
89 const struct regmap_config *config)
90{
91 if (config->val_bits == 8 && config->reg_bits == 8 &&
92 sccb_is_available(i2c->adapter))
93 return &regmap_sccb_bus;
94
95 return ERR_PTR(-ENOTSUPP);
96}
97
98struct regmap *__regmap_init_sccb(struct i2c_client *i2c,
99 const struct regmap_config *config,
100 struct lock_class_key *lock_key,
101 const char *lock_name)
102{
103 const struct regmap_bus *bus = regmap_get_sccb_bus(i2c, config);
104
105 if (IS_ERR(bus))
106 return ERR_CAST(bus);
107
108 return __regmap_init(&i2c->dev, bus, &i2c->dev, config,
109 lock_key, lock_name);
110}
111EXPORT_SYMBOL_GPL(__regmap_init_sccb);
112
113struct regmap *__devm_regmap_init_sccb(struct i2c_client *i2c,
114 const struct regmap_config *config,
115 struct lock_class_key *lock_key,
116 const char *lock_name)
117{
118 const struct regmap_bus *bus = regmap_get_sccb_bus(i2c, config);
119
120 if (IS_ERR(bus))
121 return ERR_CAST(bus);
122
123 return __devm_regmap_init(&i2c->dev, bus, &i2c->dev, config,
124 lock_key, lock_name);
125}
126EXPORT_SYMBOL_GPL(__devm_regmap_init_sccb);
127
128MODULE_LICENSE("GPL v2");
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index 4f38068ffb71..52bf358e2c73 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -514,6 +514,10 @@ struct regmap *__regmap_init_i2c(struct i2c_client *i2c,
514 const struct regmap_config *config, 514 const struct regmap_config *config,
515 struct lock_class_key *lock_key, 515 struct lock_class_key *lock_key,
516 const char *lock_name); 516 const char *lock_name);
517struct regmap *__regmap_init_sccb(struct i2c_client *i2c,
518 const struct regmap_config *config,
519 struct lock_class_key *lock_key,
520 const char *lock_name);
517struct regmap *__regmap_init_slimbus(struct slim_device *slimbus, 521struct regmap *__regmap_init_slimbus(struct slim_device *slimbus,
518 const struct regmap_config *config, 522 const struct regmap_config *config,
519 struct lock_class_key *lock_key, 523 struct lock_class_key *lock_key,
@@ -558,6 +562,10 @@ struct regmap *__devm_regmap_init_i2c(struct i2c_client *i2c,
558 const struct regmap_config *config, 562 const struct regmap_config *config,
559 struct lock_class_key *lock_key, 563 struct lock_class_key *lock_key,
560 const char *lock_name); 564 const char *lock_name);
565struct regmap *__devm_regmap_init_sccb(struct i2c_client *i2c,
566 const struct regmap_config *config,
567 struct lock_class_key *lock_key,
568 const char *lock_name);
561struct regmap *__devm_regmap_init_spi(struct spi_device *dev, 569struct regmap *__devm_regmap_init_spi(struct spi_device *dev,
562 const struct regmap_config *config, 570 const struct regmap_config *config,
563 struct lock_class_key *lock_key, 571 struct lock_class_key *lock_key,
@@ -646,6 +654,19 @@ int regmap_attach_dev(struct device *dev, struct regmap *map,
646 i2c, config) 654 i2c, config)
647 655
648/** 656/**
657 * regmap_init_sccb() - Initialise register map
658 *
659 * @i2c: Device that will be interacted with
660 * @config: Configuration for register map
661 *
662 * The return value will be an ERR_PTR() on error or a valid pointer to
663 * a struct regmap.
664 */
665#define regmap_init_sccb(i2c, config) \
666 __regmap_lockdep_wrapper(__regmap_init_sccb, #config, \
667 i2c, config)
668
669/**
649 * regmap_init_slimbus() - Initialise register map 670 * regmap_init_slimbus() - Initialise register map
650 * 671 *
651 * @slimbus: Device that will be interacted with 672 * @slimbus: Device that will be interacted with
@@ -798,6 +819,20 @@ bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg);
798 i2c, config) 819 i2c, config)
799 820
800/** 821/**
822 * devm_regmap_init_sccb() - Initialise managed register map
823 *
824 * @i2c: Device that will be interacted with
825 * @config: Configuration for register map
826 *
827 * The return value will be an ERR_PTR() on error or a valid pointer
828 * to a struct regmap. The regmap will be automatically freed by the
829 * device management code.
830 */
831#define devm_regmap_init_sccb(i2c, config) \
832 __regmap_lockdep_wrapper(__devm_regmap_init_sccb, #config, \
833 i2c, config)
834
835/**
801 * devm_regmap_init_spi() - Initialise register map 836 * devm_regmap_init_spi() - Initialise register map
802 * 837 *
803 * @dev: Device that will be interacted with 838 * @dev: Device that will be interacted with