All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/3] Add support for USB on ST-Ericsson Ux500
@ 2021-07-05 16:28 Stephan Gerhold
  2021-07-05 16:28 ` [PATCH 1/3] power: pmic: Add driver for ST-Ericsson AB8500 via PRCMU Stephan Gerhold
                   ` (2 more replies)
  0 siblings, 3 replies; 12+ messages in thread
From: Stephan Gerhold @ 2021-07-05 16:28 UTC (permalink / raw)
  To: u-boot
  Cc: Marek Vasut, Linus Walleij, Joe Hershberger, Jaehoon Chung,
	Stephan Gerhold

This patch series adds support for USB on ST-Ericsson Ux500 by:
  - Adding a driver to talk to the AB8500 PMIC
  - Adding a driver to enable the USB PHY
  - Adding a simple Ux500 glue driver for the musb-new driver

This was tested on the u8500 "stemmy" board that is already present
in U-Boot.


Stephan Gerhold (3):
  power: pmic: Add driver for ST-Ericsson AB8500 via PRCMU
  phy: Add driver for ST-Ericsson AB8500 USB PHY
  usb: musb-new: Add glue driver for ST-Ericsson Ux500

 drivers/phy/Kconfig              |   6 +
 drivers/phy/Makefile             |   1 +
 drivers/phy/phy-ab8500-usb.c     |  54 +++++++
 drivers/power/pmic/Kconfig       |  10 ++
 drivers/power/pmic/Makefile      |   1 +
 drivers/power/pmic/ab8500.c      | 258 +++++++++++++++++++++++++++++++
 drivers/usb/musb-new/Kconfig     |  11 +-
 drivers/usb/musb-new/Makefile    |   1 +
 drivers/usb/musb-new/musb_core.c |   2 +-
 drivers/usb/musb-new/ux500.c     | 179 +++++++++++++++++++++
 include/power/ab8500.h           | 125 +++++++++++++++
 11 files changed, 646 insertions(+), 2 deletions(-)
 create mode 100644 drivers/phy/phy-ab8500-usb.c
 create mode 100644 drivers/power/pmic/ab8500.c
 create mode 100644 drivers/usb/musb-new/ux500.c
 create mode 100644 include/power/ab8500.h

-- 
2.32.0


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH 1/3] power: pmic: Add driver for ST-Ericsson AB8500 via PRCMU
  2021-07-05 16:28 [PATCH 0/3] Add support for USB on ST-Ericsson Ux500 Stephan Gerhold
@ 2021-07-05 16:28 ` Stephan Gerhold
  2021-07-06  1:08   ` Jaehoon Chung
  2021-07-05 16:28 ` [PATCH 2/3] phy: Add driver for ST-Ericsson AB8500 USB PHY Stephan Gerhold
  2021-07-05 16:28 ` [PATCH 3/3] usb: musb-new: Add glue driver for ST-Ericsson Ux500 Stephan Gerhold
  2 siblings, 1 reply; 12+ messages in thread
From: Stephan Gerhold @ 2021-07-05 16:28 UTC (permalink / raw)
  To: u-boot
  Cc: Marek Vasut, Linus Walleij, Joe Hershberger, Jaehoon Chung,
	Stephan Gerhold

All devices based on ST-Ericsson Ux500 use a PMIC similar to AB8500
(Analog Baseband). There is AB8500, AB8505, AB9540 and AB8540
although in practice only AB8500 and AB8505 are relevant since the
platforms with AB9540 and AB8540 were cancelled and never used in
production.

In general, the AB8500 PMIC uses I2C as control interface, where the
different register banks are represented as separate I2C devices.
However, in practice AB8500 is always connected to a special I2C bus
on the DB8500 SoC that is controlled by the power/reset/clock
management unit (PRCMU) firmware.

Add a simple driver that allows reading/writing registers of the
AB8500 PMIC. The driver directly accesses registers from the PRCMU
parent device (represented by syscon in U-Boot). Abstracting it
further (e.g. with the i2c uclass) would not provide any advantage
because the PRCMU I2C bus is always just connected to AB8500 and
vice-versa.

The ab8500.h header is mostly taken as-is from Linux (with some
minor adjustments) to allow using similar code in both Linux and
U-Boot.

Cc: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Stephan Gerhold <stephan@gerhold.net>
---

 drivers/power/pmic/Kconfig  |  10 ++
 drivers/power/pmic/Makefile |   1 +
 drivers/power/pmic/ab8500.c | 258 ++++++++++++++++++++++++++++++++++++
 include/power/ab8500.h      | 125 +++++++++++++++++
 4 files changed, 394 insertions(+)
 create mode 100644 drivers/power/pmic/ab8500.c
 create mode 100644 include/power/ab8500.h

diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig
index 583fd3ddcd..fd6648b313 100644
--- a/drivers/power/pmic/Kconfig
+++ b/drivers/power/pmic/Kconfig
@@ -31,6 +31,16 @@ config SPL_PMIC_CHILDREN
 	to call your regulator code (e.g. see rk8xx.c for direct functions
 	for use in SPL).
 
+config PMIC_AB8500
+	bool "Enable driver for ST-Ericsson AB8500 PMIC via PRCMU"
+	depends on DM_PMIC
+	select REGMAP
+	select SYSCON
+	help
+	  Enable support for the ST-Ericsson AB8500 (Analog Baseband) PMIC.
+	  It connects with the ST-Ericsson DB8500 SoC via an I2C bus managed by
+	  the power/reset/clock management unit (PRCMU) firmware.
+
 config PMIC_ACT8846
 	bool "Enable support for the active-semi 8846 PMIC"
 	depends on DM_PMIC && DM_I2C
diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile
index 89099fde57..5d1a97e5f6 100644
--- a/drivers/power/pmic/Makefile
+++ b/drivers/power/pmic/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_$(SPL_)DM_PMIC_PFUZE100) += pfuze100.o
 obj-$(CONFIG_$(SPL_)DM_PMIC_PCA9450) += pca9450.o
 obj-$(CONFIG_PMIC_S2MPS11) += s2mps11.o
 obj-$(CONFIG_DM_PMIC_SANDBOX) += sandbox.o i2c_pmic_emul.o
+obj-$(CONFIG_PMIC_AB8500) += ab8500.o
 obj-$(CONFIG_PMIC_ACT8846) += act8846.o
 obj-$(CONFIG_PMIC_AS3722) += as3722.o as3722_gpio.o
 obj-$(CONFIG_PMIC_MAX8997) += max8997.o
diff --git a/drivers/power/pmic/ab8500.c b/drivers/power/pmic/ab8500.c
new file mode 100644
index 0000000000..a87a3b497c
--- /dev/null
+++ b/drivers/power/pmic/ab8500.c
@@ -0,0 +1,258 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Stephan Gerhold
+ *
+ * Adapted from old U-Boot and Linux kernel implementation:
+ * Copyright (C) STMicroelectronics 2009
+ * Copyright (C) ST-Ericsson SA 2010
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <power/ab8500.h>
+#include <power/pmic.h>
+
+/* CPU mailbox registers */
+#define PRCM_MBOX_CPU_VAL		0x0fc
+#define PRCM_MBOX_CPU_SET		0x100
+#define PRCM_MBOX_CPU_CLR		0x104
+
+#define PRCM_ARM_IT1_CLR		0x48C
+#define PRCM_ARM_IT1_VAL		0x494
+
+#define PRCM_TCDM_RANGE			2
+#define PRCM_REQ_MB5			0xE44
+#define PRCM_ACK_MB5			0xDF4
+#define _PRCM_MBOX_HEADER		0xFE8
+#define PRCM_MBOX_HEADER_REQ_MB5	(_PRCM_MBOX_HEADER + 0x5)
+#define PRCMU_I2C_MBOX_BIT		BIT(5)
+
+/* Mailbox 5 Requests */
+#define PRCM_REQ_MB5_I2C_SLAVE_OP	(PRCM_REQ_MB5 + 0x0)
+#define PRCM_REQ_MB5_I2C_HW_BITS	(PRCM_REQ_MB5 + 0x1)
+#define PRCM_REQ_MB5_I2C_REG		(PRCM_REQ_MB5 + 0x2)
+#define PRCM_REQ_MB5_I2C_VAL		(PRCM_REQ_MB5 + 0x3)
+#define PRCMU_I2C(bank)			(((bank) << 1) | BIT(6))
+#define PRCMU_I2C_WRITE			0
+#define PRCMU_I2C_READ			1
+#define PRCMU_I2C_STOP_EN		BIT(3)
+
+/* Mailbox 5 ACKs */
+#define PRCM_ACK_MB5_I2C_STATUS		(PRCM_ACK_MB5 + 0x1)
+#define PRCM_ACK_MB5_I2C_VAL		(PRCM_ACK_MB5 + 0x3)
+#define PRCMU_I2C_WR_OK			0x1
+#define PRCMU_I2C_RD_OK			0x2
+
+/* AB8500 version registers */
+#define AB8500_MISC_REV_REG		AB8500_MISC(0x80)
+#define AB8500_MISC_IC_NAME_REG		AB8500_MISC(0x82)
+
+struct ab8500_priv {
+	struct ab8500 ab8500;
+	struct regmap *regmap;
+};
+
+static inline int prcmu_tcdm_readb(struct regmap *map, uint offset, u8 *valp)
+{
+	return regmap_raw_read_range(map, PRCM_TCDM_RANGE, offset,
+				     valp, sizeof(*valp));
+}
+
+static inline int prcmu_tcdm_writeb(struct regmap *map, uint offset, u8 val)
+{
+	return regmap_raw_write_range(map, PRCM_TCDM_RANGE, offset,
+				      &val, sizeof(val));
+}
+
+static int prcmu_wait_i2c_mbx_ready(struct ab8500_priv *priv)
+{
+	uint val;
+	int ret;
+
+	ret = regmap_read(priv->regmap, PRCM_ARM_IT1_VAL, &val);
+	if (ret == 0 && val & PRCMU_I2C_MBOX_BIT) {
+		printf("ab8500: warning: PRCMU i2c mailbox was not acked\n");
+		/* clear mailbox 5 ack irq */
+		regmap_write(priv->regmap, PRCM_ARM_IT1_CLR, PRCMU_I2C_MBOX_BIT);
+	}
+
+	/* wait for on-going transaction, use 1s timeout */
+	return regmap_read_poll_timeout(priv->regmap, PRCM_MBOX_CPU_VAL, val,
+					!(val & PRCMU_I2C_MBOX_BIT), 0, 1000);
+}
+
+static int prcmu_wait_i2c_mbx_done(struct ab8500_priv *priv)
+{
+	uint val;
+	int ret;
+
+	/* set interrupt to XP70 */
+	ret = regmap_write(priv->regmap, PRCM_MBOX_CPU_SET, PRCMU_I2C_MBOX_BIT);
+	if (ret)
+		return ret;
+
+	/* wait for mailbox 5 (i2c) ack, use 1s timeout */
+	return regmap_read_poll_timeout(priv->regmap, PRCM_ARM_IT1_VAL, val,
+					(val & PRCMU_I2C_MBOX_BIT), 0, 1000);
+}
+
+static int ab8500_transfer(struct udevice *dev, uint bank_reg, u8 *val,
+			   u8 op, u8 expected_status)
+{
+	struct ab8500_priv *priv = dev_get_priv(dev);
+	u8 reg = bank_reg & 0xff;
+	u8 bank = bank_reg >> 8;
+	u8 status;
+	int ret;
+
+	ret = prcmu_wait_i2c_mbx_ready(priv);
+	if (ret)
+		return ret;
+
+	ret = prcmu_tcdm_writeb(priv->regmap, PRCM_MBOX_HEADER_REQ_MB5, 0);
+	if (ret)
+		return ret;
+	ret = prcmu_tcdm_writeb(priv->regmap, PRCM_REQ_MB5_I2C_SLAVE_OP,
+				PRCMU_I2C(bank) | op);
+	if (ret)
+		return ret;
+	ret = prcmu_tcdm_writeb(priv->regmap, PRCM_REQ_MB5_I2C_HW_BITS,
+				PRCMU_I2C_STOP_EN);
+	if (ret)
+		return ret;
+	ret = prcmu_tcdm_writeb(priv->regmap, PRCM_REQ_MB5_I2C_REG, reg);
+	if (ret)
+		return ret;
+	ret = prcmu_tcdm_writeb(priv->regmap, PRCM_REQ_MB5_I2C_VAL, *val);
+	if (ret)
+		return ret;
+
+	ret = prcmu_wait_i2c_mbx_done(priv);
+	if (ret) {
+		printf("%s: mailbox request timed out\n", __func__);
+		return ret;
+	}
+
+	/* read transfer result */
+	ret = prcmu_tcdm_readb(priv->regmap, PRCM_ACK_MB5_I2C_STATUS, &status);
+	if (ret)
+		return ret;
+	ret = prcmu_tcdm_readb(priv->regmap, PRCM_ACK_MB5_I2C_VAL, val);
+	if (ret)
+		return ret;
+
+	/* clear mailbox 5 ack irq */
+	regmap_write(priv->regmap, PRCM_ARM_IT1_CLR, PRCMU_I2C_MBOX_BIT);
+
+	if (status != expected_status) {
+		/*
+		 * AB8500 does not have the AB8500_MISC_IC_NAME_REG register,
+		 * but we need to try reading it to detect AB8505.
+		 * In case of an error, assume that we have AB8500.
+		 */
+		if (op == PRCMU_I2C_READ && bank_reg == AB8500_MISC_IC_NAME_REG) {
+			*val = AB8500_VERSION_AB8500;
+			return 0;
+		}
+
+		printf("%s: return status %d\n", __func__, status);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int ab8500_reg_count(struct udevice *dev)
+{
+	return AB8500_NUM_REGISTERS;
+}
+
+static int ab8500_read(struct udevice *dev, uint reg, uint8_t *buf, int len)
+{
+	int ret;
+
+	if (len != 1)
+		return -EINVAL;
+
+	*buf = 0;
+	ret = ab8500_transfer(dev, reg, buf, PRCMU_I2C_READ, PRCMU_I2C_RD_OK);
+	if (ret) {
+		printf("%s failed: %d\n", __func__, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int ab8500_write(struct udevice *dev, uint reg, const uint8_t *buf, int len)
+{
+	int ret;
+	u8 val;
+
+	if (len != 1)
+		return -EINVAL;
+
+	val = *buf;
+	ret = ab8500_transfer(dev, reg, &val, PRCMU_I2C_WRITE, PRCMU_I2C_WR_OK);
+	if (ret) {
+		printf("%s failed: %d\n", __func__, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static struct dm_pmic_ops ab8500_ops = {
+	.reg_count = ab8500_reg_count,
+	.read = ab8500_read,
+	.write = ab8500_write,
+};
+
+static int ab8500_probe(struct udevice *dev)
+{
+	struct ab8500_priv *priv = dev_get_priv(dev);
+	int ret;
+
+	/* get regmap from the PRCMU parent device (syscon in U-Boot) */
+	priv->regmap = syscon_get_regmap(dev->parent);
+	if (IS_ERR(priv->regmap))
+		return PTR_ERR(priv->regmap);
+
+	ret = pmic_reg_read(dev, AB8500_MISC_IC_NAME_REG);
+	if (ret < 0) {
+		printf("ab8500: failed to read chip version: %d\n", ret);
+		return ret;
+	}
+	priv->ab8500.version = ret;
+
+	ret = pmic_reg_read(dev, AB8500_MISC_REV_REG);
+	if (ret < 0) {
+		printf("ab8500: failed to read chip id: %d\n", ret);
+		return ret;
+	}
+	priv->ab8500.chip_id = ret;
+
+	debug("ab8500: version: %#x, chip id: %#x\n",
+	      priv->ab8500.version, priv->ab8500.chip_id);
+
+	return 0;
+}
+
+static const struct udevice_id ab8500_ids[] = {
+	{ .compatible = "stericsson,ab8500" },
+	{ }
+};
+
+U_BOOT_DRIVER(pmic_ab8500) = {
+	.name		= "pmic_ab8500",
+	.id		= UCLASS_PMIC,
+	.of_match	= ab8500_ids,
+	.bind		= dm_scan_fdt_dev,
+	.probe		= ab8500_probe,
+	.ops		= &ab8500_ops,
+	.priv_auto	= sizeof(struct ab8500_priv),
+};
diff --git a/include/power/ab8500.h b/include/power/ab8500.h
new file mode 100644
index 0000000000..157eb4a5b1
--- /dev/null
+++ b/include/power/ab8500.h
@@ -0,0 +1,125 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Based on include/linux/mfd/abx500/ab8500.h from Linux
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
+ */
+
+#ifndef _PMIC_AB8500_H_
+#define _PMIC_AB8500_H_
+
+/*
+ * AB IC versions
+ *
+ * AB8500_VERSION_AB8500 should be 0xFF but will never be read as need a
+ * non-supported multi-byte I2C access via PRCMU. Set to 0x00 to ease the
+ * print of version string.
+ */
+enum ab8500_version {
+	AB8500_VERSION_AB8500 = 0x0,
+	AB8500_VERSION_AB8505 = 0x1,
+	AB8500_VERSION_AB9540 = 0x2,
+	AB8500_VERSION_AB8540 = 0x4,
+	AB8500_VERSION_UNDEFINED,
+};
+
+/* AB8500 CIDs*/
+#define AB8500_CUTEARLY	0x00
+#define AB8500_CUT1P0	0x10
+#define AB8500_CUT1P1	0x11
+#define AB8500_CUT1P2	0x12 /* Only valid for AB8540 */
+#define AB8500_CUT2P0	0x20
+#define AB8500_CUT3P0	0x30
+#define AB8500_CUT3P3	0x33
+
+/*
+ * AB8500 bank addresses
+ */
+#define AB8500_BANK(bank, reg)		(((bank) << 8) | (reg))
+#define AB8500_M_FSM_RANK(reg)		AB8500_BANK(0x0, reg)
+#define AB8500_SYS_CTRL1_BLOCK(reg)	AB8500_BANK(0x1, reg)
+#define AB8500_SYS_CTRL2_BLOCK(reg)	AB8500_BANK(0x2, reg)
+#define AB8500_REGU_CTRL1(reg)		AB8500_BANK(0x3, reg)
+#define AB8500_REGU_CTRL2(reg)		AB8500_BANK(0x4, reg)
+#define AB8500_USB(reg)			AB8500_BANK(0x5, reg)
+#define AB8500_TVOUT(reg)		AB8500_BANK(0x6, reg)
+#define AB8500_DBI(reg)			AB8500_BANK(0x7, reg)
+#define AB8500_ECI_AV_ACC(reg)		AB8500_BANK(0x8, reg)
+#define AB8500_RESERVED(reg)		AB8500_BANK(0x9, reg)
+#define AB8500_GPADC(reg)		AB8500_BANK(0xA, reg)
+#define AB8500_CHARGER(reg)		AB8500_BANK(0xB, reg)
+#define AB8500_GAS_GAUGE(reg)		AB8500_BANK(0xC, reg)
+#define AB8500_AUDIO(reg)		AB8500_BANK(0xD, reg)
+#define AB8500_INTERRUPT(reg)		AB8500_BANK(0xE, reg)
+#define AB8500_RTC(reg)			AB8500_BANK(0xF, reg)
+#define AB8500_GPIO(reg)		AB8500_BANK(0x10, reg)
+#define AB8500_MISC(reg)		AB8500_BANK(0x10, reg)
+#define AB8500_DEVELOPMENT(reg)		AB8500_BANK(0x11, reg)
+#define AB8500_DEBUG(reg)		AB8500_BANK(0x12, reg)
+#define AB8500_PROD_TEST(reg)		AB8500_BANK(0x13, reg)
+#define AB8500_STE_TEST(reg)		AB8500_BANK(0x14, reg)
+#define AB8500_OTP_EMUL(reg)		AB8500_BANK(0x15, reg)
+
+#define AB8500_NUM_BANKS		0x16
+#define AB8500_NUM_REGISTERS		AB8500_BANK(AB8500_NUM_BANKS, 0)
+
+struct ab8500 {
+	enum ab8500_version version;
+	u8 chip_id;
+};
+
+static inline int is_ab8500(struct ab8500 *ab)
+{
+	return ab->version == AB8500_VERSION_AB8500;
+}
+
+static inline int is_ab8505(struct ab8500 *ab)
+{
+	return ab->version == AB8500_VERSION_AB8505;
+}
+
+/* exclude also ab8505, ab9540... */
+static inline int is_ab8500_1p0_or_earlier(struct ab8500 *ab)
+{
+	return (is_ab8500(ab) && (ab->chip_id <= AB8500_CUT1P0));
+}
+
+/* exclude also ab8505, ab9540... */
+static inline int is_ab8500_1p1_or_earlier(struct ab8500 *ab)
+{
+	return (is_ab8500(ab) && (ab->chip_id <= AB8500_CUT1P1));
+}
+
+/* exclude also ab8505, ab9540... */
+static inline int is_ab8500_2p0_or_earlier(struct ab8500 *ab)
+{
+	return (is_ab8500(ab) && (ab->chip_id <= AB8500_CUT2P0));
+}
+
+static inline int is_ab8500_3p3_or_earlier(struct ab8500 *ab)
+{
+	return (is_ab8500(ab) && (ab->chip_id <= AB8500_CUT3P3));
+}
+
+/* exclude also ab8505, ab9540... */
+static inline int is_ab8500_2p0(struct ab8500 *ab)
+{
+	return (is_ab8500(ab) && (ab->chip_id == AB8500_CUT2P0));
+}
+
+static inline int is_ab8505_1p0_or_earlier(struct ab8500 *ab)
+{
+	return (is_ab8505(ab) && (ab->chip_id <= AB8500_CUT1P0));
+}
+
+static inline int is_ab8505_2p0(struct ab8500 *ab)
+{
+	return (is_ab8505(ab) && (ab->chip_id == AB8500_CUT2P0));
+}
+
+static inline int is_ab8505_2p0_earlier(struct ab8500 *ab)
+{
+	return (is_ab8505(ab) && (ab->chip_id < AB8500_CUT2P0));
+}
+
+#endif
-- 
2.32.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 2/3] phy: Add driver for ST-Ericsson AB8500 USB PHY
  2021-07-05 16:28 [PATCH 0/3] Add support for USB on ST-Ericsson Ux500 Stephan Gerhold
  2021-07-05 16:28 ` [PATCH 1/3] power: pmic: Add driver for ST-Ericsson AB8500 via PRCMU Stephan Gerhold
@ 2021-07-05 16:28 ` Stephan Gerhold
  2021-07-06  1:10   ` Jaehoon Chung
  2021-07-07 23:46   ` Linus Walleij
  2021-07-05 16:28 ` [PATCH 3/3] usb: musb-new: Add glue driver for ST-Ericsson Ux500 Stephan Gerhold
  2 siblings, 2 replies; 12+ messages in thread
From: Stephan Gerhold @ 2021-07-05 16:28 UTC (permalink / raw)
  To: u-boot
  Cc: Marek Vasut, Linus Walleij, Joe Hershberger, Jaehoon Chung,
	Stephan Gerhold

The AB8500 PMIC contains an USB PHY that needs to be set up in
device or host mode to make USB work properly. Add a simple driver
for the generic PHY uclass that allows enabling it.

The if (CONFIG_IS_ENABLED(USB_MUSB_HOST)) might be a bit strange.
The USB PHY must be configured in either host or device mode and
somehow the USB PHY driver must be made aware of the mode.

Actually, the MUSB driver used together with this PHY does not
support dynamic selection of host/device mode in U-Boot at the moment.
Therefore, one very simple approach that works fine is to select
the mode to configure at compile time. When the MUSB driver is
configured in host mode the PHY is configured in host mode, and
similarly when the MUSB driver is configured in device/gadget mode.

Cc: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Stephan Gerhold <stephan@gerhold.net>
---

Better suggestions to make the USB PHY driver aware of the mode
are very welcome. :) I'm not sure it's worth it though, the compile
time selection is not ideal but it does the job just fine for now.
---
 drivers/phy/Kconfig          |  6 ++++
 drivers/phy/Makefile         |  1 +
 drivers/phy/phy-ab8500-usb.c | 54 ++++++++++++++++++++++++++++++++++++
 3 files changed, 61 insertions(+)
 create mode 100644 drivers/phy/phy-ab8500-usb.c

diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 008186a10d..92c74b9d0b 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -64,6 +64,12 @@ config MIPI_DPHY_HELPERS
 	help
 	  Provides a number of helpers a core functions for MIPI D-PHY drivers.
 
+config AB8500_USB_PHY
+	bool "AB8500 USB PHY Driver"
+	depends on PHY && PMIC_AB8500
+	help
+	  Support for the USB OTG PHY in ST-Ericsson AB8500.
+
 config BCM6318_USBH_PHY
 	bool "BCM6318 USBH PHY support"
 	depends on PHY && ARCH_BMIPS
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index 3c4a673a83..bf03d05d9b 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -6,6 +6,7 @@
 obj-$(CONFIG_$(SPL_)PHY) += phy-uclass.o
 obj-$(CONFIG_$(SPL_)NOP_PHY) += nop-phy.o
 obj-$(CONFIG_MIPI_DPHY_HELPERS) += phy-core-mipi-dphy.o
+obj-$(CONFIG_AB8500_USB_PHY) += phy-ab8500-usb.o
 obj-$(CONFIG_BCM6318_USBH_PHY) += bcm6318-usbh-phy.o
 obj-$(CONFIG_BCM6348_USBH_PHY) += bcm6348-usbh-phy.o
 obj-$(CONFIG_BCM6358_USBH_PHY) += bcm6358-usbh-phy.o
diff --git a/drivers/phy/phy-ab8500-usb.c b/drivers/phy/phy-ab8500-usb.c
new file mode 100644
index 0000000000..4ecb03a9cb
--- /dev/null
+++ b/drivers/phy/phy-ab8500-usb.c
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Copyright (C) 2019 Stephan Gerhold */
+
+#include <common.h>
+#include <dm.h>
+#include <generic-phy.h>
+#include <linux/bitops.h>
+#include <power/pmic.h>
+#include <power/ab8500.h>
+
+#define AB8500_USB_PHY_CTRL_REG			AB8500_USB(0x8A)
+#define AB8500_BIT_PHY_CTRL_HOST_EN		BIT(0)
+#define AB8500_BIT_PHY_CTRL_DEVICE_EN		BIT(1)
+#define AB8500_USB_PHY_CTRL_MASK		(AB8500_BIT_PHY_CTRL_HOST_EN |\
+						 AB8500_BIT_PHY_CTRL_DEVICE_EN)
+
+static int ab8500_usb_phy_power_on(struct phy *phy)
+{
+	struct udevice *dev = phy->dev;
+	uint set;
+
+	if (CONFIG_IS_ENABLED(USB_MUSB_HOST))
+		set = AB8500_BIT_PHY_CTRL_HOST_EN;
+	else
+		set = AB8500_BIT_PHY_CTRL_DEVICE_EN;
+
+	return pmic_clrsetbits(dev->parent, AB8500_USB_PHY_CTRL_REG,
+			       AB8500_USB_PHY_CTRL_MASK, set);
+}
+
+static int ab8500_usb_phy_power_off(struct phy *phy)
+{
+	struct udevice *dev = phy->dev;
+
+	return pmic_clrsetbits(dev->parent, AB8500_USB_PHY_CTRL_REG,
+			       AB8500_USB_PHY_CTRL_MASK, 0);
+}
+
+struct phy_ops ab8500_usb_phy_ops = {
+	.power_on = ab8500_usb_phy_power_on,
+	.power_off = ab8500_usb_phy_power_off,
+};
+
+static const struct udevice_id ab8500_usb_phy_ids[] = {
+	{ .compatible = "stericsson,ab8500-usb" },
+	{ }
+};
+
+U_BOOT_DRIVER(ab8500_usb_phy) = {
+	.name = "ab8500_usb_phy",
+	.id = UCLASS_PHY,
+	.of_match = ab8500_usb_phy_ids,
+	.ops = &ab8500_usb_phy_ops,
+};
-- 
2.32.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 3/3] usb: musb-new: Add glue driver for ST-Ericsson Ux500
  2021-07-05 16:28 [PATCH 0/3] Add support for USB on ST-Ericsson Ux500 Stephan Gerhold
  2021-07-05 16:28 ` [PATCH 1/3] power: pmic: Add driver for ST-Ericsson AB8500 via PRCMU Stephan Gerhold
  2021-07-05 16:28 ` [PATCH 2/3] phy: Add driver for ST-Ericsson AB8500 USB PHY Stephan Gerhold
@ 2021-07-05 16:28 ` Stephan Gerhold
  2021-07-07 23:47   ` Linus Walleij
  2 siblings, 1 reply; 12+ messages in thread
From: Stephan Gerhold @ 2021-07-05 16:28 UTC (permalink / raw)
  To: u-boot
  Cc: Marek Vasut, Linus Walleij, Joe Hershberger, Jaehoon Chung,
	Stephan Gerhold

The ST-Ericsson DB8500 SoC contains a MUSB OTG controller which
supports both host and gadget mode. For some reason there is
nothing special about it - add a simple glue driver for Ux500
that literally just sets up MUSB together with a generic PHY.
There are no SoC-specific registers etc needed to make USB work.

The new Ux500 glue driver is only tested to work with DM_USB
and DM_USB_GADGET. Both host and gadget mode work fine on
the u8500 "stemmy" board that is already present in U-Boot.

Cc: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Stephan Gerhold <stephan@gerhold.net>
---

This patch could be applied separately from the first two if
needed. There is a functional runtime dependency but not
a compile time dependency with the PMIC changes in the first
two patches.

---
 drivers/usb/musb-new/Kconfig     |  11 +-
 drivers/usb/musb-new/Makefile    |   1 +
 drivers/usb/musb-new/musb_core.c |   2 +-
 drivers/usb/musb-new/ux500.c     | 179 +++++++++++++++++++++++++++++++
 4 files changed, 191 insertions(+), 2 deletions(-)
 create mode 100644 drivers/usb/musb-new/ux500.c

diff --git a/drivers/usb/musb-new/Kconfig b/drivers/usb/musb-new/Kconfig
index fd6f4109b0..81ceea9740 100644
--- a/drivers/usb/musb-new/Kconfig
+++ b/drivers/usb/musb-new/Kconfig
@@ -72,6 +72,15 @@ config USB_MUSB_SUNXI
 	Say y here to enable support for the sunxi OTG / DRC USB controller
 	used on almost all sunxi boards.
 
+config USB_MUSB_UX500
+	bool "Enable ST-Ericsson Ux500 USB controller"
+	depends on DM_USB && DM_USB_GADGET && ARCH_U8500
+	default y
+	help
+	  Say y to enable support for the MUSB OTG USB controller used in
+	  ST-Ericsson Ux500. The driver supports either gadget or host mode
+	  based on the selection of CONFIG_USB_MUSB_HOST.
+
 config USB_MUSB_DISABLE_BULK_COMBINE_SPLIT
 	bool "Disable MUSB bulk split/combine"
 	default y
@@ -85,7 +94,7 @@ endif
 
 config USB_MUSB_PIO_ONLY
 	bool "Disable DMA (always use PIO)"
-	default y if USB_MUSB_AM35X || USB_MUSB_PIC32 || USB_MUSB_OMAP2PLUS || USB_MUSB_DSPS || USB_MUSB_SUNXI || USB_MUSB_MT85XX
+	default y if USB_MUSB_AM35X || USB_MUSB_PIC32 || USB_MUSB_OMAP2PLUS || USB_MUSB_DSPS || USB_MUSB_SUNXI || USB_MUSB_MT85XX || USB_MUSB_UX500
 	help
 	  All data is copied between memory and FIFO by the CPU.
 	  DMA controllers are ignored.
diff --git a/drivers/usb/musb-new/Makefile b/drivers/usb/musb-new/Makefile
index 6355eb12dd..396ff02654 100644
--- a/drivers/usb/musb-new/Makefile
+++ b/drivers/usb/musb-new/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_USB_MUSB_OMAP2PLUS) += omap2430.o
 obj-$(CONFIG_USB_MUSB_PIC32) += pic32.o
 obj-$(CONFIG_USB_MUSB_SUNXI) += sunxi.o
 obj-$(CONFIG_USB_MUSB_TI) += ti-musb.o
+obj-$(CONFIG_USB_MUSB_UX500) += ux500.o
 
 ccflags-y := $(call cc-option,-Wno-unused-variable) \
 		$(call cc-option,-Wno-unused-but-set-variable) \
diff --git a/drivers/usb/musb-new/musb_core.c b/drivers/usb/musb-new/musb_core.c
index 22811a5efb..18d9bc805f 100644
--- a/drivers/usb/musb-new/musb_core.c
+++ b/drivers/usb/musb-new/musb_core.c
@@ -1526,7 +1526,7 @@ static int __devinit musb_core_init(u16 musb_type, struct musb *musb)
 /*-------------------------------------------------------------------------*/
 
 #if defined(CONFIG_SOC_OMAP2430) || defined(CONFIG_SOC_OMAP3430) || \
-	defined(CONFIG_ARCH_OMAP4)
+	defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_ARCH_U8500)
 
 static irqreturn_t generic_interrupt(int irq, void *__hci)
 {
diff --git a/drivers/usb/musb-new/ux500.c b/drivers/usb/musb-new/ux500.c
new file mode 100644
index 0000000000..57c7d5630d
--- /dev/null
+++ b/drivers/usb/musb-new/ux500.c
@@ -0,0 +1,179 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Copyright (C) 2019 Stephan Gerhold */
+
+#include <common.h>
+#include <dm.h>
+#include <generic-phy.h>
+#include <dm/device_compat.h>
+#include "musb_uboot.h"
+
+static struct musb_hdrc_config ux500_musb_hdrc_config = {
+	.multipoint	= true,
+	.dyn_fifo	= true,
+	.num_eps	= 16,
+	.ram_bits	= 16,
+};
+
+struct ux500_glue {
+	struct musb_host_data mdata;
+	struct device dev;
+	struct phy phy;
+	bool enabled;
+};
+#define to_ux500_glue(d)	container_of(d, struct ux500_glue, dev)
+
+static int ux500_musb_enable(struct musb *musb)
+{
+	struct ux500_glue *glue = to_ux500_glue(musb->controller);
+	int ret;
+
+	if (glue->enabled)
+		return 0;
+
+	ret = generic_phy_power_on(&glue->phy);
+	if (ret) {
+		printf("%s: failed to power on USB PHY\n", __func__);
+		return ret;
+	}
+
+	glue->enabled = true;
+	return 0;
+}
+
+static void ux500_musb_disable(struct musb *musb)
+{
+	struct ux500_glue *glue = to_ux500_glue(musb->controller);
+	int ret;
+
+	if (!glue->enabled)
+		return;
+
+	ret = generic_phy_power_off(&glue->phy);
+	if (ret) {
+		printf("%s: failed to power off USB PHY\n", __func__);
+		return;
+	}
+
+	glue->enabled = false;
+}
+
+static int ux500_musb_init(struct musb *musb)
+{
+	struct ux500_glue *glue = to_ux500_glue(musb->controller);
+	int ret;
+
+	ret = generic_phy_init(&glue->phy);
+	if (ret) {
+		printf("%s: failed to init USB PHY\n", __func__);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int ux500_musb_exit(struct musb *musb)
+{
+	struct ux500_glue *glue = to_ux500_glue(musb->controller);
+	int ret;
+
+	ret = generic_phy_exit(&glue->phy);
+	if (ret) {
+		printf("%s: failed to exit USB PHY\n", __func__);
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct musb_platform_ops ux500_musb_ops = {
+	.init		= ux500_musb_init,
+	.exit		= ux500_musb_exit,
+	.enable		= ux500_musb_enable,
+	.disable	= ux500_musb_disable,
+};
+
+int dm_usb_gadget_handle_interrupts(struct udevice *dev)
+{
+	struct ux500_glue *glue = dev_get_priv(dev);
+
+	glue->mdata.host->isr(0, glue->mdata.host);
+	return 0;
+}
+
+static int ux500_musb_probe(struct udevice *dev)
+{
+#ifdef CONFIG_USB_MUSB_HOST
+	struct usb_bus_priv *priv = dev_get_uclass_priv(dev);
+#endif
+	struct ux500_glue *glue = dev_get_priv(dev);
+	struct musb_host_data *host = &glue->mdata;
+	struct musb_hdrc_platform_data pdata;
+	void *base = dev_read_addr_ptr(dev);
+	int ret;
+
+	if (!base)
+		return -EINVAL;
+
+	ret = generic_phy_get_by_name(dev, "usb", &glue->phy);
+	if (ret) {
+		dev_err(dev, "failed to get USB PHY: %d\n", ret);
+		return ret;
+	}
+
+	memset(&pdata, 0, sizeof(pdata));
+	pdata.platform_ops = &ux500_musb_ops;
+	pdata.config = &ux500_musb_hdrc_config;
+
+#ifdef CONFIG_USB_MUSB_HOST
+	priv->desc_before_addr = true;
+	pdata.mode = MUSB_HOST;
+
+	host->host = musb_init_controller(&pdata, &glue->dev, base);
+	if (!host->host)
+		return -EIO;
+
+	return musb_lowlevel_init(host);
+#else
+	pdata.mode = MUSB_PERIPHERAL;
+	host->host = musb_init_controller(&pdata, &glue->dev, base);
+	if (!host->host)
+		return -EIO;
+
+	return usb_add_gadget_udc(&glue->dev, &host->host->g);
+#endif
+}
+
+static int ux500_musb_remove(struct udevice *dev)
+{
+	struct ux500_glue *glue = dev_get_priv(dev);
+	struct musb_host_data *host = &glue->mdata;
+
+	usb_del_gadget_udc(&host->host->g);
+	musb_stop(host->host);
+	free(host->host);
+	host->host = NULL;
+
+	return 0;
+}
+
+static const struct udevice_id ux500_musb_ids[] = {
+	{ .compatible = "stericsson,db8500-musb" },
+	{ }
+};
+
+U_BOOT_DRIVER(ux500_musb) = {
+	.name		= "ux500-musb",
+#ifdef CONFIG_USB_MUSB_HOST
+	.id		= UCLASS_USB,
+#else
+	.id		= UCLASS_USB_GADGET_GENERIC,
+#endif
+	.of_match	= ux500_musb_ids,
+	.probe		= ux500_musb_probe,
+	.remove		= ux500_musb_remove,
+#ifdef CONFIG_USB_MUSB_HOST
+	.ops		= &musb_usb_ops,
+#endif
+	.plat_auto	= sizeof(struct usb_plat),
+	.priv_auto	= sizeof(struct ux500_glue),
+};
-- 
2.32.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH 1/3] power: pmic: Add driver for ST-Ericsson AB8500 via PRCMU
  2021-07-05 16:28 ` [PATCH 1/3] power: pmic: Add driver for ST-Ericsson AB8500 via PRCMU Stephan Gerhold
@ 2021-07-06  1:08   ` Jaehoon Chung
  2021-07-06  8:52     ` Stephan Gerhold
  0 siblings, 1 reply; 12+ messages in thread
From: Jaehoon Chung @ 2021-07-06  1:08 UTC (permalink / raw)
  To: Stephan Gerhold, u-boot; +Cc: Marek Vasut, Linus Walleij, Joe Hershberger

On 7/6/21 1:28 AM, Stephan Gerhold wrote:
> All devices based on ST-Ericsson Ux500 use a PMIC similar to AB8500
> (Analog Baseband). There is AB8500, AB8505, AB9540 and AB8540
> although in practice only AB8500 and AB8505 are relevant since the
> platforms with AB9540 and AB8540 were cancelled and never used in
> production.
> 
> In general, the AB8500 PMIC uses I2C as control interface, where the
> different register banks are represented as separate I2C devices.
> However, in practice AB8500 is always connected to a special I2C bus
> on the DB8500 SoC that is controlled by the power/reset/clock
> management unit (PRCMU) firmware.
> 
> Add a simple driver that allows reading/writing registers of the
> AB8500 PMIC. The driver directly accesses registers from the PRCMU
> parent device (represented by syscon in U-Boot). Abstracting it
> further (e.g. with the i2c uclass) would not provide any advantage
> because the PRCMU I2C bus is always just connected to AB8500 and
> vice-versa.
> 
> The ab8500.h header is mostly taken as-is from Linux (with some
> minor adjustments) to allow using similar code in both Linux and
> U-Boot.
> 
> Cc: Linus Walleij <linus.walleij@linaro.org>
> Signed-off-by: Stephan Gerhold <stephan@gerhold.net>
> ---
> 
>  drivers/power/pmic/Kconfig  |  10 ++
>  drivers/power/pmic/Makefile |   1 +
>  drivers/power/pmic/ab8500.c | 258 ++++++++++++++++++++++++++++++++++++
>  include/power/ab8500.h      | 125 +++++++++++++++++
>  4 files changed, 394 insertions(+)
>  create mode 100644 drivers/power/pmic/ab8500.c
>  create mode 100644 include/power/ab8500.h
> 
> diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig
> index 583fd3ddcd..fd6648b313 100644
> --- a/drivers/power/pmic/Kconfig
> +++ b/drivers/power/pmic/Kconfig
> @@ -31,6 +31,16 @@ config SPL_PMIC_CHILDREN
>  	to call your regulator code (e.g. see rk8xx.c for direct functions
>  	for use in SPL).
>  
> +config PMIC_AB8500
> +	bool "Enable driver for ST-Ericsson AB8500 PMIC via PRCMU"
> +	depends on DM_PMIC
> +	select REGMAP
> +	select SYSCON
> +	help
> +	  Enable support for the ST-Ericsson AB8500 (Analog Baseband) PMIC.
> +	  It connects with the ST-Ericsson DB8500 SoC via an I2C bus managed by
> +	  the power/reset/clock management unit (PRCMU) firmware.
> +
>  config PMIC_ACT8846
>  	bool "Enable support for the active-semi 8846 PMIC"
>  	depends on DM_PMIC && DM_I2C
> diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile
> index 89099fde57..5d1a97e5f6 100644
> --- a/drivers/power/pmic/Makefile
> +++ b/drivers/power/pmic/Makefile
> @@ -15,6 +15,7 @@ obj-$(CONFIG_$(SPL_)DM_PMIC_PFUZE100) += pfuze100.o
>  obj-$(CONFIG_$(SPL_)DM_PMIC_PCA9450) += pca9450.o
>  obj-$(CONFIG_PMIC_S2MPS11) += s2mps11.o
>  obj-$(CONFIG_DM_PMIC_SANDBOX) += sandbox.o i2c_pmic_emul.o
> +obj-$(CONFIG_PMIC_AB8500) += ab8500.o
>  obj-$(CONFIG_PMIC_ACT8846) += act8846.o
>  obj-$(CONFIG_PMIC_AS3722) += as3722.o as3722_gpio.o
>  obj-$(CONFIG_PMIC_MAX8997) += max8997.o
> diff --git a/drivers/power/pmic/ab8500.c b/drivers/power/pmic/ab8500.c
> new file mode 100644
> index 0000000000..a87a3b497c
> --- /dev/null
> +++ b/drivers/power/pmic/ab8500.c
> @@ -0,0 +1,258 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (C) 2019 Stephan Gerhold
> + *
> + * Adapted from old U-Boot and Linux kernel implementation:
> + * Copyright (C) STMicroelectronics 2009
> + * Copyright (C) ST-Ericsson SA 2010
> + */
> +
> +#include <common.h>
> +#include <dm.h>
> +#include <regmap.h>
> +#include <syscon.h>
> +#include <linux/bitops.h>
> +#include <linux/err.h>
> +#include <power/ab8500.h>
> +#include <power/pmic.h>
> +
> +/* CPU mailbox registers */
> +#define PRCM_MBOX_CPU_VAL		0x0fc
> +#define PRCM_MBOX_CPU_SET		0x100
> +#define PRCM_MBOX_CPU_CLR		0x104
> +
> +#define PRCM_ARM_IT1_CLR		0x48C
> +#define PRCM_ARM_IT1_VAL		0x494
> +
> +#define PRCM_TCDM_RANGE			2
> +#define PRCM_REQ_MB5			0xE44
> +#define PRCM_ACK_MB5			0xDF4
> +#define _PRCM_MBOX_HEADER		0xFE8
> +#define PRCM_MBOX_HEADER_REQ_MB5	(_PRCM_MBOX_HEADER + 0x5)
> +#define PRCMU_I2C_MBOX_BIT		BIT(5)
> +
> +/* Mailbox 5 Requests */
> +#define PRCM_REQ_MB5_I2C_SLAVE_OP	(PRCM_REQ_MB5 + 0x0)
> +#define PRCM_REQ_MB5_I2C_HW_BITS	(PRCM_REQ_MB5 + 0x1)
> +#define PRCM_REQ_MB5_I2C_REG		(PRCM_REQ_MB5 + 0x2)
> +#define PRCM_REQ_MB5_I2C_VAL		(PRCM_REQ_MB5 + 0x3)
> +#define PRCMU_I2C(bank)			(((bank) << 1) | BIT(6))
> +#define PRCMU_I2C_WRITE			0
> +#define PRCMU_I2C_READ			1
> +#define PRCMU_I2C_STOP_EN		BIT(3)
> +
> +/* Mailbox 5 ACKs */
> +#define PRCM_ACK_MB5_I2C_STATUS		(PRCM_ACK_MB5 + 0x1)
> +#define PRCM_ACK_MB5_I2C_VAL		(PRCM_ACK_MB5 + 0x3)
> +#define PRCMU_I2C_WR_OK			0x1
> +#define PRCMU_I2C_RD_OK			0x2
> +
> +/* AB8500 version registers */
> +#define AB8500_MISC_REV_REG		AB8500_MISC(0x80)
> +#define AB8500_MISC_IC_NAME_REG		AB8500_MISC(0x82)
> +
> +struct ab8500_priv {
> +	struct ab8500 ab8500;
> +	struct regmap *regmap;
> +};
> +
> +static inline int prcmu_tcdm_readb(struct regmap *map, uint offset, u8 *valp)
> +{
> +	return regmap_raw_read_range(map, PRCM_TCDM_RANGE, offset,
> +				     valp, sizeof(*valp));
> +}
> +
> +static inline int prcmu_tcdm_writeb(struct regmap *map, uint offset, u8 val)
> +{
> +	return regmap_raw_write_range(map, PRCM_TCDM_RANGE, offset,
> +				      &val, sizeof(val));
> +}
> +
> +static int prcmu_wait_i2c_mbx_ready(struct ab8500_priv *priv)
> +{
> +	uint val;
> +	int ret;
> +
> +	ret = regmap_read(priv->regmap, PRCM_ARM_IT1_VAL, &val);

Doesn't need to check about returned to error?

> +	if (ret == 0 && val & PRCMU_I2C_MBOX_BIT) {
> +		printf("ab8500: warning: PRCMU i2c mailbox was not acked\n");
> +		/* clear mailbox 5 ack irq */
> +		regmap_write(priv->regmap, PRCM_ARM_IT1_CLR, PRCMU_I2C_MBOX_BIT);

Not need to check the return value about regmap_write()?

> +	}
> +
> +	/* wait for on-going transaction, use 1s timeout */
> +	return regmap_read_poll_timeout(priv->regmap, PRCM_MBOX_CPU_VAL, val,
> +					!(val & PRCMU_I2C_MBOX_BIT), 0, 1000);
> +}
> +
> +static int prcmu_wait_i2c_mbx_done(struct ab8500_priv *priv)
> +{
> +	uint val;
> +	int ret;
> +
> +	/* set interrupt to XP70 */
> +	ret = regmap_write(priv->regmap, PRCM_MBOX_CPU_SET, PRCMU_I2C_MBOX_BIT);
> +	if (ret)
> +		return ret;
> +
> +	/* wait for mailbox 5 (i2c) ack, use 1s timeout */
> +	return regmap_read_poll_timeout(priv->regmap, PRCM_ARM_IT1_VAL, val,
> +					(val & PRCMU_I2C_MBOX_BIT), 0, 1000);
> +}
> +
> +static int ab8500_transfer(struct udevice *dev, uint bank_reg, u8 *val,
> +			   u8 op, u8 expected_status)
> +{
> +	struct ab8500_priv *priv = dev_get_priv(dev);
> +	u8 reg = bank_reg & 0xff;
> +	u8 bank = bank_reg >> 8;
> +	u8 status;
> +	int ret;
> +
> +	ret = prcmu_wait_i2c_mbx_ready(priv);
> +	if (ret)
> +		return ret;
> +
> +	ret = prcmu_tcdm_writeb(priv->regmap, PRCM_MBOX_HEADER_REQ_MB5, 0);
> +	if (ret)
> +		return ret;
> +	ret = prcmu_tcdm_writeb(priv->regmap, PRCM_REQ_MB5_I2C_SLAVE_OP,
> +				PRCMU_I2C(bank) | op);
> +	if (ret)
> +		return ret;
> +	ret = prcmu_tcdm_writeb(priv->regmap, PRCM_REQ_MB5_I2C_HW_BITS,
> +				PRCMU_I2C_STOP_EN);
> +	if (ret)
> +		return ret;
> +	ret = prcmu_tcdm_writeb(priv->regmap, PRCM_REQ_MB5_I2C_REG, reg);
> +	if (ret)
> +		return ret;
> +	ret = prcmu_tcdm_writeb(priv->regmap, PRCM_REQ_MB5_I2C_VAL, *val);
> +	if (ret)
> +		return ret;
> +
> +	ret = prcmu_wait_i2c_mbx_done(priv);
> +	if (ret) {
> +		printf("%s: mailbox request timed out\n", __func__);
> +		return ret;
> +	}
> +
> +	/* read transfer result */
> +	ret = prcmu_tcdm_readb(priv->regmap, PRCM_ACK_MB5_I2C_STATUS, &status);
> +	if (ret)
> +		return ret;
> +	ret = prcmu_tcdm_readb(priv->regmap, PRCM_ACK_MB5_I2C_VAL, val);
> +	if (ret)
> +		return ret;
> +
> +	/* clear mailbox 5 ack irq */
> +	regmap_write(priv->regmap, PRCM_ARM_IT1_CLR, PRCMU_I2C_MBOX_BIT);

Ditto.

> +
> +	if (status != expected_status) {
> +		/*
> +		 * AB8500 does not have the AB8500_MISC_IC_NAME_REG register,
> +		 * but we need to try reading it to detect AB8505.
> +		 * In case of an error, assume that we have AB8500.
> +		 */
> +		if (op == PRCMU_I2C_READ && bank_reg == AB8500_MISC_IC_NAME_REG) {
> +			*val = AB8500_VERSION_AB8500;
> +			return 0;
> +		}
> +
> +		printf("%s: return status %d\n", __func__, status);
> +		return -EIO;
> +	}
> +
> +	return 0;
> +}
> +
> +static int ab8500_reg_count(struct udevice *dev)
> +{
> +	return AB8500_NUM_REGISTERS;
> +}
> +
> +static int ab8500_read(struct udevice *dev, uint reg, uint8_t *buf, int len)
> +{
> +	int ret;
> +
> +	if (len != 1)
> +		return -EINVAL;
> +
> +	*buf = 0;
> +	ret = ab8500_transfer(dev, reg, buf, PRCMU_I2C_READ, PRCMU_I2C_RD_OK);
> +	if (ret) {
> +		printf("%s failed: %d\n", __func__, ret);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int ab8500_write(struct udevice *dev, uint reg, const uint8_t *buf, int len)
> +{
> +	int ret;
> +	u8 val;
> +
> +	if (len != 1)
> +		return -EINVAL;
> +
> +	val = *buf;
> +	ret = ab8500_transfer(dev, reg, &val, PRCMU_I2C_WRITE, PRCMU_I2C_WR_OK);
> +	if (ret) {
> +		printf("%s failed: %d\n", __func__, ret);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static struct dm_pmic_ops ab8500_ops = {
> +	.reg_count = ab8500_reg_count,
> +	.read = ab8500_read,
> +	.write = ab8500_write,
> +};
> +
> +static int ab8500_probe(struct udevice *dev)
> +{
> +	struct ab8500_priv *priv = dev_get_priv(dev);
> +	int ret;
> +
> +	/* get regmap from the PRCMU parent device (syscon in U-Boot) */
> +	priv->regmap = syscon_get_regmap(dev->parent);
> +	if (IS_ERR(priv->regmap))
> +		return PTR_ERR(priv->regmap);
> +
> +	ret = pmic_reg_read(dev, AB8500_MISC_IC_NAME_REG);
> +	if (ret < 0) {
> +		printf("ab8500: failed to read chip version: %d\n", ret);
> +		return ret;
> +	}
> +	priv->ab8500.version = ret;
> +
> +	ret = pmic_reg_read(dev, AB8500_MISC_REV_REG);
> +	if (ret < 0) {
> +		printf("ab8500: failed to read chip id: %d\n", ret);
> +		return ret;
> +	}
> +	priv->ab8500.chip_id = ret;
> +
> +	debug("ab8500: version: %#x, chip id: %#x\n",
> +	      priv->ab8500.version, priv->ab8500.chip_id);
> +
> +	return 0;
> +}
> +
> +static const struct udevice_id ab8500_ids[] = {
> +	{ .compatible = "stericsson,ab8500" },
> +	{ }
> +};
> +
> +U_BOOT_DRIVER(pmic_ab8500) = {
> +	.name		= "pmic_ab8500",
> +	.id		= UCLASS_PMIC,
> +	.of_match	= ab8500_ids,
> +	.bind		= dm_scan_fdt_dev,
> +	.probe		= ab8500_probe,
> +	.ops		= &ab8500_ops,
> +	.priv_auto	= sizeof(struct ab8500_priv),
> +};
> diff --git a/include/power/ab8500.h b/include/power/ab8500.h
> new file mode 100644
> index 0000000000..157eb4a5b1
> --- /dev/null
> +++ b/include/power/ab8500.h
> @@ -0,0 +1,125 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Based on include/linux/mfd/abx500/ab8500.h from Linux
> + * Copyright (C) ST-Ericsson SA 2010
> + * Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
> + */
> +
> +#ifndef _PMIC_AB8500_H_
> +#define _PMIC_AB8500_H_
> +
> +/*
> + * AB IC versions
> + *
> + * AB8500_VERSION_AB8500 should be 0xFF but will never be read as need a
> + * non-supported multi-byte I2C access via PRCMU. Set to 0x00 to ease the
> + * print of version string.
> + */
> +enum ab8500_version {
> +	AB8500_VERSION_AB8500 = 0x0,
> +	AB8500_VERSION_AB8505 = 0x1,
> +	AB8500_VERSION_AB9540 = 0x2,
> +	AB8500_VERSION_AB8540 = 0x4,
> +	AB8500_VERSION_UNDEFINED,
> +};
> +
> +/* AB8500 CIDs*/
> +#define AB8500_CUTEARLY	0x00
> +#define AB8500_CUT1P0	0x10
> +#define AB8500_CUT1P1	0x11
> +#define AB8500_CUT1P2	0x12 /* Only valid for AB8540 */
> +#define AB8500_CUT2P0	0x20
> +#define AB8500_CUT3P0	0x30
> +#define AB8500_CUT3P3	0x33
> +
> +/*
> + * AB8500 bank addresses
> + */
> +#define AB8500_BANK(bank, reg)		(((bank) << 8) | (reg))
> +#define AB8500_M_FSM_RANK(reg)		AB8500_BANK(0x0, reg)
> +#define AB8500_SYS_CTRL1_BLOCK(reg)	AB8500_BANK(0x1, reg)
> +#define AB8500_SYS_CTRL2_BLOCK(reg)	AB8500_BANK(0x2, reg)
> +#define AB8500_REGU_CTRL1(reg)		AB8500_BANK(0x3, reg)
> +#define AB8500_REGU_CTRL2(reg)		AB8500_BANK(0x4, reg)
> +#define AB8500_USB(reg)			AB8500_BANK(0x5, reg)
> +#define AB8500_TVOUT(reg)		AB8500_BANK(0x6, reg)
> +#define AB8500_DBI(reg)			AB8500_BANK(0x7, reg)
> +#define AB8500_ECI_AV_ACC(reg)		AB8500_BANK(0x8, reg)
> +#define AB8500_RESERVED(reg)		AB8500_BANK(0x9, reg)
> +#define AB8500_GPADC(reg)		AB8500_BANK(0xA, reg)
> +#define AB8500_CHARGER(reg)		AB8500_BANK(0xB, reg)
> +#define AB8500_GAS_GAUGE(reg)		AB8500_BANK(0xC, reg)
> +#define AB8500_AUDIO(reg)		AB8500_BANK(0xD, reg)
> +#define AB8500_INTERRUPT(reg)		AB8500_BANK(0xE, reg)
> +#define AB8500_RTC(reg)			AB8500_BANK(0xF, reg)
> +#define AB8500_GPIO(reg)		AB8500_BANK(0x10, reg)
> +#define AB8500_MISC(reg)		AB8500_BANK(0x10, reg)
> +#define AB8500_DEVELOPMENT(reg)		AB8500_BANK(0x11, reg)
> +#define AB8500_DEBUG(reg)		AB8500_BANK(0x12, reg)
> +#define AB8500_PROD_TEST(reg)		AB8500_BANK(0x13, reg)
> +#define AB8500_STE_TEST(reg)		AB8500_BANK(0x14, reg)
> +#define AB8500_OTP_EMUL(reg)		AB8500_BANK(0x15, reg)
> +
> +#define AB8500_NUM_BANKS		0x16
> +#define AB8500_NUM_REGISTERS		AB8500_BANK(AB8500_NUM_BANKS, 0)
> +
> +struct ab8500 {
> +	enum ab8500_version version;
> +	u8 chip_id;
> +};> +

I have checked that below codes are existed in linux kernel. 
But I didn't find where the below codes is used in U-boot.
Will it be used in future? 

Best Regards,
Jaehoon Chung

> +static inline int is_ab8500(struct ab8500 *ab)
> +{
> +	return ab->version == AB8500_VERSION_AB8500;
> +}
> +
> +static inline int is_ab8505(struct ab8500 *ab)
> +{
> +	return ab->version == AB8500_VERSION_AB8505;
> +}
> +
> +/* exclude also ab8505, ab9540... */
> +static inline int is_ab8500_1p0_or_earlier(struct ab8500 *ab)
> +{
> +	return (is_ab8500(ab) && (ab->chip_id <= AB8500_CUT1P0));
> +}
> +
> +/* exclude also ab8505, ab9540... */
> +static inline int is_ab8500_1p1_or_earlier(struct ab8500 *ab)
> +{
> +	return (is_ab8500(ab) && (ab->chip_id <= AB8500_CUT1P1));
> +}
> +
> +/* exclude also ab8505, ab9540... */
> +static inline int is_ab8500_2p0_or_earlier(struct ab8500 *ab)
> +{
> +	return (is_ab8500(ab) && (ab->chip_id <= AB8500_CUT2P0));
> +}
> +
> +static inline int is_ab8500_3p3_or_earlier(struct ab8500 *ab)
> +{
> +	return (is_ab8500(ab) && (ab->chip_id <= AB8500_CUT3P3));
> +}
> +
> +/* exclude also ab8505, ab9540... */
> +static inline int is_ab8500_2p0(struct ab8500 *ab)
> +{
> +	return (is_ab8500(ab) && (ab->chip_id == AB8500_CUT2P0));
> +}
> +
> +static inline int is_ab8505_1p0_or_earlier(struct ab8500 *ab)
> +{
> +	return (is_ab8505(ab) && (ab->chip_id <= AB8500_CUT1P0));
> +}
> +
> +static inline int is_ab8505_2p0(struct ab8500 *ab)
> +{
> +	return (is_ab8505(ab) && (ab->chip_id == AB8500_CUT2P0));
> +}
> +
> +static inline int is_ab8505_2p0_earlier(struct ab8500 *ab)
> +{
> +	return (is_ab8505(ab) && (ab->chip_id < AB8500_CUT2P0));
> +}
> +
> +#endif
> 


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 2/3] phy: Add driver for ST-Ericsson AB8500 USB PHY
  2021-07-05 16:28 ` [PATCH 2/3] phy: Add driver for ST-Ericsson AB8500 USB PHY Stephan Gerhold
@ 2021-07-06  1:10   ` Jaehoon Chung
  2021-07-06  9:01     ` Stephan Gerhold
  2021-07-07 23:46   ` Linus Walleij
  1 sibling, 1 reply; 12+ messages in thread
From: Jaehoon Chung @ 2021-07-06  1:10 UTC (permalink / raw)
  To: Stephan Gerhold, u-boot; +Cc: Marek Vasut, Linus Walleij, Joe Hershberger

Hi Stephan,

On 7/6/21 1:28 AM, Stephan Gerhold wrote:
> The AB8500 PMIC contains an USB PHY that needs to be set up in
> device or host mode to make USB work properly. Add a simple driver
> for the generic PHY uclass that allows enabling it.
> 
> The if (CONFIG_IS_ENABLED(USB_MUSB_HOST)) might be a bit strange.
> The USB PHY must be configured in either host or device mode and
> somehow the USB PHY driver must be made aware of the mode.
> 
> Actually, the MUSB driver used together with this PHY does not
> support dynamic selection of host/device mode in U-Boot at the moment.
> Therefore, one very simple approach that works fine is to select
> the mode to configure at compile time. When the MUSB driver is
> configured in host mode the PHY is configured in host mode, and
> similarly when the MUSB driver is configured in device/gadget mode.
> 
> Cc: Linus Walleij <linus.walleij@linaro.org>
> Signed-off-by: Stephan Gerhold <stephan@gerhold.net>
> ---
> 
> Better suggestions to make the USB PHY driver aware of the mode
> are very welcome. :) I'm not sure it's worth it though, the compile
> time selection is not ideal but it does the job just fine for now.
> ---
>  drivers/phy/Kconfig          |  6 ++++
>  drivers/phy/Makefile         |  1 +
>  drivers/phy/phy-ab8500-usb.c | 54 ++++++++++++++++++++++++++++++++++++
>  3 files changed, 61 insertions(+)
>  create mode 100644 drivers/phy/phy-ab8500-usb.c
> 
> diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
> index 008186a10d..92c74b9d0b 100644
> --- a/drivers/phy/Kconfig
> +++ b/drivers/phy/Kconfig
> @@ -64,6 +64,12 @@ config MIPI_DPHY_HELPERS
>  	help
>  	  Provides a number of helpers a core functions for MIPI D-PHY drivers.
>  
> +config AB8500_USB_PHY
> +	bool "AB8500 USB PHY Driver"
> +	depends on PHY && PMIC_AB8500
> +	help
> +	  Support for the USB OTG PHY in ST-Ericsson AB8500.
> +
>  config BCM6318_USBH_PHY
>  	bool "BCM6318 USBH PHY support"
>  	depends on PHY && ARCH_BMIPS
> diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
> index 3c4a673a83..bf03d05d9b 100644
> --- a/drivers/phy/Makefile
> +++ b/drivers/phy/Makefile
> @@ -6,6 +6,7 @@
>  obj-$(CONFIG_$(SPL_)PHY) += phy-uclass.o
>  obj-$(CONFIG_$(SPL_)NOP_PHY) += nop-phy.o
>  obj-$(CONFIG_MIPI_DPHY_HELPERS) += phy-core-mipi-dphy.o
> +obj-$(CONFIG_AB8500_USB_PHY) += phy-ab8500-usb.o
>  obj-$(CONFIG_BCM6318_USBH_PHY) += bcm6318-usbh-phy.o
>  obj-$(CONFIG_BCM6348_USBH_PHY) += bcm6348-usbh-phy.o
>  obj-$(CONFIG_BCM6358_USBH_PHY) += bcm6358-usbh-phy.o
> diff --git a/drivers/phy/phy-ab8500-usb.c b/drivers/phy/phy-ab8500-usb.c
> new file mode 100644
> index 0000000000..4ecb03a9cb
> --- /dev/null
> +++ b/drivers/phy/phy-ab8500-usb.c
> @@ -0,0 +1,54 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/* Copyright (C) 2019 Stephan Gerhold */
> +
> +#include <common.h>
> +#include <dm.h>
> +#include <generic-phy.h>
> +#include <linux/bitops.h>
> +#include <power/pmic.h>
> +#include <power/ab8500.h>
> +
> +#define AB8500_USB_PHY_CTRL_REG			AB8500_USB(0x8A)
> +#define AB8500_BIT_PHY_CTRL_HOST_EN		BIT(0)
> +#define AB8500_BIT_PHY_CTRL_DEVICE_EN		BIT(1)
> +#define AB8500_USB_PHY_CTRL_MASK		(AB8500_BIT_PHY_CTRL_HOST_EN |\
> +						 AB8500_BIT_PHY_CTRL_DEVICE_EN)
> +
> +static int ab8500_usb_phy_power_on(struct phy *phy)
> +{
> +	struct udevice *dev = phy->dev;
> +	uint set;
> +

unit set = AB8500_BIT_PHY_CTRL_DEVICE_EN;

if (CONFIG_IS_ENABLED(USB)MUSB_HOST))
	set = ...;

how about that?

> +	if (CONFIG_IS_ENABLED(USB_MUSB_HOST))
> +		set = AB8500_BIT_PHY_CTRL_HOST_EN;
> +	else
> +		set = AB8500_BIT_PHY_CTRL_DEVICE_EN;
> +
> +	return pmic_clrsetbits(dev->parent, AB8500_USB_PHY_CTRL_REG,
> +			       AB8500_USB_PHY_CTRL_MASK, set);
> +}
> +
> +static int ab8500_usb_phy_power_off(struct phy *phy)
> +{
> +	struct udevice *dev = phy->dev;
> +
> +	return pmic_clrsetbits(dev->parent, AB8500_USB_PHY_CTRL_REG,
> +			       AB8500_USB_PHY_CTRL_MASK, 0);
> +}
> +
> +struct phy_ops ab8500_usb_phy_ops = {
> +	.power_on = ab8500_usb_phy_power_on,
> +	.power_off = ab8500_usb_phy_power_off,
> +};
> +
> +static const struct udevice_id ab8500_usb_phy_ids[] = {
> +	{ .compatible = "stericsson,ab8500-usb" },
> +	{ }
> +};
> +
> +U_BOOT_DRIVER(ab8500_usb_phy) = {
> +	.name = "ab8500_usb_phy",
> +	.id = UCLASS_PHY,
> +	.of_match = ab8500_usb_phy_ids,
> +	.ops = &ab8500_usb_phy_ops,
> +};
> 


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 1/3] power: pmic: Add driver for ST-Ericsson AB8500 via PRCMU
  2021-07-06  1:08   ` Jaehoon Chung
@ 2021-07-06  8:52     ` Stephan Gerhold
  2021-07-06 21:25       ` Jaehoon Chung
  0 siblings, 1 reply; 12+ messages in thread
From: Stephan Gerhold @ 2021-07-06  8:52 UTC (permalink / raw)
  To: Jaehoon Chung; +Cc: u-boot, Marek Vasut, Linus Walleij, Joe Hershberger

On Tue, Jul 06, 2021 at 10:08:03AM +0900, Jaehoon Chung wrote:
> On 7/6/21 1:28 AM, Stephan Gerhold wrote:
> > All devices based on ST-Ericsson Ux500 use a PMIC similar to AB8500
> > (Analog Baseband). There is AB8500, AB8505, AB9540 and AB8540
> > although in practice only AB8500 and AB8505 are relevant since the
> > platforms with AB9540 and AB8540 were cancelled and never used in
> > production.
> > 
> > In general, the AB8500 PMIC uses I2C as control interface, where the
> > different register banks are represented as separate I2C devices.
> > However, in practice AB8500 is always connected to a special I2C bus
> > on the DB8500 SoC that is controlled by the power/reset/clock
> > management unit (PRCMU) firmware.
> > 
> > Add a simple driver that allows reading/writing registers of the
> > AB8500 PMIC. The driver directly accesses registers from the PRCMU
> > parent device (represented by syscon in U-Boot). Abstracting it
> > further (e.g. with the i2c uclass) would not provide any advantage
> > because the PRCMU I2C bus is always just connected to AB8500 and
> > vice-versa.
> > 
> > The ab8500.h header is mostly taken as-is from Linux (with some
> > minor adjustments) to allow using similar code in both Linux and
> > U-Boot.
> > 
> > Cc: Linus Walleij <linus.walleij@linaro.org>
> > Signed-off-by: Stephan Gerhold <stephan@gerhold.net>
> > ---
> > 
> >  drivers/power/pmic/Kconfig  |  10 ++
> >  drivers/power/pmic/Makefile |   1 +
> >  drivers/power/pmic/ab8500.c | 258 ++++++++++++++++++++++++++++++++++++
> >  include/power/ab8500.h      | 125 +++++++++++++++++
> >  4 files changed, 394 insertions(+)
> >  create mode 100644 drivers/power/pmic/ab8500.c
> >  create mode 100644 include/power/ab8500.h
> > 
> > diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig
> > index 583fd3ddcd..fd6648b313 100644
> > --- a/drivers/power/pmic/Kconfig
> > +++ b/drivers/power/pmic/Kconfig
> > @@ -31,6 +31,16 @@ config SPL_PMIC_CHILDREN
> >  	to call your regulator code (e.g. see rk8xx.c for direct functions
> >  	for use in SPL).
> >  
> > +config PMIC_AB8500
> > +	bool "Enable driver for ST-Ericsson AB8500 PMIC via PRCMU"
> > +	depends on DM_PMIC
> > +	select REGMAP
> > +	select SYSCON
> > +	help
> > +	  Enable support for the ST-Ericsson AB8500 (Analog Baseband) PMIC.
> > +	  It connects with the ST-Ericsson DB8500 SoC via an I2C bus managed by
> > +	  the power/reset/clock management unit (PRCMU) firmware.
> > +
> >  config PMIC_ACT8846
> >  	bool "Enable support for the active-semi 8846 PMIC"
> >  	depends on DM_PMIC && DM_I2C
> > diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile
> > index 89099fde57..5d1a97e5f6 100644
> > --- a/drivers/power/pmic/Makefile
> > +++ b/drivers/power/pmic/Makefile
> > @@ -15,6 +15,7 @@ obj-$(CONFIG_$(SPL_)DM_PMIC_PFUZE100) += pfuze100.o
> >  obj-$(CONFIG_$(SPL_)DM_PMIC_PCA9450) += pca9450.o
> >  obj-$(CONFIG_PMIC_S2MPS11) += s2mps11.o
> >  obj-$(CONFIG_DM_PMIC_SANDBOX) += sandbox.o i2c_pmic_emul.o
> > +obj-$(CONFIG_PMIC_AB8500) += ab8500.o
> >  obj-$(CONFIG_PMIC_ACT8846) += act8846.o
> >  obj-$(CONFIG_PMIC_AS3722) += as3722.o as3722_gpio.o
> >  obj-$(CONFIG_PMIC_MAX8997) += max8997.o
> > diff --git a/drivers/power/pmic/ab8500.c b/drivers/power/pmic/ab8500.c
> > new file mode 100644
> > index 0000000000..a87a3b497c
> > --- /dev/null
> > +++ b/drivers/power/pmic/ab8500.c
> > @@ -0,0 +1,258 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/*
> > + * Copyright (C) 2019 Stephan Gerhold
> > + *
> > + * Adapted from old U-Boot and Linux kernel implementation:
> > + * Copyright (C) STMicroelectronics 2009
> > + * Copyright (C) ST-Ericsson SA 2010
> > + */
> > +
> > +#include <common.h>
> > +#include <dm.h>
> > +#include <regmap.h>
> > +#include <syscon.h>
> > +#include <linux/bitops.h>
> > +#include <linux/err.h>
> > +#include <power/ab8500.h>
> > +#include <power/pmic.h>
> > +
> > +/* CPU mailbox registers */
> > +#define PRCM_MBOX_CPU_VAL		0x0fc
> > +#define PRCM_MBOX_CPU_SET		0x100
> > +#define PRCM_MBOX_CPU_CLR		0x104
> > +
> > +#define PRCM_ARM_IT1_CLR		0x48C
> > +#define PRCM_ARM_IT1_VAL		0x494
> > +
> > +#define PRCM_TCDM_RANGE			2
> > +#define PRCM_REQ_MB5			0xE44
> > +#define PRCM_ACK_MB5			0xDF4
> > +#define _PRCM_MBOX_HEADER		0xFE8
> > +#define PRCM_MBOX_HEADER_REQ_MB5	(_PRCM_MBOX_HEADER + 0x5)
> > +#define PRCMU_I2C_MBOX_BIT		BIT(5)
> > +
> > +/* Mailbox 5 Requests */
> > +#define PRCM_REQ_MB5_I2C_SLAVE_OP	(PRCM_REQ_MB5 + 0x0)
> > +#define PRCM_REQ_MB5_I2C_HW_BITS	(PRCM_REQ_MB5 + 0x1)
> > +#define PRCM_REQ_MB5_I2C_REG		(PRCM_REQ_MB5 + 0x2)
> > +#define PRCM_REQ_MB5_I2C_VAL		(PRCM_REQ_MB5 + 0x3)
> > +#define PRCMU_I2C(bank)			(((bank) << 1) | BIT(6))
> > +#define PRCMU_I2C_WRITE			0
> > +#define PRCMU_I2C_READ			1
> > +#define PRCMU_I2C_STOP_EN		BIT(3)
> > +
> > +/* Mailbox 5 ACKs */
> > +#define PRCM_ACK_MB5_I2C_STATUS		(PRCM_ACK_MB5 + 0x1)
> > +#define PRCM_ACK_MB5_I2C_VAL		(PRCM_ACK_MB5 + 0x3)
> > +#define PRCMU_I2C_WR_OK			0x1
> > +#define PRCMU_I2C_RD_OK			0x2
> > +
> > +/* AB8500 version registers */
> > +#define AB8500_MISC_REV_REG		AB8500_MISC(0x80)
> > +#define AB8500_MISC_IC_NAME_REG		AB8500_MISC(0x82)
> > +
> > +struct ab8500_priv {
> > +	struct ab8500 ab8500;
> > +	struct regmap *regmap;
> > +};
> > +
> > +static inline int prcmu_tcdm_readb(struct regmap *map, uint offset, u8 *valp)
> > +{
> > +	return regmap_raw_read_range(map, PRCM_TCDM_RANGE, offset,
> > +				     valp, sizeof(*valp));
> > +}
> > +
> > +static inline int prcmu_tcdm_writeb(struct regmap *map, uint offset, u8 val)
> > +{
> > +	return regmap_raw_write_range(map, PRCM_TCDM_RANGE, offset,
> > +				      &val, sizeof(val));
> > +}
> > +
> > +static int prcmu_wait_i2c_mbx_ready(struct ab8500_priv *priv)
> > +{
> > +	uint val;
> > +	int ret;
> > +
> > +	ret = regmap_read(priv->regmap, PRCM_ARM_IT1_VAL, &val);
> 
> Doesn't need to check about returned to error?
> 
> > +	if (ret == 0 && val & PRCMU_I2C_MBOX_BIT) {
> > +		printf("ab8500: warning: PRCMU i2c mailbox was not acked\n");
> > +		/* clear mailbox 5 ack irq */
> > +		regmap_write(priv->regmap, PRCM_ARM_IT1_CLR, PRCMU_I2C_MBOX_BIT);
> 
> Not need to check the return value about regmap_write()?
> 

Good point, it's probably better to return in case of errors here.

> > [...]
> > +
> > +	/* clear mailbox 5 ack irq */
> > +	regmap_write(priv->regmap, PRCM_ARM_IT1_CLR, PRCMU_I2C_MBOX_BIT);
> 
> Ditto.
> 

But here it doesn't really make sense: The read/write is already done.
Even if we don't manage to clear the IRQ the read/write will still have
succeeded. I will add a comment to clarify this.

> > +
> > +	if (status != expected_status) {
> > +		/*
> > +		 * AB8500 does not have the AB8500_MISC_IC_NAME_REG register,
> > +		 * but we need to try reading it to detect AB8505.
> > +		 * In case of an error, assume that we have AB8500.
> > +		 */
> > +		if (op == PRCMU_I2C_READ && bank_reg == AB8500_MISC_IC_NAME_REG) {
> > +			*val = AB8500_VERSION_AB8500;
> > +			return 0;
> > +		}
> > +
> > +		printf("%s: return status %d\n", __func__, status);
> > +		return -EIO;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static int ab8500_reg_count(struct udevice *dev)
> > +{
> > +	return AB8500_NUM_REGISTERS;
> > +}
> > +
> > +static int ab8500_read(struct udevice *dev, uint reg, uint8_t *buf, int len)
> > +{
> > +	int ret;
> > +
> > +	if (len != 1)
> > +		return -EINVAL;
> > +
> > +	*buf = 0;
> > +	ret = ab8500_transfer(dev, reg, buf, PRCMU_I2C_READ, PRCMU_I2C_RD_OK);
> > +	if (ret) {
> > +		printf("%s failed: %d\n", __func__, ret);
> > +		return ret;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static int ab8500_write(struct udevice *dev, uint reg, const uint8_t *buf, int len)
> > +{
> > +	int ret;
> > +	u8 val;
> > +
> > +	if (len != 1)
> > +		return -EINVAL;
> > +
> > +	val = *buf;
> > +	ret = ab8500_transfer(dev, reg, &val, PRCMU_I2C_WRITE, PRCMU_I2C_WR_OK);
> > +	if (ret) {
> > +		printf("%s failed: %d\n", __func__, ret);
> > +		return ret;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static struct dm_pmic_ops ab8500_ops = {
> > +	.reg_count = ab8500_reg_count,
> > +	.read = ab8500_read,
> > +	.write = ab8500_write,
> > +};
> > +
> > +static int ab8500_probe(struct udevice *dev)
> > +{
> > +	struct ab8500_priv *priv = dev_get_priv(dev);
> > +	int ret;
> > +
> > +	/* get regmap from the PRCMU parent device (syscon in U-Boot) */
> > +	priv->regmap = syscon_get_regmap(dev->parent);
> > +	if (IS_ERR(priv->regmap))
> > +		return PTR_ERR(priv->regmap);
> > +
> > +	ret = pmic_reg_read(dev, AB8500_MISC_IC_NAME_REG);
> > +	if (ret < 0) {
> > +		printf("ab8500: failed to read chip version: %d\n", ret);
> > +		return ret;
> > +	}
> > +	priv->ab8500.version = ret;
> > +
> > +	ret = pmic_reg_read(dev, AB8500_MISC_REV_REG);
> > +	if (ret < 0) {
> > +		printf("ab8500: failed to read chip id: %d\n", ret);
> > +		return ret;
> > +	}
> > +	priv->ab8500.chip_id = ret;
> > +
> > +	debug("ab8500: version: %#x, chip id: %#x\n",
> > +	      priv->ab8500.version, priv->ab8500.chip_id);
> > +
> > +	return 0;
> > +}
> > +
> > +static const struct udevice_id ab8500_ids[] = {
> > +	{ .compatible = "stericsson,ab8500" },
> > +	{ }
> > +};
> > +
> > +U_BOOT_DRIVER(pmic_ab8500) = {
> > +	.name		= "pmic_ab8500",
> > +	.id		= UCLASS_PMIC,
> > +	.of_match	= ab8500_ids,
> > +	.bind		= dm_scan_fdt_dev,
> > +	.probe		= ab8500_probe,
> > +	.ops		= &ab8500_ops,
> > +	.priv_auto	= sizeof(struct ab8500_priv),
> > +};
> > diff --git a/include/power/ab8500.h b/include/power/ab8500.h
> > new file mode 100644
> > index 0000000000..157eb4a5b1
> > --- /dev/null
> > +++ b/include/power/ab8500.h
> > @@ -0,0 +1,125 @@
> > +/* SPDX-License-Identifier: GPL-2.0-only */
> > +/*
> > + * Based on include/linux/mfd/abx500/ab8500.h from Linux
> > + * Copyright (C) ST-Ericsson SA 2010
> > + * Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
> > + */
> > +
> > +#ifndef _PMIC_AB8500_H_
> > +#define _PMIC_AB8500_H_
> > +
> > +/*
> > + * AB IC versions
> > + *
> > + * AB8500_VERSION_AB8500 should be 0xFF but will never be read as need a
> > + * non-supported multi-byte I2C access via PRCMU. Set to 0x00 to ease the
> > + * print of version string.
> > + */
> > +enum ab8500_version {
> > +	AB8500_VERSION_AB8500 = 0x0,
> > +	AB8500_VERSION_AB8505 = 0x1,
> > +	AB8500_VERSION_AB9540 = 0x2,
> > +	AB8500_VERSION_AB8540 = 0x4,
> > +	AB8500_VERSION_UNDEFINED,
> > +};
> > +
> > +/* AB8500 CIDs*/
> > +#define AB8500_CUTEARLY	0x00
> > +#define AB8500_CUT1P0	0x10
> > +#define AB8500_CUT1P1	0x11
> > +#define AB8500_CUT1P2	0x12 /* Only valid for AB8540 */
> > +#define AB8500_CUT2P0	0x20
> > +#define AB8500_CUT3P0	0x30
> > +#define AB8500_CUT3P3	0x33
> > +
> > +/*
> > + * AB8500 bank addresses
> > + */
> > +#define AB8500_BANK(bank, reg)		(((bank) << 8) | (reg))
> > +#define AB8500_M_FSM_RANK(reg)		AB8500_BANK(0x0, reg)
> > +#define AB8500_SYS_CTRL1_BLOCK(reg)	AB8500_BANK(0x1, reg)
> > +#define AB8500_SYS_CTRL2_BLOCK(reg)	AB8500_BANK(0x2, reg)
> > +#define AB8500_REGU_CTRL1(reg)		AB8500_BANK(0x3, reg)
> > +#define AB8500_REGU_CTRL2(reg)		AB8500_BANK(0x4, reg)
> > +#define AB8500_USB(reg)			AB8500_BANK(0x5, reg)
> > +#define AB8500_TVOUT(reg)		AB8500_BANK(0x6, reg)
> > +#define AB8500_DBI(reg)			AB8500_BANK(0x7, reg)
> > +#define AB8500_ECI_AV_ACC(reg)		AB8500_BANK(0x8, reg)
> > +#define AB8500_RESERVED(reg)		AB8500_BANK(0x9, reg)
> > +#define AB8500_GPADC(reg)		AB8500_BANK(0xA, reg)
> > +#define AB8500_CHARGER(reg)		AB8500_BANK(0xB, reg)
> > +#define AB8500_GAS_GAUGE(reg)		AB8500_BANK(0xC, reg)
> > +#define AB8500_AUDIO(reg)		AB8500_BANK(0xD, reg)
> > +#define AB8500_INTERRUPT(reg)		AB8500_BANK(0xE, reg)
> > +#define AB8500_RTC(reg)			AB8500_BANK(0xF, reg)
> > +#define AB8500_GPIO(reg)		AB8500_BANK(0x10, reg)
> > +#define AB8500_MISC(reg)		AB8500_BANK(0x10, reg)
> > +#define AB8500_DEVELOPMENT(reg)		AB8500_BANK(0x11, reg)
> > +#define AB8500_DEBUG(reg)		AB8500_BANK(0x12, reg)
> > +#define AB8500_PROD_TEST(reg)		AB8500_BANK(0x13, reg)
> > +#define AB8500_STE_TEST(reg)		AB8500_BANK(0x14, reg)
> > +#define AB8500_OTP_EMUL(reg)		AB8500_BANK(0x15, reg)
> > +
> > +#define AB8500_NUM_BANKS		0x16
> > +#define AB8500_NUM_REGISTERS		AB8500_BANK(AB8500_NUM_BANKS, 0)
> > +
> > +struct ab8500 {
> > +	enum ab8500_version version;
> > +	u8 chip_id;
> > +};> +
> 
> I have checked that below codes are existed in linux kernel. 
> But I didn't find where the below codes is used in U-boot.
> Will it be used in future? 
> 

At the moment I don't have any drivers myself that make use of this.
However, it would certainly be needed if more advanced drivers for
AB8500 are written. I don't know if this will happen anytime soon.

I can remove these if you would prefer to have them added once they are
actually needed. What do you think?

Thanks!
Stephan

> > +static inline int is_ab8500(struct ab8500 *ab)
> > +{
> > +	return ab->version == AB8500_VERSION_AB8500;
> > +}
> > +
> > +static inline int is_ab8505(struct ab8500 *ab)
> > +{
> > +	return ab->version == AB8500_VERSION_AB8505;
> > +}
> > +
> > +/* exclude also ab8505, ab9540... */
> > +static inline int is_ab8500_1p0_or_earlier(struct ab8500 *ab)
> > +{
> > +	return (is_ab8500(ab) && (ab->chip_id <= AB8500_CUT1P0));
> > +}
> > +
> > +/* exclude also ab8505, ab9540... */
> > +static inline int is_ab8500_1p1_or_earlier(struct ab8500 *ab)
> > +{
> > +	return (is_ab8500(ab) && (ab->chip_id <= AB8500_CUT1P1));
> > +}
> > +
> > +/* exclude also ab8505, ab9540... */
> > +static inline int is_ab8500_2p0_or_earlier(struct ab8500 *ab)
> > +{
> > +	return (is_ab8500(ab) && (ab->chip_id <= AB8500_CUT2P0));
> > +}
> > +
> > +static inline int is_ab8500_3p3_or_earlier(struct ab8500 *ab)
> > +{
> > +	return (is_ab8500(ab) && (ab->chip_id <= AB8500_CUT3P3));
> > +}
> > +
> > +/* exclude also ab8505, ab9540... */
> > +static inline int is_ab8500_2p0(struct ab8500 *ab)
> > +{
> > +	return (is_ab8500(ab) && (ab->chip_id == AB8500_CUT2P0));
> > +}
> > +
> > +static inline int is_ab8505_1p0_or_earlier(struct ab8500 *ab)
> > +{
> > +	return (is_ab8505(ab) && (ab->chip_id <= AB8500_CUT1P0));
> > +}
> > +
> > +static inline int is_ab8505_2p0(struct ab8500 *ab)
> > +{
> > +	return (is_ab8505(ab) && (ab->chip_id == AB8500_CUT2P0));
> > +}
> > +
> > +static inline int is_ab8505_2p0_earlier(struct ab8500 *ab)
> > +{
> > +	return (is_ab8505(ab) && (ab->chip_id < AB8500_CUT2P0));
> > +}
> > +
> > +#endif
> > 
> 

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 2/3] phy: Add driver for ST-Ericsson AB8500 USB PHY
  2021-07-06  1:10   ` Jaehoon Chung
@ 2021-07-06  9:01     ` Stephan Gerhold
  0 siblings, 0 replies; 12+ messages in thread
From: Stephan Gerhold @ 2021-07-06  9:01 UTC (permalink / raw)
  To: Jaehoon Chung; +Cc: u-boot, Marek Vasut, Linus Walleij, Joe Hershberger

On Tue, Jul 06, 2021 at 10:10:54AM +0900, Jaehoon Chung wrote:
> Hi Stephan,
> 
> On 7/6/21 1:28 AM, Stephan Gerhold wrote:
> > The AB8500 PMIC contains an USB PHY that needs to be set up in
> > device or host mode to make USB work properly. Add a simple driver
> > for the generic PHY uclass that allows enabling it.
> > 
> > The if (CONFIG_IS_ENABLED(USB_MUSB_HOST)) might be a bit strange.
> > The USB PHY must be configured in either host or device mode and
> > somehow the USB PHY driver must be made aware of the mode.
> > 
> > Actually, the MUSB driver used together with this PHY does not
> > support dynamic selection of host/device mode in U-Boot at the moment.
> > Therefore, one very simple approach that works fine is to select
> > the mode to configure at compile time. When the MUSB driver is
> > configured in host mode the PHY is configured in host mode, and
> > similarly when the MUSB driver is configured in device/gadget mode.
> > 
> > Cc: Linus Walleij <linus.walleij@linaro.org>
> > Signed-off-by: Stephan Gerhold <stephan@gerhold.net>
> > ---
> > 
> > Better suggestions to make the USB PHY driver aware of the mode
> > are very welcome. :) I'm not sure it's worth it though, the compile
> > time selection is not ideal but it does the job just fine for now.
> > ---
> >  drivers/phy/Kconfig          |  6 ++++
> >  drivers/phy/Makefile         |  1 +
> >  drivers/phy/phy-ab8500-usb.c | 54 ++++++++++++++++++++++++++++++++++++
> >  3 files changed, 61 insertions(+)
> >  create mode 100644 drivers/phy/phy-ab8500-usb.c
> > 
> > diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
> > index 008186a10d..92c74b9d0b 100644
> > --- a/drivers/phy/Kconfig
> > +++ b/drivers/phy/Kconfig
> > @@ -64,6 +64,12 @@ config MIPI_DPHY_HELPERS
> >  	help
> >  	  Provides a number of helpers a core functions for MIPI D-PHY drivers.
> >  
> > +config AB8500_USB_PHY
> > +	bool "AB8500 USB PHY Driver"
> > +	depends on PHY && PMIC_AB8500
> > +	help
> > +	  Support for the USB OTG PHY in ST-Ericsson AB8500.
> > +
> >  config BCM6318_USBH_PHY
> >  	bool "BCM6318 USBH PHY support"
> >  	depends on PHY && ARCH_BMIPS
> > diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
> > index 3c4a673a83..bf03d05d9b 100644
> > --- a/drivers/phy/Makefile
> > +++ b/drivers/phy/Makefile
> > @@ -6,6 +6,7 @@
> >  obj-$(CONFIG_$(SPL_)PHY) += phy-uclass.o
> >  obj-$(CONFIG_$(SPL_)NOP_PHY) += nop-phy.o
> >  obj-$(CONFIG_MIPI_DPHY_HELPERS) += phy-core-mipi-dphy.o
> > +obj-$(CONFIG_AB8500_USB_PHY) += phy-ab8500-usb.o
> >  obj-$(CONFIG_BCM6318_USBH_PHY) += bcm6318-usbh-phy.o
> >  obj-$(CONFIG_BCM6348_USBH_PHY) += bcm6348-usbh-phy.o
> >  obj-$(CONFIG_BCM6358_USBH_PHY) += bcm6358-usbh-phy.o
> > diff --git a/drivers/phy/phy-ab8500-usb.c b/drivers/phy/phy-ab8500-usb.c
> > new file mode 100644
> > index 0000000000..4ecb03a9cb
> > --- /dev/null
> > +++ b/drivers/phy/phy-ab8500-usb.c
> > @@ -0,0 +1,54 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/* Copyright (C) 2019 Stephan Gerhold */
> > +
> > +#include <common.h>
> > +#include <dm.h>
> > +#include <generic-phy.h>
> > +#include <linux/bitops.h>
> > +#include <power/pmic.h>
> > +#include <power/ab8500.h>
> > +
> > +#define AB8500_USB_PHY_CTRL_REG			AB8500_USB(0x8A)
> > +#define AB8500_BIT_PHY_CTRL_HOST_EN		BIT(0)
> > +#define AB8500_BIT_PHY_CTRL_DEVICE_EN		BIT(1)
> > +#define AB8500_USB_PHY_CTRL_MASK		(AB8500_BIT_PHY_CTRL_HOST_EN |\
> > +						 AB8500_BIT_PHY_CTRL_DEVICE_EN)
> > +
> > +static int ab8500_usb_phy_power_on(struct phy *phy)
> > +{
> > +	struct udevice *dev = phy->dev;
> > +	uint set;
> > +
> 
> unit set = AB8500_BIT_PHY_CTRL_DEVICE_EN;
> 
> if (CONFIG_IS_ENABLED(USB)MUSB_HOST))
> 	set = ...;
> 
> how about that?
> 

Both looks fine to me, I can change it in v2.

> > +	if (CONFIG_IS_ENABLED(USB_MUSB_HOST))
> > +		set = AB8500_BIT_PHY_CTRL_HOST_EN;
> > +	else
> > +		set = AB8500_BIT_PHY_CTRL_DEVICE_EN;
> > +
> > +	return pmic_clrsetbits(dev->parent, AB8500_USB_PHY_CTRL_REG,
> > +			       AB8500_USB_PHY_CTRL_MASK, set);
> > +}

Thanks for the review!
Stephan

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 1/3] power: pmic: Add driver for ST-Ericsson AB8500 via PRCMU
  2021-07-06  8:52     ` Stephan Gerhold
@ 2021-07-06 21:25       ` Jaehoon Chung
  2021-07-07 13:15         ` Stephan Gerhold
  0 siblings, 1 reply; 12+ messages in thread
From: Jaehoon Chung @ 2021-07-06 21:25 UTC (permalink / raw)
  To: Stephan Gerhold; +Cc: u-boot, Marek Vasut, Linus Walleij, Joe Hershberger

On 7/6/21 5:52 PM, Stephan Gerhold wrote:
> On Tue, Jul 06, 2021 at 10:08:03AM +0900, Jaehoon Chung wrote:
>> On 7/6/21 1:28 AM, Stephan Gerhold wrote:
>>> All devices based on ST-Ericsson Ux500 use a PMIC similar to AB8500
>>> (Analog Baseband). There is AB8500, AB8505, AB9540 and AB8540
>>> although in practice only AB8500 and AB8505 are relevant since the
>>> platforms with AB9540 and AB8540 were cancelled and never used in
>>> production.
>>>
>>> In general, the AB8500 PMIC uses I2C as control interface, where the
>>> different register banks are represented as separate I2C devices.
>>> However, in practice AB8500 is always connected to a special I2C bus
>>> on the DB8500 SoC that is controlled by the power/reset/clock
>>> management unit (PRCMU) firmware.
>>>
>>> Add a simple driver that allows reading/writing registers of the
>>> AB8500 PMIC. The driver directly accesses registers from the PRCMU
>>> parent device (represented by syscon in U-Boot). Abstracting it
>>> further (e.g. with the i2c uclass) would not provide any advantage
>>> because the PRCMU I2C bus is always just connected to AB8500 and
>>> vice-versa.
>>>
>>> The ab8500.h header is mostly taken as-is from Linux (with some
>>> minor adjustments) to allow using similar code in both Linux and
>>> U-Boot.
>>>
>>> Cc: Linus Walleij <linus.walleij@linaro.org>
>>> Signed-off-by: Stephan Gerhold <stephan@gerhold.net>
>>> ---
>>>
>>>  drivers/power/pmic/Kconfig  |  10 ++
>>>  drivers/power/pmic/Makefile |   1 +
>>>  drivers/power/pmic/ab8500.c | 258 ++++++++++++++++++++++++++++++++++++
>>>  include/power/ab8500.h      | 125 +++++++++++++++++
>>>  4 files changed, 394 insertions(+)
>>>  create mode 100644 drivers/power/pmic/ab8500.c
>>>  create mode 100644 include/power/ab8500.h
>>>
>>> diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig
>>> index 583fd3ddcd..fd6648b313 100644
>>> --- a/drivers/power/pmic/Kconfig
>>> +++ b/drivers/power/pmic/Kconfig
>>> @@ -31,6 +31,16 @@ config SPL_PMIC_CHILDREN
>>>  	to call your regulator code (e.g. see rk8xx.c for direct functions
>>>  	for use in SPL).
>>>  
>>> +config PMIC_AB8500
>>> +	bool "Enable driver for ST-Ericsson AB8500 PMIC via PRCMU"
>>> +	depends on DM_PMIC
>>> +	select REGMAP
>>> +	select SYSCON
>>> +	help
>>> +	  Enable support for the ST-Ericsson AB8500 (Analog Baseband) PMIC.
>>> +	  It connects with the ST-Ericsson DB8500 SoC via an I2C bus managed by
>>> +	  the power/reset/clock management unit (PRCMU) firmware.
>>> +
>>>  config PMIC_ACT8846
>>>  	bool "Enable support for the active-semi 8846 PMIC"
>>>  	depends on DM_PMIC && DM_I2C
>>> diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile
>>> index 89099fde57..5d1a97e5f6 100644
>>> --- a/drivers/power/pmic/Makefile
>>> +++ b/drivers/power/pmic/Makefile
>>> @@ -15,6 +15,7 @@ obj-$(CONFIG_$(SPL_)DM_PMIC_PFUZE100) += pfuze100.o
>>>  obj-$(CONFIG_$(SPL_)DM_PMIC_PCA9450) += pca9450.o
>>>  obj-$(CONFIG_PMIC_S2MPS11) += s2mps11.o
>>>  obj-$(CONFIG_DM_PMIC_SANDBOX) += sandbox.o i2c_pmic_emul.o
>>> +obj-$(CONFIG_PMIC_AB8500) += ab8500.o
>>>  obj-$(CONFIG_PMIC_ACT8846) += act8846.o
>>>  obj-$(CONFIG_PMIC_AS3722) += as3722.o as3722_gpio.o
>>>  obj-$(CONFIG_PMIC_MAX8997) += max8997.o
>>> diff --git a/drivers/power/pmic/ab8500.c b/drivers/power/pmic/ab8500.c
>>> new file mode 100644
>>> index 0000000000..a87a3b497c
>>> --- /dev/null
>>> +++ b/drivers/power/pmic/ab8500.c
>>> @@ -0,0 +1,258 @@
>>> +// SPDX-License-Identifier: GPL-2.0+
>>> +/*
>>> + * Copyright (C) 2019 Stephan Gerhold
>>> + *
>>> + * Adapted from old U-Boot and Linux kernel implementation:
>>> + * Copyright (C) STMicroelectronics 2009
>>> + * Copyright (C) ST-Ericsson SA 2010
>>> + */
>>> +
>>> +#include <common.h>
>>> +#include <dm.h>
>>> +#include <regmap.h>
>>> +#include <syscon.h>
>>> +#include <linux/bitops.h>
>>> +#include <linux/err.h>
>>> +#include <power/ab8500.h>
>>> +#include <power/pmic.h>
>>> +
>>> +/* CPU mailbox registers */
>>> +#define PRCM_MBOX_CPU_VAL		0x0fc
>>> +#define PRCM_MBOX_CPU_SET		0x100
>>> +#define PRCM_MBOX_CPU_CLR		0x104
>>> +
>>> +#define PRCM_ARM_IT1_CLR		0x48C
>>> +#define PRCM_ARM_IT1_VAL		0x494
>>> +
>>> +#define PRCM_TCDM_RANGE			2
>>> +#define PRCM_REQ_MB5			0xE44
>>> +#define PRCM_ACK_MB5			0xDF4
>>> +#define _PRCM_MBOX_HEADER		0xFE8
>>> +#define PRCM_MBOX_HEADER_REQ_MB5	(_PRCM_MBOX_HEADER + 0x5)
>>> +#define PRCMU_I2C_MBOX_BIT		BIT(5)
>>> +
>>> +/* Mailbox 5 Requests */
>>> +#define PRCM_REQ_MB5_I2C_SLAVE_OP	(PRCM_REQ_MB5 + 0x0)
>>> +#define PRCM_REQ_MB5_I2C_HW_BITS	(PRCM_REQ_MB5 + 0x1)
>>> +#define PRCM_REQ_MB5_I2C_REG		(PRCM_REQ_MB5 + 0x2)
>>> +#define PRCM_REQ_MB5_I2C_VAL		(PRCM_REQ_MB5 + 0x3)
>>> +#define PRCMU_I2C(bank)			(((bank) << 1) | BIT(6))
>>> +#define PRCMU_I2C_WRITE			0
>>> +#define PRCMU_I2C_READ			1
>>> +#define PRCMU_I2C_STOP_EN		BIT(3)
>>> +
>>> +/* Mailbox 5 ACKs */
>>> +#define PRCM_ACK_MB5_I2C_STATUS		(PRCM_ACK_MB5 + 0x1)
>>> +#define PRCM_ACK_MB5_I2C_VAL		(PRCM_ACK_MB5 + 0x3)
>>> +#define PRCMU_I2C_WR_OK			0x1
>>> +#define PRCMU_I2C_RD_OK			0x2
>>> +
>>> +/* AB8500 version registers */
>>> +#define AB8500_MISC_REV_REG		AB8500_MISC(0x80)
>>> +#define AB8500_MISC_IC_NAME_REG		AB8500_MISC(0x82)
>>> +
>>> +struct ab8500_priv {
>>> +	struct ab8500 ab8500;
>>> +	struct regmap *regmap;
>>> +};
>>> +
>>> +static inline int prcmu_tcdm_readb(struct regmap *map, uint offset, u8 *valp)
>>> +{
>>> +	return regmap_raw_read_range(map, PRCM_TCDM_RANGE, offset,
>>> +				     valp, sizeof(*valp));
>>> +}
>>> +
>>> +static inline int prcmu_tcdm_writeb(struct regmap *map, uint offset, u8 val)
>>> +{
>>> +	return regmap_raw_write_range(map, PRCM_TCDM_RANGE, offset,
>>> +				      &val, sizeof(val));
>>> +}
>>> +
>>> +static int prcmu_wait_i2c_mbx_ready(struct ab8500_priv *priv)
>>> +{
>>> +	uint val;
>>> +	int ret;
>>> +
>>> +	ret = regmap_read(priv->regmap, PRCM_ARM_IT1_VAL, &val);
>>
>> Doesn't need to check about returned to error?
>>
>>> +	if (ret == 0 && val & PRCMU_I2C_MBOX_BIT) {
>>> +		printf("ab8500: warning: PRCMU i2c mailbox was not acked\n");
>>> +		/* clear mailbox 5 ack irq */
>>> +		regmap_write(priv->regmap, PRCM_ARM_IT1_CLR, PRCMU_I2C_MBOX_BIT);
>>
>> Not need to check the return value about regmap_write()?
>>
> 
> Good point, it's probably better to return in case of errors here.
> 
>>> [...]
>>> +
>>> +	/* clear mailbox 5 ack irq */
>>> +	regmap_write(priv->regmap, PRCM_ARM_IT1_CLR, PRCMU_I2C_MBOX_BIT);
>>
>> Ditto.
>>
> 
> But here it doesn't really make sense: The read/write is already done.
> Even if we don't manage to clear the IRQ the read/write will still have
> succeeded. I will add a comment to clarify this.
> 
>>> +
>>> +	if (status != expected_status) {
>>> +		/*
>>> +		 * AB8500 does not have the AB8500_MISC_IC_NAME_REG register,
>>> +		 * but we need to try reading it to detect AB8505.
>>> +		 * In case of an error, assume that we have AB8500.
>>> +		 */
>>> +		if (op == PRCMU_I2C_READ && bank_reg == AB8500_MISC_IC_NAME_REG) {
>>> +			*val = AB8500_VERSION_AB8500;
>>> +			return 0;
>>> +		}
>>> +
>>> +		printf("%s: return status %d\n", __func__, status);
>>> +		return -EIO;
>>> +	}
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static int ab8500_reg_count(struct udevice *dev)
>>> +{
>>> +	return AB8500_NUM_REGISTERS;
>>> +}
>>> +
>>> +static int ab8500_read(struct udevice *dev, uint reg, uint8_t *buf, int len)
>>> +{
>>> +	int ret;
>>> +
>>> +	if (len != 1)
>>> +		return -EINVAL;
>>> +
>>> +	*buf = 0;
>>> +	ret = ab8500_transfer(dev, reg, buf, PRCMU_I2C_READ, PRCMU_I2C_RD_OK);
>>> +	if (ret) {
>>> +		printf("%s failed: %d\n", __func__, ret);
>>> +		return ret;
>>> +	}
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static int ab8500_write(struct udevice *dev, uint reg, const uint8_t *buf, int len)
>>> +{
>>> +	int ret;
>>> +	u8 val;
>>> +
>>> +	if (len != 1)
>>> +		return -EINVAL;
>>> +
>>> +	val = *buf;
>>> +	ret = ab8500_transfer(dev, reg, &val, PRCMU_I2C_WRITE, PRCMU_I2C_WR_OK);
>>> +	if (ret) {
>>> +		printf("%s failed: %d\n", __func__, ret);
>>> +		return ret;
>>> +	}
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static struct dm_pmic_ops ab8500_ops = {
>>> +	.reg_count = ab8500_reg_count,
>>> +	.read = ab8500_read,
>>> +	.write = ab8500_write,
>>> +};
>>> +
>>> +static int ab8500_probe(struct udevice *dev)
>>> +{
>>> +	struct ab8500_priv *priv = dev_get_priv(dev);
>>> +	int ret;
>>> +
>>> +	/* get regmap from the PRCMU parent device (syscon in U-Boot) */
>>> +	priv->regmap = syscon_get_regmap(dev->parent);
>>> +	if (IS_ERR(priv->regmap))
>>> +		return PTR_ERR(priv->regmap);
>>> +
>>> +	ret = pmic_reg_read(dev, AB8500_MISC_IC_NAME_REG);
>>> +	if (ret < 0) {
>>> +		printf("ab8500: failed to read chip version: %d\n", ret);
>>> +		return ret;
>>> +	}
>>> +	priv->ab8500.version = ret;
>>> +
>>> +	ret = pmic_reg_read(dev, AB8500_MISC_REV_REG);
>>> +	if (ret < 0) {
>>> +		printf("ab8500: failed to read chip id: %d\n", ret);
>>> +		return ret;
>>> +	}
>>> +	priv->ab8500.chip_id = ret;
>>> +
>>> +	debug("ab8500: version: %#x, chip id: %#x\n",
>>> +	      priv->ab8500.version, priv->ab8500.chip_id);
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static const struct udevice_id ab8500_ids[] = {
>>> +	{ .compatible = "stericsson,ab8500" },
>>> +	{ }
>>> +};
>>> +
>>> +U_BOOT_DRIVER(pmic_ab8500) = {
>>> +	.name		= "pmic_ab8500",
>>> +	.id		= UCLASS_PMIC,
>>> +	.of_match	= ab8500_ids,
>>> +	.bind		= dm_scan_fdt_dev,
>>> +	.probe		= ab8500_probe,
>>> +	.ops		= &ab8500_ops,
>>> +	.priv_auto	= sizeof(struct ab8500_priv),
>>> +};
>>> diff --git a/include/power/ab8500.h b/include/power/ab8500.h
>>> new file mode 100644
>>> index 0000000000..157eb4a5b1
>>> --- /dev/null
>>> +++ b/include/power/ab8500.h
>>> @@ -0,0 +1,125 @@
>>> +/* SPDX-License-Identifier: GPL-2.0-only */
>>> +/*
>>> + * Based on include/linux/mfd/abx500/ab8500.h from Linux
>>> + * Copyright (C) ST-Ericsson SA 2010
>>> + * Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
>>> + */
>>> +
>>> +#ifndef _PMIC_AB8500_H_
>>> +#define _PMIC_AB8500_H_
>>> +
>>> +/*
>>> + * AB IC versions
>>> + *
>>> + * AB8500_VERSION_AB8500 should be 0xFF but will never be read as need a
>>> + * non-supported multi-byte I2C access via PRCMU. Set to 0x00 to ease the
>>> + * print of version string.
>>> + */
>>> +enum ab8500_version {
>>> +	AB8500_VERSION_AB8500 = 0x0,
>>> +	AB8500_VERSION_AB8505 = 0x1,
>>> +	AB8500_VERSION_AB9540 = 0x2,
>>> +	AB8500_VERSION_AB8540 = 0x4,
>>> +	AB8500_VERSION_UNDEFINED,
>>> +};
>>> +
>>> +/* AB8500 CIDs*/
>>> +#define AB8500_CUTEARLY	0x00
>>> +#define AB8500_CUT1P0	0x10
>>> +#define AB8500_CUT1P1	0x11
>>> +#define AB8500_CUT1P2	0x12 /* Only valid for AB8540 */
>>> +#define AB8500_CUT2P0	0x20
>>> +#define AB8500_CUT3P0	0x30
>>> +#define AB8500_CUT3P3	0x33
>>> +
>>> +/*
>>> + * AB8500 bank addresses
>>> + */
>>> +#define AB8500_BANK(bank, reg)		(((bank) << 8) | (reg))
>>> +#define AB8500_M_FSM_RANK(reg)		AB8500_BANK(0x0, reg)
>>> +#define AB8500_SYS_CTRL1_BLOCK(reg)	AB8500_BANK(0x1, reg)
>>> +#define AB8500_SYS_CTRL2_BLOCK(reg)	AB8500_BANK(0x2, reg)
>>> +#define AB8500_REGU_CTRL1(reg)		AB8500_BANK(0x3, reg)
>>> +#define AB8500_REGU_CTRL2(reg)		AB8500_BANK(0x4, reg)
>>> +#define AB8500_USB(reg)			AB8500_BANK(0x5, reg)
>>> +#define AB8500_TVOUT(reg)		AB8500_BANK(0x6, reg)
>>> +#define AB8500_DBI(reg)			AB8500_BANK(0x7, reg)
>>> +#define AB8500_ECI_AV_ACC(reg)		AB8500_BANK(0x8, reg)
>>> +#define AB8500_RESERVED(reg)		AB8500_BANK(0x9, reg)
>>> +#define AB8500_GPADC(reg)		AB8500_BANK(0xA, reg)
>>> +#define AB8500_CHARGER(reg)		AB8500_BANK(0xB, reg)
>>> +#define AB8500_GAS_GAUGE(reg)		AB8500_BANK(0xC, reg)
>>> +#define AB8500_AUDIO(reg)		AB8500_BANK(0xD, reg)
>>> +#define AB8500_INTERRUPT(reg)		AB8500_BANK(0xE, reg)
>>> +#define AB8500_RTC(reg)			AB8500_BANK(0xF, reg)
>>> +#define AB8500_GPIO(reg)		AB8500_BANK(0x10, reg)
>>> +#define AB8500_MISC(reg)		AB8500_BANK(0x10, reg)
>>> +#define AB8500_DEVELOPMENT(reg)		AB8500_BANK(0x11, reg)
>>> +#define AB8500_DEBUG(reg)		AB8500_BANK(0x12, reg)
>>> +#define AB8500_PROD_TEST(reg)		AB8500_BANK(0x13, reg)
>>> +#define AB8500_STE_TEST(reg)		AB8500_BANK(0x14, reg)
>>> +#define AB8500_OTP_EMUL(reg)		AB8500_BANK(0x15, reg)
>>> +
>>> +#define AB8500_NUM_BANKS		0x16
>>> +#define AB8500_NUM_REGISTERS		AB8500_BANK(AB8500_NUM_BANKS, 0)
>>> +
>>> +struct ab8500 {
>>> +	enum ab8500_version version;
>>> +	u8 chip_id;
>>> +};> +
>>
>> I have checked that below codes are existed in linux kernel. 
>> But I didn't find where the below codes is used in U-boot.
>> Will it be used in future? 
>>
> 
> At the moment I don't have any drivers myself that make use of this.
> However, it would certainly be needed if more advanced drivers for
> AB8500 are written. I don't know if this will happen anytime soon.
> 
> I can remove these if you would prefer to have them added once they are
> actually needed. What do you think?

If you want to maintain them, not need to remove them. :)

Best Regards,
Jaehoon Chung

> 
> Thanks!
> Stephan
> 
>>> +static inline int is_ab8500(struct ab8500 *ab)
>>> +{
>>> +	return ab->version == AB8500_VERSION_AB8500;
>>> +}
>>> +
>>> +static inline int is_ab8505(struct ab8500 *ab)
>>> +{
>>> +	return ab->version == AB8500_VERSION_AB8505;
>>> +}
>>> +
>>> +/* exclude also ab8505, ab9540... */
>>> +static inline int is_ab8500_1p0_or_earlier(struct ab8500 *ab)
>>> +{
>>> +	return (is_ab8500(ab) && (ab->chip_id <= AB8500_CUT1P0));
>>> +}
>>> +
>>> +/* exclude also ab8505, ab9540... */
>>> +static inline int is_ab8500_1p1_or_earlier(struct ab8500 *ab)
>>> +{
>>> +	return (is_ab8500(ab) && (ab->chip_id <= AB8500_CUT1P1));
>>> +}
>>> +
>>> +/* exclude also ab8505, ab9540... */
>>> +static inline int is_ab8500_2p0_or_earlier(struct ab8500 *ab)
>>> +{
>>> +	return (is_ab8500(ab) && (ab->chip_id <= AB8500_CUT2P0));
>>> +}
>>> +
>>> +static inline int is_ab8500_3p3_or_earlier(struct ab8500 *ab)
>>> +{
>>> +	return (is_ab8500(ab) && (ab->chip_id <= AB8500_CUT3P3));
>>> +}
>>> +
>>> +/* exclude also ab8505, ab9540... */
>>> +static inline int is_ab8500_2p0(struct ab8500 *ab)
>>> +{
>>> +	return (is_ab8500(ab) && (ab->chip_id == AB8500_CUT2P0));
>>> +}
>>> +
>>> +static inline int is_ab8505_1p0_or_earlier(struct ab8500 *ab)
>>> +{
>>> +	return (is_ab8505(ab) && (ab->chip_id <= AB8500_CUT1P0));
>>> +}
>>> +
>>> +static inline int is_ab8505_2p0(struct ab8500 *ab)
>>> +{
>>> +	return (is_ab8505(ab) && (ab->chip_id == AB8500_CUT2P0));
>>> +}
>>> +
>>> +static inline int is_ab8505_2p0_earlier(struct ab8500 *ab)
>>> +{
>>> +	return (is_ab8505(ab) && (ab->chip_id < AB8500_CUT2P0));
>>> +}
>>> +
>>> +#endif
>>>
>>
> 


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 1/3] power: pmic: Add driver for ST-Ericsson AB8500 via PRCMU
  2021-07-06 21:25       ` Jaehoon Chung
@ 2021-07-07 13:15         ` Stephan Gerhold
  0 siblings, 0 replies; 12+ messages in thread
From: Stephan Gerhold @ 2021-07-07 13:15 UTC (permalink / raw)
  To: Jaehoon Chung; +Cc: u-boot, Marek Vasut, Linus Walleij, Joe Hershberger

On Wed, Jul 07, 2021 at 06:25:37AM +0900, Jaehoon Chung wrote:
> On 7/6/21 5:52 PM, Stephan Gerhold wrote:
> > On Tue, Jul 06, 2021 at 10:08:03AM +0900, Jaehoon Chung wrote:
> >> On 7/6/21 1:28 AM, Stephan Gerhold wrote:
> >>> All devices based on ST-Ericsson Ux500 use a PMIC similar to AB8500
> >>> (Analog Baseband). There is AB8500, AB8505, AB9540 and AB8540
> >>> although in practice only AB8500 and AB8505 are relevant since the
> >>> platforms with AB9540 and AB8540 were cancelled and never used in
> >>> production.
> >>>
> >>> In general, the AB8500 PMIC uses I2C as control interface, where the
> >>> different register banks are represented as separate I2C devices.
> >>> However, in practice AB8500 is always connected to a special I2C bus
> >>> on the DB8500 SoC that is controlled by the power/reset/clock
> >>> management unit (PRCMU) firmware.
> >>>
> >>> Add a simple driver that allows reading/writing registers of the
> >>> AB8500 PMIC. The driver directly accesses registers from the PRCMU
> >>> parent device (represented by syscon in U-Boot). Abstracting it
> >>> further (e.g. with the i2c uclass) would not provide any advantage
> >>> because the PRCMU I2C bus is always just connected to AB8500 and
> >>> vice-versa.
> >>>
> >>> The ab8500.h header is mostly taken as-is from Linux (with some
> >>> minor adjustments) to allow using similar code in both Linux and
> >>> U-Boot.
> >>>
> >>> Cc: Linus Walleij <linus.walleij@linaro.org>
> >>> Signed-off-by: Stephan Gerhold <stephan@gerhold.net>
> >>> ---
> >>>
> >>>  drivers/power/pmic/Kconfig  |  10 ++
> >>>  drivers/power/pmic/Makefile |   1 +
> >>>  drivers/power/pmic/ab8500.c | 258 ++++++++++++++++++++++++++++++++++++
> >>>  include/power/ab8500.h      | 125 +++++++++++++++++
> >>>  4 files changed, 394 insertions(+)
> >>>  create mode 100644 drivers/power/pmic/ab8500.c
> >>>  create mode 100644 include/power/ab8500.h
> >>>
> >>> diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig
> >>> index 583fd3ddcd..fd6648b313 100644
> >>> --- a/drivers/power/pmic/Kconfig
> >>> +++ b/drivers/power/pmic/Kconfig
> >>> @@ -31,6 +31,16 @@ config SPL_PMIC_CHILDREN
> >>>  	to call your regulator code (e.g. see rk8xx.c for direct functions
> >>>  	for use in SPL).
> >>>  
> >>> +config PMIC_AB8500
> >>> +	bool "Enable driver for ST-Ericsson AB8500 PMIC via PRCMU"
> >>> +	depends on DM_PMIC
> >>> +	select REGMAP
> >>> +	select SYSCON
> >>> +	help
> >>> +	  Enable support for the ST-Ericsson AB8500 (Analog Baseband) PMIC.
> >>> +	  It connects with the ST-Ericsson DB8500 SoC via an I2C bus managed by
> >>> +	  the power/reset/clock management unit (PRCMU) firmware.
> >>> +
> >>>  config PMIC_ACT8846
> >>>  	bool "Enable support for the active-semi 8846 PMIC"
> >>>  	depends on DM_PMIC && DM_I2C
> >>> diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile
> >>> index 89099fde57..5d1a97e5f6 100644
> >>> --- a/drivers/power/pmic/Makefile
> >>> +++ b/drivers/power/pmic/Makefile
> >>> @@ -15,6 +15,7 @@ obj-$(CONFIG_$(SPL_)DM_PMIC_PFUZE100) += pfuze100.o
> >>>  obj-$(CONFIG_$(SPL_)DM_PMIC_PCA9450) += pca9450.o
> >>>  obj-$(CONFIG_PMIC_S2MPS11) += s2mps11.o
> >>>  obj-$(CONFIG_DM_PMIC_SANDBOX) += sandbox.o i2c_pmic_emul.o
> >>> +obj-$(CONFIG_PMIC_AB8500) += ab8500.o
> >>>  obj-$(CONFIG_PMIC_ACT8846) += act8846.o
> >>>  obj-$(CONFIG_PMIC_AS3722) += as3722.o as3722_gpio.o
> >>>  obj-$(CONFIG_PMIC_MAX8997) += max8997.o
> >>> diff --git a/drivers/power/pmic/ab8500.c b/drivers/power/pmic/ab8500.c
> >>> new file mode 100644
> >>> index 0000000000..a87a3b497c
> >>> --- /dev/null
> >>> +++ b/drivers/power/pmic/ab8500.c
> >>> @@ -0,0 +1,258 @@
> >>> +// SPDX-License-Identifier: GPL-2.0+
> >>> +/*
> >>> + * Copyright (C) 2019 Stephan Gerhold
> >>> + *
> >>> + * Adapted from old U-Boot and Linux kernel implementation:
> >>> + * Copyright (C) STMicroelectronics 2009
> >>> + * Copyright (C) ST-Ericsson SA 2010
> >>> + */
> >>> +
> >>> +#include <common.h>
> >>> +#include <dm.h>
> >>> +#include <regmap.h>
> >>> +#include <syscon.h>
> >>> +#include <linux/bitops.h>
> >>> +#include <linux/err.h>
> >>> +#include <power/ab8500.h>
> >>> +#include <power/pmic.h>
> >>> +
> >>> +/* CPU mailbox registers */
> >>> +#define PRCM_MBOX_CPU_VAL		0x0fc
> >>> +#define PRCM_MBOX_CPU_SET		0x100
> >>> +#define PRCM_MBOX_CPU_CLR		0x104
> >>> +
> >>> +#define PRCM_ARM_IT1_CLR		0x48C
> >>> +#define PRCM_ARM_IT1_VAL		0x494
> >>> +
> >>> +#define PRCM_TCDM_RANGE			2
> >>> +#define PRCM_REQ_MB5			0xE44
> >>> +#define PRCM_ACK_MB5			0xDF4
> >>> +#define _PRCM_MBOX_HEADER		0xFE8
> >>> +#define PRCM_MBOX_HEADER_REQ_MB5	(_PRCM_MBOX_HEADER + 0x5)
> >>> +#define PRCMU_I2C_MBOX_BIT		BIT(5)
> >>> +
> >>> +/* Mailbox 5 Requests */
> >>> +#define PRCM_REQ_MB5_I2C_SLAVE_OP	(PRCM_REQ_MB5 + 0x0)
> >>> +#define PRCM_REQ_MB5_I2C_HW_BITS	(PRCM_REQ_MB5 + 0x1)
> >>> +#define PRCM_REQ_MB5_I2C_REG		(PRCM_REQ_MB5 + 0x2)
> >>> +#define PRCM_REQ_MB5_I2C_VAL		(PRCM_REQ_MB5 + 0x3)
> >>> +#define PRCMU_I2C(bank)			(((bank) << 1) | BIT(6))
> >>> +#define PRCMU_I2C_WRITE			0
> >>> +#define PRCMU_I2C_READ			1
> >>> +#define PRCMU_I2C_STOP_EN		BIT(3)
> >>> +
> >>> +/* Mailbox 5 ACKs */
> >>> +#define PRCM_ACK_MB5_I2C_STATUS		(PRCM_ACK_MB5 + 0x1)
> >>> +#define PRCM_ACK_MB5_I2C_VAL		(PRCM_ACK_MB5 + 0x3)
> >>> +#define PRCMU_I2C_WR_OK			0x1
> >>> +#define PRCMU_I2C_RD_OK			0x2
> >>> +
> >>> +/* AB8500 version registers */
> >>> +#define AB8500_MISC_REV_REG		AB8500_MISC(0x80)
> >>> +#define AB8500_MISC_IC_NAME_REG		AB8500_MISC(0x82)
> >>> +
> >>> +struct ab8500_priv {
> >>> +	struct ab8500 ab8500;
> >>> +	struct regmap *regmap;
> >>> +};
> >>> +
> >>> +static inline int prcmu_tcdm_readb(struct regmap *map, uint offset, u8 *valp)
> >>> +{
> >>> +	return regmap_raw_read_range(map, PRCM_TCDM_RANGE, offset,
> >>> +				     valp, sizeof(*valp));
> >>> +}
> >>> +
> >>> +static inline int prcmu_tcdm_writeb(struct regmap *map, uint offset, u8 val)
> >>> +{
> >>> +	return regmap_raw_write_range(map, PRCM_TCDM_RANGE, offset,
> >>> +				      &val, sizeof(val));
> >>> +}
> >>> +
> >>> +static int prcmu_wait_i2c_mbx_ready(struct ab8500_priv *priv)
> >>> +{
> >>> +	uint val;
> >>> +	int ret;
> >>> +
> >>> +	ret = regmap_read(priv->regmap, PRCM_ARM_IT1_VAL, &val);
> >>
> >> Doesn't need to check about returned to error?
> >>
> >>> +	if (ret == 0 && val & PRCMU_I2C_MBOX_BIT) {
> >>> +		printf("ab8500: warning: PRCMU i2c mailbox was not acked\n");
> >>> +		/* clear mailbox 5 ack irq */
> >>> +		regmap_write(priv->regmap, PRCM_ARM_IT1_CLR, PRCMU_I2C_MBOX_BIT);
> >>
> >> Not need to check the return value about regmap_write()?
> >>
> > 
> > Good point, it's probably better to return in case of errors here.
> > 
> >>> [...]
> >>> +
> >>> +	/* clear mailbox 5 ack irq */
> >>> +	regmap_write(priv->regmap, PRCM_ARM_IT1_CLR, PRCMU_I2C_MBOX_BIT);
> >>
> >> Ditto.
> >>
> > 
> > But here it doesn't really make sense: The read/write is already done.
> > Even if we don't manage to clear the IRQ the read/write will still have
> > succeeded. I will add a comment to clarify this.
> > 
> >>> +
> >>> +	if (status != expected_status) {
> >>> +		/*
> >>> +		 * AB8500 does not have the AB8500_MISC_IC_NAME_REG register,
> >>> +		 * but we need to try reading it to detect AB8505.
> >>> +		 * In case of an error, assume that we have AB8500.
> >>> +		 */
> >>> +		if (op == PRCMU_I2C_READ && bank_reg == AB8500_MISC_IC_NAME_REG) {
> >>> +			*val = AB8500_VERSION_AB8500;
> >>> +			return 0;
> >>> +		}
> >>> +
> >>> +		printf("%s: return status %d\n", __func__, status);
> >>> +		return -EIO;
> >>> +	}
> >>> +
> >>> +	return 0;
> >>> +}
> >>> +
> >>> +static int ab8500_reg_count(struct udevice *dev)
> >>> +{
> >>> +	return AB8500_NUM_REGISTERS;
> >>> +}
> >>> +
> >>> +static int ab8500_read(struct udevice *dev, uint reg, uint8_t *buf, int len)
> >>> +{
> >>> +	int ret;
> >>> +
> >>> +	if (len != 1)
> >>> +		return -EINVAL;
> >>> +
> >>> +	*buf = 0;
> >>> +	ret = ab8500_transfer(dev, reg, buf, PRCMU_I2C_READ, PRCMU_I2C_RD_OK);
> >>> +	if (ret) {
> >>> +		printf("%s failed: %d\n", __func__, ret);
> >>> +		return ret;
> >>> +	}
> >>> +
> >>> +	return 0;
> >>> +}
> >>> +
> >>> +static int ab8500_write(struct udevice *dev, uint reg, const uint8_t *buf, int len)
> >>> +{
> >>> +	int ret;
> >>> +	u8 val;
> >>> +
> >>> +	if (len != 1)
> >>> +		return -EINVAL;
> >>> +
> >>> +	val = *buf;
> >>> +	ret = ab8500_transfer(dev, reg, &val, PRCMU_I2C_WRITE, PRCMU_I2C_WR_OK);
> >>> +	if (ret) {
> >>> +		printf("%s failed: %d\n", __func__, ret);
> >>> +		return ret;
> >>> +	}
> >>> +
> >>> +	return 0;
> >>> +}
> >>> +
> >>> +static struct dm_pmic_ops ab8500_ops = {
> >>> +	.reg_count = ab8500_reg_count,
> >>> +	.read = ab8500_read,
> >>> +	.write = ab8500_write,
> >>> +};
> >>> +
> >>> +static int ab8500_probe(struct udevice *dev)
> >>> +{
> >>> +	struct ab8500_priv *priv = dev_get_priv(dev);
> >>> +	int ret;
> >>> +
> >>> +	/* get regmap from the PRCMU parent device (syscon in U-Boot) */
> >>> +	priv->regmap = syscon_get_regmap(dev->parent);
> >>> +	if (IS_ERR(priv->regmap))
> >>> +		return PTR_ERR(priv->regmap);
> >>> +
> >>> +	ret = pmic_reg_read(dev, AB8500_MISC_IC_NAME_REG);
> >>> +	if (ret < 0) {
> >>> +		printf("ab8500: failed to read chip version: %d\n", ret);
> >>> +		return ret;
> >>> +	}
> >>> +	priv->ab8500.version = ret;
> >>> +
> >>> +	ret = pmic_reg_read(dev, AB8500_MISC_REV_REG);
> >>> +	if (ret < 0) {
> >>> +		printf("ab8500: failed to read chip id: %d\n", ret);
> >>> +		return ret;
> >>> +	}
> >>> +	priv->ab8500.chip_id = ret;
> >>> +
> >>> +	debug("ab8500: version: %#x, chip id: %#x\n",
> >>> +	      priv->ab8500.version, priv->ab8500.chip_id);
> >>> +
> >>> +	return 0;
> >>> +}
> >>> +
> >>> +static const struct udevice_id ab8500_ids[] = {
> >>> +	{ .compatible = "stericsson,ab8500" },
> >>> +	{ }
> >>> +};
> >>> +
> >>> +U_BOOT_DRIVER(pmic_ab8500) = {
> >>> +	.name		= "pmic_ab8500",
> >>> +	.id		= UCLASS_PMIC,
> >>> +	.of_match	= ab8500_ids,
> >>> +	.bind		= dm_scan_fdt_dev,
> >>> +	.probe		= ab8500_probe,
> >>> +	.ops		= &ab8500_ops,
> >>> +	.priv_auto	= sizeof(struct ab8500_priv),
> >>> +};
> >>> diff --git a/include/power/ab8500.h b/include/power/ab8500.h
> >>> new file mode 100644
> >>> index 0000000000..157eb4a5b1
> >>> --- /dev/null
> >>> +++ b/include/power/ab8500.h
> >>> @@ -0,0 +1,125 @@
> >>> +/* SPDX-License-Identifier: GPL-2.0-only */
> >>> +/*
> >>> + * Based on include/linux/mfd/abx500/ab8500.h from Linux
> >>> + * Copyright (C) ST-Ericsson SA 2010
> >>> + * Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
> >>> + */
> >>> +
> >>> +#ifndef _PMIC_AB8500_H_
> >>> +#define _PMIC_AB8500_H_
> >>> +
> >>> +/*
> >>> + * AB IC versions
> >>> + *
> >>> + * AB8500_VERSION_AB8500 should be 0xFF but will never be read as need a
> >>> + * non-supported multi-byte I2C access via PRCMU. Set to 0x00 to ease the
> >>> + * print of version string.
> >>> + */
> >>> +enum ab8500_version {
> >>> +	AB8500_VERSION_AB8500 = 0x0,
> >>> +	AB8500_VERSION_AB8505 = 0x1,
> >>> +	AB8500_VERSION_AB9540 = 0x2,
> >>> +	AB8500_VERSION_AB8540 = 0x4,
> >>> +	AB8500_VERSION_UNDEFINED,
> >>> +};
> >>> +
> >>> +/* AB8500 CIDs*/
> >>> +#define AB8500_CUTEARLY	0x00
> >>> +#define AB8500_CUT1P0	0x10
> >>> +#define AB8500_CUT1P1	0x11
> >>> +#define AB8500_CUT1P2	0x12 /* Only valid for AB8540 */
> >>> +#define AB8500_CUT2P0	0x20
> >>> +#define AB8500_CUT3P0	0x30
> >>> +#define AB8500_CUT3P3	0x33
> >>> +
> >>> +/*
> >>> + * AB8500 bank addresses
> >>> + */
> >>> +#define AB8500_BANK(bank, reg)		(((bank) << 8) | (reg))
> >>> +#define AB8500_M_FSM_RANK(reg)		AB8500_BANK(0x0, reg)
> >>> +#define AB8500_SYS_CTRL1_BLOCK(reg)	AB8500_BANK(0x1, reg)
> >>> +#define AB8500_SYS_CTRL2_BLOCK(reg)	AB8500_BANK(0x2, reg)
> >>> +#define AB8500_REGU_CTRL1(reg)		AB8500_BANK(0x3, reg)
> >>> +#define AB8500_REGU_CTRL2(reg)		AB8500_BANK(0x4, reg)
> >>> +#define AB8500_USB(reg)			AB8500_BANK(0x5, reg)
> >>> +#define AB8500_TVOUT(reg)		AB8500_BANK(0x6, reg)
> >>> +#define AB8500_DBI(reg)			AB8500_BANK(0x7, reg)
> >>> +#define AB8500_ECI_AV_ACC(reg)		AB8500_BANK(0x8, reg)
> >>> +#define AB8500_RESERVED(reg)		AB8500_BANK(0x9, reg)
> >>> +#define AB8500_GPADC(reg)		AB8500_BANK(0xA, reg)
> >>> +#define AB8500_CHARGER(reg)		AB8500_BANK(0xB, reg)
> >>> +#define AB8500_GAS_GAUGE(reg)		AB8500_BANK(0xC, reg)
> >>> +#define AB8500_AUDIO(reg)		AB8500_BANK(0xD, reg)
> >>> +#define AB8500_INTERRUPT(reg)		AB8500_BANK(0xE, reg)
> >>> +#define AB8500_RTC(reg)			AB8500_BANK(0xF, reg)
> >>> +#define AB8500_GPIO(reg)		AB8500_BANK(0x10, reg)
> >>> +#define AB8500_MISC(reg)		AB8500_BANK(0x10, reg)
> >>> +#define AB8500_DEVELOPMENT(reg)		AB8500_BANK(0x11, reg)
> >>> +#define AB8500_DEBUG(reg)		AB8500_BANK(0x12, reg)
> >>> +#define AB8500_PROD_TEST(reg)		AB8500_BANK(0x13, reg)
> >>> +#define AB8500_STE_TEST(reg)		AB8500_BANK(0x14, reg)
> >>> +#define AB8500_OTP_EMUL(reg)		AB8500_BANK(0x15, reg)
> >>> +
> >>> +#define AB8500_NUM_BANKS		0x16
> >>> +#define AB8500_NUM_REGISTERS		AB8500_BANK(AB8500_NUM_BANKS, 0)
> >>> +
> >>> +struct ab8500 {
> >>> +	enum ab8500_version version;
> >>> +	u8 chip_id;
> >>> +};> +
> >>
> >> I have checked that below codes are existed in linux kernel. 
> >> But I didn't find where the below codes is used in U-boot.
> >> Will it be used in future? 
> >>
> > 
> > At the moment I don't have any drivers myself that make use of this.
> > However, it would certainly be needed if more advanced drivers for
> > AB8500 are written. I don't know if this will happen anytime soon.
> > 
> > I can remove these if you would prefer to have them added once they are
> > actually needed. What do you think?
> 
> If you want to maintain them, not need to remove them. :)
> 

Yes, I think they are fine. Will send a v2 with the other suggested
changes soon.

Thanks!
Stephan

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 2/3] phy: Add driver for ST-Ericsson AB8500 USB PHY
  2021-07-05 16:28 ` [PATCH 2/3] phy: Add driver for ST-Ericsson AB8500 USB PHY Stephan Gerhold
  2021-07-06  1:10   ` Jaehoon Chung
@ 2021-07-07 23:46   ` Linus Walleij
  1 sibling, 0 replies; 12+ messages in thread
From: Linus Walleij @ 2021-07-07 23:46 UTC (permalink / raw)
  To: Stephan Gerhold
  Cc: U-Boot Mailing List, Marek Vasut, Joe Hershberger, Jaehoon Chung

On Mon, Jul 5, 2021 at 6:28 PM Stephan Gerhold <stephan@gerhold.net> wrote:

> The AB8500 PMIC contains an USB PHY that needs to be set up in
> device or host mode to make USB work properly. Add a simple driver
> for the generic PHY uclass that allows enabling it.
>
> The if (CONFIG_IS_ENABLED(USB_MUSB_HOST)) might be a bit strange.
> The USB PHY must be configured in either host or device mode and
> somehow the USB PHY driver must be made aware of the mode.
>
> Actually, the MUSB driver used together with this PHY does not
> support dynamic selection of host/device mode in U-Boot at the moment.
> Therefore, one very simple approach that works fine is to select
> the mode to configure at compile time. When the MUSB driver is
> configured in host mode the PHY is configured in host mode, and
> similarly when the MUSB driver is configured in device/gadget mode.
>
> Cc: Linus Walleij <linus.walleij@linaro.org>
> Signed-off-by: Stephan Gerhold <stephan@gerhold.net>

FWIW:
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 3/3] usb: musb-new: Add glue driver for ST-Ericsson Ux500
  2021-07-05 16:28 ` [PATCH 3/3] usb: musb-new: Add glue driver for ST-Ericsson Ux500 Stephan Gerhold
@ 2021-07-07 23:47   ` Linus Walleij
  0 siblings, 0 replies; 12+ messages in thread
From: Linus Walleij @ 2021-07-07 23:47 UTC (permalink / raw)
  To: Stephan Gerhold
  Cc: U-Boot Mailing List, Marek Vasut, Joe Hershberger, Jaehoon Chung

On Mon, Jul 5, 2021 at 6:28 PM Stephan Gerhold <stephan@gerhold.net> wrote:

> The ST-Ericsson DB8500 SoC contains a MUSB OTG controller which
> supports both host and gadget mode. For some reason there is
> nothing special about it - add a simple glue driver for Ux500
> that literally just sets up MUSB together with a generic PHY.
> There are no SoC-specific registers etc needed to make USB work.
>
> The new Ux500 glue driver is only tested to work with DM_USB
> and DM_USB_GADGET. Both host and gadget mode work fine on
> the u8500 "stemmy" board that is already present in U-Boot.
>
> Cc: Linus Walleij <linus.walleij@linaro.org>
> Signed-off-by: Stephan Gerhold <stephan@gerhold.net>

FWIW:
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2021-07-07 23:48 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-07-05 16:28 [PATCH 0/3] Add support for USB on ST-Ericsson Ux500 Stephan Gerhold
2021-07-05 16:28 ` [PATCH 1/3] power: pmic: Add driver for ST-Ericsson AB8500 via PRCMU Stephan Gerhold
2021-07-06  1:08   ` Jaehoon Chung
2021-07-06  8:52     ` Stephan Gerhold
2021-07-06 21:25       ` Jaehoon Chung
2021-07-07 13:15         ` Stephan Gerhold
2021-07-05 16:28 ` [PATCH 2/3] phy: Add driver for ST-Ericsson AB8500 USB PHY Stephan Gerhold
2021-07-06  1:10   ` Jaehoon Chung
2021-07-06  9:01     ` Stephan Gerhold
2021-07-07 23:46   ` Linus Walleij
2021-07-05 16:28 ` [PATCH 3/3] usb: musb-new: Add glue driver for ST-Ericsson Ux500 Stephan Gerhold
2021-07-07 23:47   ` Linus Walleij

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.