2021-05-11 12:26:25

by Sander Vanheule

[permalink] [raw]
Subject: [PATCH 3/5] mfd: Add RTL8231 core device

The RTL8231 is implemented as an MDIO device, and provides a regmap
interface for register access by the core and child devices.

The chip can also be a device on an SMI bus, a proprietary I2C-like bus
by Realtek. Since kernel support for SMI is limited, and no real-world
SMI implementations have been encountered for this device, this is
currently unimplemented. The use of the regmap interface should make any
future support relatively straightforward.

After reset, all pins are muxed to GPIO inputs before the pin drivers
are enabled. This is done to prevent accidental system resets, when a
pin is connected to the parent SoC's reset line.

Signed-off-by: Sander Vanheule <[email protected]>
---
drivers/mfd/Kconfig | 9 ++
drivers/mfd/Makefile | 1 +
drivers/mfd/rtl8231.c | 163 ++++++++++++++++++++++++++++++++++++
include/linux/mfd/rtl8231.h | 49 +++++++++++
4 files changed, 222 insertions(+)
create mode 100644 drivers/mfd/rtl8231.c
create mode 100644 include/linux/mfd/rtl8231.h

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 5c7f2b100191..0b0cf296aac4 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -1076,6 +1076,15 @@ config MFD_RDC321X
southbridge which provides access to GPIOs and Watchdog using the
southbridge PCI device configuration space.

+config MFD_RTL8231
+ tristate "Realtek RTL8231 GPIO and LED expander"
+ select MFD_CORE
+ select REGMAP
+ help
+ Support for the Realtek RTL8231 GPIO and LED expander.
+ Provides up to 37 GPIOs, 88 LEDs, and one PWM output.
+ When built as a module, this module will be named rtl8231_expander.
+
config MFD_RT5033
tristate "Richtek RT5033 Power Management IC"
depends on I2C
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 4f6d2b8a5f76..4b27c2486ccc 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -234,6 +234,7 @@ obj-$(CONFIG_MFD_MENF21BMC) += menf21bmc.o
obj-$(CONFIG_MFD_HI6421_PMIC) += hi6421-pmic-core.o
obj-$(CONFIG_MFD_HI655X_PMIC) += hi655x-pmic.o
obj-$(CONFIG_MFD_DLN2) += dln2.o
+obj-$(CONFIG_MFD_RTL8231) += rtl8231.o
obj-$(CONFIG_MFD_RT5033) += rt5033.o
obj-$(CONFIG_MFD_SKY81452) += sky81452.o

diff --git a/drivers/mfd/rtl8231.c b/drivers/mfd/rtl8231.c
new file mode 100644
index 000000000000..4db3ad23d822
--- /dev/null
+++ b/drivers/mfd/rtl8231.c
@@ -0,0 +1,163 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/bits.h>
+#include <linux/delay.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/rtl8231.h>
+#include <linux/mdio.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+static const struct reg_field RTL8231_FIELD_LED_START = REG_FIELD(RTL8231_REG_FUNC0, 1, 1);
+static const struct reg_field RTL8231_FIELD_READY_CODE = REG_FIELD(RTL8231_REG_FUNC1, 4, 9);
+static const struct reg_field RTL8231_FIELD_SOFT_RESET = REG_FIELD(RTL8231_REG_PIN_HI_CFG, 15, 15);
+
+static const struct mfd_cell rtl8231_cells[] = {
+ {
+ .name = "rtl8231-pinctrl",
+ .of_compatible = "realtek,rtl8231-pinctrl",
+ },
+ {
+ .name = "rtl8231-leds",
+ .of_compatible = "realtek,rtl8231-leds",
+ },
+};
+
+static int rtl8231_init(struct device *dev, struct regmap *map)
+{
+ struct regmap_field *field_ready_code;
+ struct regmap_field *field_soft_reset;
+ unsigned int v;
+ int err = 0;
+
+ field_ready_code = regmap_field_alloc(map, RTL8231_FIELD_READY_CODE);
+ if (IS_ERR(field_ready_code))
+ return PTR_ERR(field_ready_code);
+
+ field_soft_reset = regmap_field_alloc(map, RTL8231_FIELD_SOFT_RESET);
+ if (IS_ERR(field_soft_reset)) {
+ err = PTR_ERR(field_soft_reset);
+ goto init_out;
+ }
+
+ err = regmap_field_read(field_ready_code, &v);
+
+ if (err) {
+ dev_err(dev, "failed to read READY_CODE\n");
+ goto init_out;
+ } else if (v != RTL8231_FUNC1_READY_CODE_VALUE) {
+ dev_err(dev, "RTL8231 not present or ready 0x%x != 0x%x\n",
+ v, RTL8231_FUNC1_READY_CODE_VALUE);
+ err = -ENODEV;
+ goto init_out;
+ }
+
+ // TODO Implement reset-gpios
+ regmap_field_write(field_soft_reset, 1);
+ usleep_range(1000, 10000);
+
+ /* Do not write LED_START before configuring pins */
+ /* Select GPIO functionality for all pins and set to input */
+ regmap_write(map, RTL8231_REG_PIN_MODE0, 0xffff);
+ regmap_write(map, RTL8231_REG_GPIO_DIR0, 0xffff);
+ regmap_write(map, RTL8231_REG_PIN_MODE1, 0xffff);
+ regmap_write(map, RTL8231_REG_GPIO_DIR1, 0xffff);
+ regmap_write(map, RTL8231_REG_PIN_HI_CFG, GENMASK(4, 0) | GENMASK(9, 5));
+
+init_out:
+ regmap_field_free(field_ready_code);
+ regmap_field_free(field_soft_reset);
+ return err;
+}
+
+static int rtl8231_mdio_reg_read(void *ctx, unsigned int reg, unsigned int *val)
+{
+ struct mdio_device *mdiodev = ctx;
+ int ret;
+
+ ret = mdiobus_read(mdiodev->bus, mdiodev->addr, reg);
+ if (ret < 0)
+ return ret;
+
+ *val = ret & 0xffff;
+ return 0;
+}
+
+static int rtl8231_mdio_reg_write(void *ctx, unsigned int reg, unsigned int val)
+{
+ struct mdio_device *mdiodev = ctx;
+
+ return mdiobus_write(mdiodev->bus, mdiodev->addr, reg, val);
+}
+
+static const struct regmap_config rtl8231_regmap_config = {
+ .val_bits = 16,
+ .reg_bits = 5,
+ .max_register = RTL8231_REG_COUNT - 1,
+ .use_single_read = true,
+ .use_single_write = true,
+ .reg_format_endian = REGMAP_ENDIAN_BIG,
+ .val_format_endian = REGMAP_ENDIAN_BIG,
+ .reg_read = rtl8231_mdio_reg_read,
+ .reg_write = rtl8231_mdio_reg_write,
+};
+
+static int rtl8231_mdio_probe(struct mdio_device *mdiodev)
+{
+ struct device *dev = &mdiodev->dev;
+ struct regmap_field *led_start;
+ struct regmap *map;
+ int err;
+
+ map = devm_regmap_init(dev, NULL, mdiodev, &rtl8231_regmap_config);
+
+ if (IS_ERR(map)) {
+ dev_err(dev, "failed to init regmap\n");
+ return PTR_ERR(map);
+ }
+
+ led_start = devm_regmap_field_alloc(dev, map, RTL8231_FIELD_LED_START);
+ if (IS_ERR(led_start))
+ return PTR_ERR(led_start);
+
+ dev_set_drvdata(dev, led_start);
+
+ err = rtl8231_init(dev, map);
+ if (err)
+ return err;
+
+ /* LED_START enables power to output pins, and starts the LED engine */
+ regmap_field_write(led_start, 1);
+
+ return devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, rtl8231_cells,
+ ARRAY_SIZE(rtl8231_cells), NULL, 0, NULL);
+}
+
+static void rtl8231_mdio_remove(struct mdio_device *mdiodev)
+{
+ struct regmap_field *led_start;
+
+ led_start = dev_get_drvdata(&mdiodev->dev);
+ regmap_field_write(led_start, 0);
+}
+
+static const struct of_device_id rtl8231_of_match[] = {
+ { .compatible = "realtek,rtl8231" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, rtl8231_of_match);
+
+static struct mdio_driver rtl8231_mdio_driver = {
+ .mdiodrv.driver = {
+ .name = "rtl8231-expander",
+ .of_match_table = rtl8231_of_match,
+ },
+ .probe = rtl8231_mdio_probe,
+ .remove = rtl8231_mdio_remove,
+};
+mdio_module_driver(rtl8231_mdio_driver);
+
+MODULE_AUTHOR("Sander Vanheule <[email protected]>");
+MODULE_DESCRIPTION("Realtek RTL8231 GPIO and LED expander");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/mfd/rtl8231.h b/include/linux/mfd/rtl8231.h
new file mode 100644
index 000000000000..5af312adbf0b
--- /dev/null
+++ b/include/linux/mfd/rtl8231.h
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Register definitions the RTL8231 GPIO and LED expander chip
+ */
+
+#ifndef __LINUX_MFD_RTL8231_H
+#define __LINUX_MFD_RTL8231_H
+
+/* Chip control */
+#define RTL8231_REG_FUNC0 0x00
+#define RTL8231_FUNC0_SCAN_MODE BIT(0)
+#define RTL8231_FUNC0_SCAN_SINGLE 0
+#define RTL8231_FUNC0_SCAN_BICOLOR BIT(0)
+
+#define RTL8231_REG_FUNC1 0x01
+#define RTL8231_FUNC1_READY_CODE_VALUE 0x37
+
+/* Pin control */
+#define RTL8231_REG_PIN_MODE0 0x02
+#define RTL8231_REG_PIN_MODE1 0x03
+
+#define RTL8231_PIN_MODE_LED 0
+#define RTL8231_PIN_MODE_GPIO 1
+
+/* Pin high config: pin and GPIO control for pins 32-26 */
+#define RTL8231_REG_PIN_HI_CFG 0x04
+
+/* GPIO control registers */
+#define RTL8231_REG_GPIO_DIR0 0x05
+#define RTL8231_REG_GPIO_DIR1 0x06
+#define RTL8231_REG_GPIO_INVERT0 0x07
+#define RTL8231_REG_GPIO_INVERT1 0x08
+
+#define RTL8231_GPIO_DIR_IN 1
+#define RTL8231_GPIO_DIR_OUT 0
+
+/* GPIO data registers */
+#define RTL8231_REG_GPIO_DATA0 0x1c
+#define RTL8231_REG_GPIO_DATA1 0x1d
+#define RTL8231_REG_GPIO_DATA2 0x1e
+
+/* LED control base registers */
+#define RTL8231_REG_LED0_BASE 0x09
+#define RTL8231_REG_LED1_BASE 0x10
+#define RTL8231_REG_LED2_BASE 0x17
+
+#define RTL8231_REG_COUNT 0x1f
+
+#endif /* __LINUX_MFD_RTL8231_H */
--
2.31.1


2021-05-12 13:13:50

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH 3/5] mfd: Add RTL8231 core device

Hi Sander,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on pavel-linux-leds/for-next]
[also build test ERROR on lee-mfd/for-mfd-next pinctrl/devel v5.13-rc1]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url: https://github.com/0day-ci/linux/commits/Sander-Vanheule/RTL8231-GPIO-expander-support/20210511-202618
base: git://git.kernel.org/pub/scm/linux/kernel/git/pavel/linux-leds.git for-next
config: microblaze-randconfig-r023-20210512 (attached as .config)
compiler: microblaze-linux-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# https://github.com/0day-ci/linux/commit/e031cc2da2c2948230bacd1ca56cfe9990e1aefd
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Sander-Vanheule/RTL8231-GPIO-expander-support/20210511-202618
git checkout e031cc2da2c2948230bacd1ca56cfe9990e1aefd
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross W=1 ARCH=microblaze

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <[email protected]>

All errors (new ones prefixed by >>):

microblaze-linux-ld: drivers/mfd/rtl8231.o: in function `rtl8231_mdio_reg_write':
>> (.text+0x50): undefined reference to `mdiobus_write'
microblaze-linux-ld: drivers/mfd/rtl8231.o: in function `rtl8231_mdio_reg_read':
>> (.text+0x80): undefined reference to `mdiobus_read'
microblaze-linux-ld: drivers/mfd/rtl8231.o: in function `mdio_module_init':
>> (.init.text+0x10): undefined reference to `mdio_driver_register'
microblaze-linux-ld: drivers/mfd/rtl8231.o: in function `mdio_module_exit':
>> (.exit.text+0x10): undefined reference to `mdio_driver_unregister'

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/[email protected]


Attachments:
(No filename) (2.16 kB)
.config.gz (32.66 kB)
Download all attachments

2021-05-12 13:23:02

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH 3/5] mfd: Add RTL8231 core device

Hi Sander,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on pavel-linux-leds/for-next]
[also build test ERROR on lee-mfd/for-mfd-next pinctrl/devel v5.13-rc1]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url: https://github.com/0day-ci/linux/commits/Sander-Vanheule/RTL8231-GPIO-expander-support/20210511-202618
base: git://git.kernel.org/pub/scm/linux/kernel/git/pavel/linux-leds.git for-next
config: h8300-randconfig-r012-20210512 (attached as .config)
compiler: h8300-linux-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# https://github.com/0day-ci/linux/commit/e031cc2da2c2948230bacd1ca56cfe9990e1aefd
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Sander-Vanheule/RTL8231-GPIO-expander-support/20210511-202618
git checkout e031cc2da2c2948230bacd1ca56cfe9990e1aefd
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross W=1 ARCH=h8300

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <[email protected]>

All errors (new ones prefixed by >>):

h8300-linux-ld: drivers/mfd/rtl8231.o: in function `rtl8231_mdio_reg_write':
>> rtl8231.c:(.text+0x4f): undefined reference to `mdiobus_write'
h8300-linux-ld: drivers/mfd/rtl8231.o: in function `rtl8231_mdio_reg_read':
>> rtl8231.c:(.text+0x75): undefined reference to `mdiobus_read'
h8300-linux-ld: drivers/mfd/rtl8231.o: in function `mdio_module_init':
>> rtl8231.c:(.init.text+0xd): undefined reference to `mdio_driver_register'

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/[email protected]


Attachments:
(No filename) (2.01 kB)
.config.gz (18.34 kB)
Download all attachments

2021-05-19 20:11:25

by Lee Jones

[permalink] [raw]
Subject: Re: [PATCH 3/5] mfd: Add RTL8231 core device

On Wed, 12 May 2021, kernel test robot wrote:

> Hi Sander,
>
> Thank you for the patch! Yet something to improve:
>
> [auto build test ERROR on pavel-linux-leds/for-next]
> [also build test ERROR on lee-mfd/for-mfd-next pinctrl/devel v5.13-rc1]
> [If your patch is applied to the wrong git tree, kindly drop us a note.
> And when submitting patch, we suggest to use '--base' as documented in
> https://git-scm.com/docs/git-format-patch]
>
> url: https://github.com/0day-ci/linux/commits/Sander-Vanheule/RTL8231-GPIO-expander-support/20210511-202618
> base: git://git.kernel.org/pub/scm/linux/kernel/git/pavel/linux-leds.git for-next
> config: h8300-randconfig-r012-20210512 (attached as .config)
> compiler: h8300-linux-gcc (GCC) 9.3.0
> reproduce (this is a W=1 build):
> wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
> chmod +x ~/bin/make.cross
> # https://github.com/0day-ci/linux/commit/e031cc2da2c2948230bacd1ca56cfe9990e1aefd
> git remote add linux-review https://github.com/0day-ci/linux
> git fetch --no-tags linux-review Sander-Vanheule/RTL8231-GPIO-expander-support/20210511-202618
> git checkout e031cc2da2c2948230bacd1ca56cfe9990e1aefd
> # save the attached .config to linux build tree
> COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross W=1 ARCH=h8300
>
> If you fix the issue, kindly add following tag as appropriate
> Reported-by: kernel test robot <[email protected]>
>
> All errors (new ones prefixed by >>):
>
> h8300-linux-ld: drivers/mfd/rtl8231.o: in function `rtl8231_mdio_reg_write':
> >> rtl8231.c:(.text+0x4f): undefined reference to `mdiobus_write'
> h8300-linux-ld: drivers/mfd/rtl8231.o: in function `rtl8231_mdio_reg_read':
> >> rtl8231.c:(.text+0x75): undefined reference to `mdiobus_read'
> h8300-linux-ld: drivers/mfd/rtl8231.o: in function `mdio_module_init':
> >> rtl8231.c:(.init.text+0xd): undefined reference to `mdio_driver_register'
>
> ---
> 0-DAY CI Kernel Test Service, Intel Corporation
> https://lists.01.org/hyperkitty/list/[email protected]

Please could you take a look at these failures.

Either fix them up or report a false positive.

--
Lee Jones [李琼斯]
Senior Technical Lead - Developer Services
Linaro.org │ Open source software for Arm SoCs
Follow Linaro: Facebook | Twitter | Blog

2021-05-19 20:13:00

by Sander Vanheule

[permalink] [raw]
Subject: Re: [PATCH 3/5] mfd: Add RTL8231 core device

On Wed, 2021-05-19 at 15:58 +0100, Lee Jones wrote:
> On Wed, 12 May 2021, kernel test robot wrote:
>
> > Hi Sander,
> >
> > Thank you for the patch! Yet something to improve:
> >
> > [auto build test ERROR on pavel-linux-leds/for-next]
> > [also build test ERROR on lee-mfd/for-mfd-next pinctrl/devel v5.13-rc1]
> > [If your patch is applied to the wrong git tree, kindly drop us a note.
> > And when submitting patch, we suggest to use '--base' as documented in
> > https://git-scm.com/docs/git-format-patch]
> >
> > url:   
> > https://github.com/0day-ci/linux/commits/Sander-Vanheule/RTL8231-GPIO-expander-support/20210511-202618
> > base:   git://git.kernel.org/pub/scm/linux/kernel/git/pavel/linux-leds.git
> > for-next
> > config: h8300-randconfig-r012-20210512 (attached as .config)
> > compiler: h8300-linux-gcc (GCC) 9.3.0
> > reproduce (this is a W=1 build):
> >         wget
> > https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O
> > ~/bin/make.cross
> >         chmod +x ~/bin/make.cross
> >         #
> > https://github.com/0day-ci/linux/commit/e031cc2da2c2948230bacd1ca56cfe9990e1aefd
> >         git remote add linux-review https://github.com/0day-ci/linux
> >         git fetch --no-tags linux-review Sander-Vanheule/RTL8231-GPIO-
> > expander-support/20210511-202618
> >         git checkout e031cc2da2c2948230bacd1ca56cfe9990e1aefd
> >         # save the attached .config to linux build tree
> >         COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross W=1
> > ARCH=h8300
> >
> > If you fix the issue, kindly add following tag as appropriate
> > Reported-by: kernel test robot <[email protected]>
> >
> > All errors (new ones prefixed by >>):
> >
> >    h8300-linux-ld: drivers/mfd/rtl8231.o: in function
> > `rtl8231_mdio_reg_write':
> > > > rtl8231.c:(.text+0x4f): undefined reference to `mdiobus_write'
> >    h8300-linux-ld: drivers/mfd/rtl8231.o: in function `rtl8231_mdio_reg_read':
> > > > rtl8231.c:(.text+0x75): undefined reference to `mdiobus_read'
> >    h8300-linux-ld: drivers/mfd/rtl8231.o: in function `mdio_module_init':
> > > > rtl8231.c:(.init.text+0xd): undefined reference to `mdio_driver_register'
> >
> > ---
> > 0-DAY CI Kernel Test Service, Intel Corporation
> > https://lists.01.org/hyperkitty/list/[email protected]
>
> Please could you take a look at these failures.
>
> Either fix them up or report a false positive.

Hi Lee,

These were caused by a missing dependency on MDIO_BUS. This should be resolved
in the v2 series.

https://lore.kernel.org/lkml/f1ca940216c0accfc804afee2dbe46d260d890ae.1621279162.git.sander@svanheule.net/

I wasn't sure how to attribute this to the test bot, since the depedency was
partly resolved through another patch.

Best,
Sander