From: Lee Jones <lee@kernel.org>
To: mathieu.dubois-briand@bootlin.com
Cc: "Rob Herring" <robh@kernel.org>,
"Krzysztof Kozlowski" <krzk+dt@kernel.org>,
"Conor Dooley" <conor+dt@kernel.org>,
"Kamel Bouhara" <kamel.bouhara@bootlin.com>,
"Linus Walleij" <linus.walleij@linaro.org>,
"Bartosz Golaszewski" <brgl@bgdev.pl>,
"Dmitry Torokhov" <dmitry.torokhov@gmail.com>,
"Uwe Kleine-König" <ukleinek@kernel.org>,
"Michael Walle" <mwalle@kernel.org>,
"Mark Brown" <broonie@kernel.org>,
"Greg Kroah-Hartman" <gregkh@linuxfoundation.org>,
"Rafael J. Wysocki" <rafael@kernel.org>,
"Danilo Krummrich" <dakr@kernel.org>,
devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-gpio@vger.kernel.org, linux-input@vger.kernel.org,
linux-pwm@vger.kernel.org, andriy.shevchenko@intel.com,
"Grégory Clement" <gregory.clement@bootlin.com>,
"Thomas Petazzoni" <thomas.petazzoni@bootlin.com>
Subject: Re: [PATCH v7 02/11] mfd: Add max7360 support
Date: Thu, 1 May 2025 13:59:43 +0100 [thread overview]
Message-ID: <20250501125943.GN1567507@google.com> (raw)
In-Reply-To: <20250428-mdb-max7360-support-v7-2-4e0608d0a7ff@bootlin.com>
On Mon, 28 Apr 2025, mathieu.dubois-briand@bootlin.com wrote:
> From: Kamel Bouhara <kamel.bouhara@bootlin.com>
>
> Add core driver to support MAX7360 i2c chip, multi function device
> with keypad, GPIO, PWM, GPO and rotary encoder submodules.
>
> Signed-off-by: Kamel Bouhara <kamel.bouhara@bootlin.com>
> Co-developed-by: Mathieu Dubois-Briand <mathieu.dubois-briand@bootlin.com>
> Signed-off-by: Mathieu Dubois-Briand <mathieu.dubois-briand@bootlin.com>
> ---
> drivers/mfd/Kconfig | 14 ++++
> drivers/mfd/Makefile | 1 +
> drivers/mfd/max7360.c | 184 ++++++++++++++++++++++++++++++++++++++++++++
> include/linux/mfd/max7360.h | 109 ++++++++++++++++++++++++++
> 4 files changed, 308 insertions(+)
Getting there. Couple of nits. Last push!
> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index 22b936310039..c2998c6ce54c 100644
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -2422,5 +2422,19 @@ config MFD_UPBOARD_FPGA
> To compile this driver as a module, choose M here: the module will be
> called upboard-fpga.
>
> +config MFD_MAX7360
> + tristate "Maxim MAX7360 I2C IO Expander"
> + depends on I2C
> + select MFD_CORE
> + select REGMAP_I2C
> + select REGMAP_IRQ
> + help
> + Say yes here to add support for Maxim MAX7360 device, embedding
> + keypad, rotary encoder, PWM and GPIO features.
> +
> + This driver provides common support for accessing the device;
> + additional drivers must be enabled in order to use the functionality
> + of the device.
> +
> endmenu
> endif
> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> index 948cbdf42a18..add9ff58eb25 100644
> --- a/drivers/mfd/Makefile
> +++ b/drivers/mfd/Makefile
> @@ -162,6 +162,7 @@ obj-$(CONFIG_MFD_DA9063) += da9063.o
> obj-$(CONFIG_MFD_DA9150) += da9150-core.o
>
> obj-$(CONFIG_MFD_MAX14577) += max14577.o
> +obj-$(CONFIG_MFD_MAX7360) += max7360.o
> obj-$(CONFIG_MFD_MAX77541) += max77541.o
> obj-$(CONFIG_MFD_MAX77620) += max77620.o
> obj-$(CONFIG_MFD_MAX77650) += max77650.o
> diff --git a/drivers/mfd/max7360.c b/drivers/mfd/max7360.c
> new file mode 100644
> index 000000000000..9a223a9b409d
> --- /dev/null
> +++ b/drivers/mfd/max7360.c
> @@ -0,0 +1,184 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Maxim MAX7360 Core Driver
> + *
> + * Copyright 2025 Bootlin
> + *
> + * Author: Kamel Bouhara <kamel.bouhara@bootlin.com>
> + * Author: Mathieu Dubois-Briand <mathieu.dubois-briand@bootlin.com>
> + */
> +
> +#include <linux/array_size.h>
> +#include <linux/bits.h>
> +#include <linux/delay.h>
> +#include <linux/device/devres.h>
> +#include <linux/dev_printk.h>
> +#include <linux/err.h>
> +#include <linux/i2c.h>
> +#include <linux/interrupt.h>
> +#include <linux/mfd/core.h>
> +#include <linux/mfd/max7360.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/module.h>
> +#include <linux/regmap.h>
> +#include <linux/types.h>
> +
> +static const struct mfd_cell max7360_cells[] = {
> + {
> + .name = "max7360-pinctrl",
> + },
All of these single line entries should be placed on a single line.
{ .name = "max7360-pinctrl" },
{ .name = "max7360-pwm" },
If ordering is not important. Please group them.
> + {
> + .name = "max7360-pwm",
> + },
> + {
> + .name = "max7360-gpo",
> + .of_compatible = "maxim,max7360-gpo",
> + },
> + {
> + .name = "max7360-gpio",
> + .of_compatible = "maxim,max7360-gpio",
> + },
> + {
> + .name = "max7360-keypad",
> + },
> + {
> + .name = "max7360-rotary",
> + },
> +};
> +
> +static const struct regmap_range max7360_volatile_ranges[] = {
> + {
> + .range_min = MAX7360_REG_KEYFIFO,
> + .range_max = MAX7360_REG_KEYFIFO,
> + }, {
> + .range_min = MAX7360_REG_I2C_TIMEOUT,
> + .range_max = MAX7360_REG_RTR_CNT,
> + },
> +};
Use regmap_reg_range()
> +static const struct regmap_access_table max7360_volatile_table = {
> + .yes_ranges = max7360_volatile_ranges,
> + .n_yes_ranges = ARRAY_SIZE(max7360_volatile_ranges),
> +};
> +
> +static const struct regmap_config max7360_regmap_config = {
> + .reg_bits = 8,
> + .val_bits = 8,
> + .max_register = MAX7360_REG_PWMCFG(MAX7360_PORT_PWM_COUNT - 1),
> + .volatile_table = &max7360_volatile_table,
> + .cache_type = REGCACHE_MAPLE,
> +};
> +
> +static int max7360_mask_irqs(struct regmap *regmap)
> +{
> + struct device *dev = regmap_get_device(regmap);
> + unsigned int val;
> + int ret;
> +
> + /*
> + * GPIO/PWM interrupts are not masked on reset: as the MAX7360 "INTI"
> + * interrupt line is shared between GPIOs and rotary encoder, this could
> + * result in repeated spurious interrupts on the rotary encoder driver
> + * if the GPIO driver is not loaded. Mask them now to avoid this
> + * situation.
> + */
> + for (unsigned int i = 0; i < MAX7360_PORT_PWM_COUNT; i++) {
> + ret = regmap_write_bits(regmap, MAX7360_REG_PWMCFG(i),
> + MAX7360_PORT_CFG_INTERRUPT_MASK,
> + MAX7360_PORT_CFG_INTERRUPT_MASK);
> + if (ret) {
> + dev_err(dev, "Failed to write max7360 port configuration");
MAX7360
> + return ret;
> + }
> + }
> +
> + /* Read GPIO in register, to ACK any pending IRQ. */
> + ret = regmap_read(regmap, MAX7360_REG_GPIOIN, &val);
> + if (ret)
> + dev_err(dev, "Failed to read gpio values: %d\n", ret);
GPIO
> +
> + return ret;
> +}
> +
> +static int max7360_reset(struct regmap *regmap)
> +{
> + struct device *dev = regmap_get_device(regmap);
> + int ret;
> +
> + ret = regmap_write(regmap, MAX7360_REG_GPIOCFG, MAX7360_GPIO_CFG_GPIO_RST);
> + if (ret) {
> + dev_err(dev, "Failed to reset GPIO configuration: %x\n", ret);
> + return ret;
> + }
> +
> + ret = regcache_drop_region(regmap, MAX7360_REG_GPIOCFG, MAX7360_REG_GPIO_LAST);
> + if (ret) {
> + dev_err(dev, "Failed to drop regmap cache: %x\n", ret);
> + return ret;
> + }
> +
> + ret = regmap_write(regmap, MAX7360_REG_SLEEP, 0);
> + if (ret) {
> + dev_err(dev, "Failed to reset autosleep configuration: %x\n", ret);
> + return ret;
> + }
> +
> + ret = regmap_write(regmap, MAX7360_REG_DEBOUNCE, 0);
> + if (ret)
> + dev_err(dev, "Failed to reset GPO port count: %x\n", ret);
> +
> + return ret;
> +}
> +
> +static int max7360_probe(struct i2c_client *client)
> +{
> + struct device *dev = &client->dev;
> + struct regmap *regmap;
> + int ret;
> +
> + regmap = devm_regmap_init_i2c(client, &max7360_regmap_config);
> + if (IS_ERR(regmap))
> + return dev_err_probe(dev, PTR_ERR(regmap), "Failed to initialise regmap\n");
dev_err_ptr_probe()
> +
> + ret = max7360_reset(regmap);
> + if (ret)
> + return dev_err_probe(dev, ret, "Failed to reset device\n");
> +
> + /* Get the device out of shutdown mode. */
> + ret = regmap_write_bits(regmap, MAX7360_REG_GPIOCFG,
> + MAX7360_GPIO_CFG_GPIO_EN,
> + MAX7360_GPIO_CFG_GPIO_EN);
> + if (ret)
> + return dev_err_probe(dev, ret, "Failed to enable GPIO and PWM module\n");
> +
> + ret = max7360_mask_irqs(regmap);
> + if (ret)
> + return dev_err_probe(dev, ret, "Could not mask interrupts\n");
> +
> + ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
> + max7360_cells, ARRAY_SIZE(max7360_cells),
> + NULL, 0, NULL);
> + if (ret)
> + return dev_err_probe(dev, ret, "Failed to register child devices\n");
> +
> + return 0;
> +}
> +
> +static const struct of_device_id max7360_dt_match[] = {
> + { .compatible = "maxim,max7360" },
> + {}
> +};
> +MODULE_DEVICE_TABLE(of, max7360_dt_match);
> +
> +static struct i2c_driver max7360_driver = {
> + .driver = {
> + .name = "max7360",
> + .of_match_table = max7360_dt_match,
> + },
> + .probe = max7360_probe,
> +};
> +module_i2c_driver(max7360_driver);
> +
> +MODULE_DESCRIPTION("Maxim MAX7360 I2C IO Expander core driver");
> +MODULE_AUTHOR("Kamel Bouhara <kamel.bouhara@bootlin.com>");
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/mfd/max7360.h b/include/linux/mfd/max7360.h
> new file mode 100644
> index 000000000000..b1d4cbee2385
> --- /dev/null
> +++ b/include/linux/mfd/max7360.h
> @@ -0,0 +1,109 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +
> +#ifndef __LINUX_MFD_MAX7360_H
> +#define __LINUX_MFD_MAX7360_H
> +
> +#include <linux/bits.h>
> +
> +#define MAX7360_MAX_KEY_ROWS 8
> +#define MAX7360_MAX_KEY_COLS 8
> +#define MAX7360_MAX_KEY_NUM (MAX7360_MAX_KEY_ROWS * MAX7360_MAX_KEY_COLS)
> +#define MAX7360_ROW_SHIFT 3
> +
> +#define MAX7360_MAX_GPIO 8
> +#define MAX7360_MAX_GPO 6
> +#define MAX7360_PORT_PWM_COUNT 8
> +#define MAX7360_PORT_RTR_PIN (MAX7360_PORT_PWM_COUNT - 1)
> +
> +/*
> + * MAX7360 registers
> + */
> +#define MAX7360_REG_KEYFIFO 0x00
> +#define MAX7360_REG_CONFIG 0x01
> +#define MAX7360_REG_DEBOUNCE 0x02
> +#define MAX7360_REG_INTERRUPT 0x03
> +#define MAX7360_REG_PORTS 0x04
> +#define MAX7360_REG_KEYREP 0x05
> +#define MAX7360_REG_SLEEP 0x06
> +
> +/*
> + * MAX7360 GPIO registers
> + *
> + * All these registers are reset together when writing bit 3 of
> + * MAX7360_REG_GPIOCFG.
> + */
> +#define MAX7360_REG_GPIOCFG 0x40
> +#define MAX7360_REG_GPIOCTRL 0x41
> +#define MAX7360_REG_GPIODEB 0x42
> +#define MAX7360_REG_GPIOCURR 0x43
> +#define MAX7360_REG_GPIOOUTM 0x44
> +#define MAX7360_REG_PWMCOM 0x45
> +#define MAX7360_REG_RTRCFG 0x46
> +#define MAX7360_REG_I2C_TIMEOUT 0x48
> +#define MAX7360_REG_GPIOIN 0x49
> +#define MAX7360_REG_RTR_CNT 0x4A
> +#define MAX7360_REG_PWMBASE 0x50
> +#define MAX7360_REG_PWMCFGBASE 0x58
> +
> +#define MAX7360_REG_GPIO_LAST 0x5F
> +
> +#define MAX7360_REG_PWM(x) (MAX7360_REG_PWMBASE + (x))
> +#define MAX7360_REG_PWMCFG(x) (MAX7360_REG_PWMCFGBASE + (x))
> +
> +/*
> + * Configuration register bits
> + */
> +#define MAX7360_FIFO_EMPTY 0x3f
> +#define MAX7360_FIFO_OVERFLOW 0x7f
> +#define MAX7360_FIFO_RELEASE BIT(6)
> +#define MAX7360_FIFO_COL GENMASK(5, 3)
> +#define MAX7360_FIFO_ROW GENMASK(2, 0)
> +
> +#define MAX7360_CFG_SLEEP BIT(7)
> +#define MAX7360_CFG_INTERRUPT BIT(5)
> +#define MAX7360_CFG_KEY_RELEASE BIT(3)
> +#define MAX7360_CFG_WAKEUP BIT(1)
> +#define MAX7360_CFG_TIMEOUT BIT(0)
> +
> +#define MAX7360_DEBOUNCE GENMASK(4, 0)
> +#define MAX7360_DEBOUNCE_MIN 9
> +#define MAX7360_DEBOUNCE_MAX 40
> +#define MAX7360_PORTS GENMASK(8, 5)
> +
> +#define MAX7360_INTERRUPT_TIME_MASK GENMASK(4, 0)
> +#define MAX7360_INTERRUPT_FIFO_MASK GENMASK(7, 5)
> +
> +#define MAX7360_PORT_CFG_INTERRUPT_MASK BIT(7)
> +#define MAX7360_PORT_CFG_INTERRUPT_EDGES BIT(6)
> +#define MAX7360_PORT_CFG_COMMON_PWM BIT(5)
> +
> +/*
> + * Autosleep register values
> + */
> +#define MAX7360_AUTOSLEEP_8192MS 0x01
> +#define MAX7360_AUTOSLEEP_4096MS 0x02
> +#define MAX7360_AUTOSLEEP_2048MS 0x03
> +#define MAX7360_AUTOSLEEP_1024MS 0x04
> +#define MAX7360_AUTOSLEEP_512MS 0x05
> +#define MAX7360_AUTOSLEEP_256MS 0x06
> +
> +#define MAX7360_GPIO_CFG_RTR_EN BIT(7)
> +#define MAX7360_GPIO_CFG_GPIO_EN BIT(4)
> +#define MAX7360_GPIO_CFG_GPIO_RST BIT(3)
> +
> +#define MAX7360_ROT_DEBOUNCE GENMASK(3, 0)
> +#define MAX7360_ROT_DEBOUNCE_MIN 0
> +#define MAX7360_ROT_DEBOUNCE_MAX 15
> +#define MAX7360_ROT_INTCNT GENMASK(6, 4)
> +#define MAX7360_ROT_INTCNT_DLY BIT(7)
> +
> +#define MAX7360_INT_INTI 0
> +#define MAX7360_INT_INTK 1
> +
> +#define MAX7360_INT_GPIO 0
> +#define MAX7360_INT_KEYPAD 1
> +#define MAX7360_INT_ROTARY 2
> +
> +#define MAX7360_NR_INTERNAL_IRQS 3
> +
> +#endif
>
> --
> 2.39.5
>
--
Lee Jones [李琼斯]
next prev parent reply other threads:[~2025-05-01 12:59 UTC|newest]
Thread overview: 36+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-04-28 11:57 [PATCH v7 00/11] Add support for MAX7360 Mathieu Dubois-Briand
2025-04-28 11:57 ` [PATCH v7 01/11] dt-bindings: mfd: gpio: Add MAX7360 Mathieu Dubois-Briand
2025-04-28 11:57 ` [PATCH v7 02/11] mfd: Add max7360 support mathieu.dubois-briand
2025-05-01 12:59 ` Lee Jones [this message]
2025-05-02 7:35 ` Mathieu Dubois-Briand
2025-05-02 8:26 ` Lee Jones
2025-05-02 9:13 ` Andy Shevchenko
2025-05-02 10:10 ` Andy Shevchenko
2025-04-28 11:57 ` [PATCH v7 03/11] pinctrl: Add MAX7360 pinctrl driver Mathieu Dubois-Briand
2025-05-02 10:15 ` Andy Shevchenko
2025-05-02 12:07 ` Mathieu Dubois-Briand
2025-04-28 11:57 ` [PATCH v7 04/11] pwm: max7360: Add MAX7360 PWM support mathieu.dubois-briand
2025-05-02 10:19 ` Andy Shevchenko
2025-05-02 12:13 ` Mathieu Dubois-Briand
2025-04-28 11:57 ` [PATCH v7 05/11] regmap: irq: Add support for chips without separate IRQ status Mathieu Dubois-Briand
2025-04-28 11:57 ` [PATCH v7 06/11] gpio: regmap: Allow to allocate regmap-irq device Mathieu Dubois-Briand
2025-05-02 10:20 ` Andy Shevchenko
2025-04-28 11:57 ` [PATCH v7 07/11] gpio: regmap: Allow to provide init_valid_mask callback Mathieu Dubois-Briand
2025-04-28 11:57 ` [PATCH v7 08/11] gpio: max7360: Add MAX7360 gpio support Mathieu Dubois-Briand
2025-05-02 10:39 ` Andy Shevchenko
2025-05-02 12:31 ` Mathieu Dubois-Briand
2025-05-02 13:03 ` Andy Shevchenko
2025-05-07 7:07 ` kernel test robot
2025-04-28 11:57 ` [PATCH v7 09/11] input: keyboard: Add support for MAX7360 keypad Mathieu Dubois-Briand
2025-05-02 10:46 ` Andy Shevchenko
2025-05-02 13:15 ` Mathieu Dubois-Briand
2025-05-02 13:32 ` Andy Shevchenko
2025-05-06 5:11 ` Dmitry Torokhov
2025-05-06 5:14 ` Dmitry Torokhov
2025-05-06 12:41 ` Mathieu Dubois-Briand
2025-04-28 11:57 ` [PATCH v7 10/11] input: misc: Add support for MAX7360 rotary Mathieu Dubois-Briand
2025-05-02 10:52 ` Andy Shevchenko
2025-05-02 13:58 ` Mathieu Dubois-Briand
2025-05-02 14:09 ` Andy Shevchenko
2025-05-05 11:52 ` Mathieu Dubois-Briand
2025-04-28 11:57 ` [PATCH v7 11/11] MAINTAINERS: Add entry on MAX7360 driver Mathieu Dubois-Briand
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250501125943.GN1567507@google.com \
--to=lee@kernel.org \
--cc=andriy.shevchenko@intel.com \
--cc=brgl@bgdev.pl \
--cc=broonie@kernel.org \
--cc=conor+dt@kernel.org \
--cc=dakr@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=dmitry.torokhov@gmail.com \
--cc=gregkh@linuxfoundation.org \
--cc=gregory.clement@bootlin.com \
--cc=kamel.bouhara@bootlin.com \
--cc=krzk+dt@kernel.org \
--cc=linus.walleij@linaro.org \
--cc=linux-gpio@vger.kernel.org \
--cc=linux-input@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pwm@vger.kernel.org \
--cc=mathieu.dubois-briand@bootlin.com \
--cc=mwalle@kernel.org \
--cc=rafael@kernel.org \
--cc=robh@kernel.org \
--cc=thomas.petazzoni@bootlin.com \
--cc=ukleinek@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.