Merge series "RTL8231 GPIO expander support" from Sander Vanheule <sander@svanheule.net>:
The RTL8231 GPIO and LED expander can be configured for use as an MDIO or SMI
bus device. Currently only the MDIO mode is supported, although SMI mode
support should be fairly straightforward, once an SMI bus driver is available.
Provided features by the RTL8231:
- Up to 37 GPIOs
- Configurable drive strength: 8mA or 4mA (currently unsupported)
- Input debouncing on high GPIOs (currently unsupported)
- Up to 88 LEDs in multiple scan matrix groups
- On, off, or one of six toggling intervals
- "single-color mode": 2×36 single color LEDs + 8 bi-color LEDs
- "bi-color mode": (12 + 2×6) bi-color LEDs + 24 single color LEDs
- Up to one PWM output (currently unsupported)
- Fixed duty cycle, 8 selectable frequencies (1.2kHz - 4.8kHz)
Register access is provided through a new MDIO regmap provider. The GPIO
controller uses gpio-regmap, although a patch is required to support a
limitation of the chip.
There remain some log warnings when probing the device, possibly due to the way
I'm using the MFD subsystem. Would it be possible to avoid these?
[ 2.602242] rtl8231-pinctrl: Failed to locate of_node [id: -2]
[ 2.609380] rtl8231-pinctrl rtl8231-pinctrl.0.auto: no of_node; not parsing pinctrl DT
When no 'leds' sub-node is specified:
[ 2.922262] rtl8231-leds: Failed to locate of_node [id: -2]
[ 2.967149] rtl8231-leds rtl8231-leds.1.auto: no of_node; not parsing pinctrl DT
[ 2.975673] rtl8231-leds rtl8231-leds.1.auto: scan mode missing or invalid
[ 2.983531] rtl8231-leds: probe of rtl8231-leds.1.auto failed with error -22
Changes since v1:
- Reintroduce MDIO regmap, with fixed Kconfig dependencies
- Add configurable dir/value order for gpio-regmap direction_out call
- Drop allocations for regmap fields that are used only on init
- Move some definitions to MFD header
- Add PM ops to replace driver remove for MFD
- Change pinctrl driver to (modified) gpio-regmap
- Change leds driver to use fwnode
Link: https://lore.kernel.org/lkml/cover.1620735871.git.sander@svanheule.net/
Changes since RFC:
- Dropped MDIO regmap interface. I was unable to resolve the Kconfig
dependency issue, so have reverted to using regmap_config.reg_read/write.
- Added pinctrl support
- Added LED support
- Changed root device to MFD, with pinctrl and leds child devices. Root
device is now an mdio_device driver.
Link: https://lore.kernel.org/linux-gpio/cover.1617914861.git.sander@svanheule.net/
Sander Vanheule (7):
regmap: Add MDIO bus support
gpio: regmap: Add configurable dir/value order
dt-bindings: leds: Binding for RTL8231 scan matrix
dt-bindings: mfd: Binding for RTL8231
mfd: Add RTL8231 core device
pinctrl: Add RTL8231 pin control and GPIO support
leds: Add support for RTL8231 LED scan matrix
.../bindings/leds/realtek,rtl8231-leds.yaml | 159 ++++++++
.../bindings/mfd/realtek,rtl8231.yaml | 202 ++++++++++
drivers/base/regmap/Kconfig | 6 +-
drivers/base/regmap/Makefile | 1 +
drivers/base/regmap/regmap-mdio.c | 57 +++
drivers/gpio/gpio-regmap.c | 20 +-
drivers/leds/Kconfig | 10 +
drivers/leds/Makefile | 1 +
drivers/leds/leds-rtl8231.c | 293 ++++++++++++++
drivers/mfd/Kconfig | 9 +
drivers/mfd/Makefile | 1 +
drivers/mfd/rtl8231.c | 153 +++++++
drivers/pinctrl/Kconfig | 11 +
drivers/pinctrl/Makefile | 1 +
drivers/pinctrl/pinctrl-rtl8231.c | 377 ++++++++++++++++++
include/linux/gpio/regmap.h | 3 +
include/linux/mfd/rtl8231.h | 57 +++
include/linux/regmap.h | 36 ++
18 files changed, 1393 insertions(+), 4 deletions(-)
create mode 100644 Documentation/devicetree/bindings/leds/realtek,rtl8231-leds.yaml
create mode 100644 Documentation/devicetree/bindings/mfd/realtek,rtl8231.yaml
create mode 100644 drivers/base/regmap/regmap-mdio.c
create mode 100644 drivers/leds/leds-rtl8231.c
create mode 100644 drivers/mfd/rtl8231.c
create mode 100644 drivers/pinctrl/pinctrl-rtl8231.c
create mode 100644 include/linux/mfd/rtl8231.h
base-commit: 6efb943b86
--
2.31.1
This commit is contained in:
Коммит
9dee1f9fc5
|
@ -4,8 +4,9 @@
|
|||
# subsystems should select the appropriate symbols.
|
||||
|
||||
config REGMAP
|
||||
default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ || REGMAP_SOUNDWIRE || REGMAP_SOUNDWIRE_MBQ || REGMAP_SCCB || REGMAP_I3C || REGMAP_SPI_AVMM)
|
||||
default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ || REGMAP_SOUNDWIRE || REGMAP_SOUNDWIRE_MBQ || REGMAP_SCCB || REGMAP_I3C || REGMAP_SPI_AVMM || REGMAP_MDIO)
|
||||
select IRQ_DOMAIN if REGMAP_IRQ
|
||||
select MDIO_BUS if REGMAP_MDIO
|
||||
bool
|
||||
|
||||
config REGCACHE_COMPRESSED
|
||||
|
@ -36,6 +37,9 @@ config REGMAP_W1
|
|||
tristate
|
||||
depends on W1
|
||||
|
||||
config REGMAP_MDIO
|
||||
tristate
|
||||
|
||||
config REGMAP_MMIO
|
||||
tristate
|
||||
|
||||
|
|
|
@ -19,3 +19,4 @@ obj-$(CONFIG_REGMAP_SOUNDWIRE_MBQ) += regmap-sdw-mbq.o
|
|||
obj-$(CONFIG_REGMAP_SCCB) += regmap-sccb.o
|
||||
obj-$(CONFIG_REGMAP_I3C) += regmap-i3c.o
|
||||
obj-$(CONFIG_REGMAP_SPI_AVMM) += regmap-spi-avmm.o
|
||||
obj-$(CONFIG_REGMAP_MDIO) += regmap-mdio.o
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/mdio.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
static int regmap_mdio_read(void *context, unsigned int reg, unsigned int *val)
|
||||
{
|
||||
struct mdio_device *mdio_dev = context;
|
||||
int ret;
|
||||
|
||||
ret = mdiobus_read(mdio_dev->bus, mdio_dev->addr, reg);
|
||||
*val = ret & 0xffff;
|
||||
|
||||
return ret < 0 ? ret : 0;
|
||||
}
|
||||
|
||||
static int regmap_mdio_write(void *context, unsigned int reg, unsigned int val)
|
||||
{
|
||||
struct mdio_device *mdio_dev = context;
|
||||
|
||||
return mdiobus_write(mdio_dev->bus, mdio_dev->addr, reg, val);
|
||||
}
|
||||
|
||||
static const struct regmap_bus regmap_mdio_bus = {
|
||||
.reg_write = regmap_mdio_write,
|
||||
.reg_read = regmap_mdio_read,
|
||||
};
|
||||
|
||||
struct regmap *__regmap_init_mdio(struct mdio_device *mdio_dev,
|
||||
const struct regmap_config *config, struct lock_class_key *lock_key,
|
||||
const char *lock_name)
|
||||
{
|
||||
if (config->reg_bits != 5 || config->val_bits != 16)
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
|
||||
return __regmap_init(&mdio_dev->dev, ®map_mdio_bus, mdio_dev, config,
|
||||
lock_key, lock_name);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__regmap_init_mdio);
|
||||
|
||||
struct regmap *__devm_regmap_init_mdio(struct mdio_device *mdio_dev,
|
||||
const struct regmap_config *config, struct lock_class_key *lock_key,
|
||||
const char *lock_name)
|
||||
{
|
||||
if (config->reg_bits != 5 || config->val_bits != 16)
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
|
||||
return __devm_regmap_init(&mdio_dev->dev, ®map_mdio_bus, mdio_dev,
|
||||
config, lock_key, lock_name);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__devm_regmap_init_mdio);
|
||||
|
||||
MODULE_AUTHOR("Sander Vanheule <sander@svanheule.net>");
|
||||
MODULE_DESCRIPTION("Regmap MDIO Module");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -27,6 +27,7 @@ struct device_node;
|
|||
struct i2c_client;
|
||||
struct i3c_device;
|
||||
struct irq_domain;
|
||||
struct mdio_device;
|
||||
struct slim_device;
|
||||
struct spi_device;
|
||||
struct spmi_device;
|
||||
|
@ -540,6 +541,10 @@ struct regmap *__regmap_init_i2c(struct i2c_client *i2c,
|
|||
const struct regmap_config *config,
|
||||
struct lock_class_key *lock_key,
|
||||
const char *lock_name);
|
||||
struct regmap *__regmap_init_mdio(struct mdio_device *mdio_dev,
|
||||
const struct regmap_config *config,
|
||||
struct lock_class_key *lock_key,
|
||||
const char *lock_name);
|
||||
struct regmap *__regmap_init_sccb(struct i2c_client *i2c,
|
||||
const struct regmap_config *config,
|
||||
struct lock_class_key *lock_key,
|
||||
|
@ -596,6 +601,10 @@ struct regmap *__devm_regmap_init_i2c(struct i2c_client *i2c,
|
|||
const struct regmap_config *config,
|
||||
struct lock_class_key *lock_key,
|
||||
const char *lock_name);
|
||||
struct regmap *__devm_regmap_init_mdio(struct mdio_device *mdio_dev,
|
||||
const struct regmap_config *config,
|
||||
struct lock_class_key *lock_key,
|
||||
const char *lock_name);
|
||||
struct regmap *__devm_regmap_init_sccb(struct i2c_client *i2c,
|
||||
const struct regmap_config *config,
|
||||
struct lock_class_key *lock_key,
|
||||
|
@ -699,6 +708,19 @@ int regmap_attach_dev(struct device *dev, struct regmap *map,
|
|||
__regmap_lockdep_wrapper(__regmap_init_i2c, #config, \
|
||||
i2c, config)
|
||||
|
||||
/**
|
||||
* regmap_init_mdio() - Initialise register map
|
||||
*
|
||||
* @mdio_dev: Device that will be interacted with
|
||||
* @config: Configuration for register map
|
||||
*
|
||||
* The return value will be an ERR_PTR() on error or a valid pointer to
|
||||
* a struct regmap.
|
||||
*/
|
||||
#define regmap_init_mdio(mdio_dev, config) \
|
||||
__regmap_lockdep_wrapper(__regmap_init_mdio, #config, \
|
||||
mdio_dev, config)
|
||||
|
||||
/**
|
||||
* regmap_init_sccb() - Initialise register map
|
||||
*
|
||||
|
@ -890,6 +912,20 @@ bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg);
|
|||
__regmap_lockdep_wrapper(__devm_regmap_init_i2c, #config, \
|
||||
i2c, config)
|
||||
|
||||
/**
|
||||
* devm_regmap_init_mdio() - Initialise managed register map
|
||||
*
|
||||
* @mdio_dev: Device that will be interacted with
|
||||
* @config: Configuration for register map
|
||||
*
|
||||
* The return value will be an ERR_PTR() on error or a valid pointer
|
||||
* to a struct regmap. The regmap will be automatically freed by the
|
||||
* device management code.
|
||||
*/
|
||||
#define devm_regmap_init_mdio(mdio_dev, config) \
|
||||
__regmap_lockdep_wrapper(__devm_regmap_init_mdio, #config, \
|
||||
mdio_dev, config)
|
||||
|
||||
/**
|
||||
* devm_regmap_init_sccb() - Initialise managed register map
|
||||
*
|
||||
|
|
Загрузка…
Ссылка в новой задаче