- UFS support and GPIO clock driver
This commit is contained in:
Tom Rini 2023-09-09 10:12:40 -04:00
commit d8d1fd0e89
7 changed files with 513 additions and 0 deletions

View file

@ -31,7 +31,9 @@ CONFIG_CMD_BOOTZ=y
CONFIG_CMD_GPIO=y CONFIG_CMD_GPIO=y
CONFIG_CMD_I2C=y CONFIG_CMD_I2C=y
CONFIG_CMD_MMC=y CONFIG_CMD_MMC=y
CONFIG_CMD_PART=y
CONFIG_CMD_SPI=y CONFIG_CMD_SPI=y
CONFIG_CMD_UFS=y
CONFIG_CMD_DHCP=y CONFIG_CMD_DHCP=y
CONFIG_CMD_MII=y CONFIG_CMD_MII=y
CONFIG_CMD_PING=y CONFIG_CMD_PING=y
@ -46,9 +48,13 @@ CONFIG_SYS_RELOC_GD_ENV_ADDR=y
CONFIG_VERSION_VARIABLE=y CONFIG_VERSION_VARIABLE=y
CONFIG_REGMAP=y CONFIG_REGMAP=y
CONFIG_SYSCON=y CONFIG_SYSCON=y
CONFIG_LBA48=y
CONFIG_SYS_64BIT_LBA=y
CONFIG_CLK=y CONFIG_CLK=y
CONFIG_CLK_GPIO=y
CONFIG_CLK_RENESAS=y CONFIG_CLK_RENESAS=y
CONFIG_RCAR_GPIO=y CONFIG_RCAR_GPIO=y
CONFIG_DM_PCA953X=y
CONFIG_DM_I2C=y CONFIG_DM_I2C=y
CONFIG_SYS_I2C_RCAR_I2C=y CONFIG_SYS_I2C_RCAR_I2C=y
CONFIG_MMC_IO_VOLTAGE=y CONFIG_MMC_IO_VOLTAGE=y
@ -67,8 +73,13 @@ CONFIG_PHY_R8A779F0_ETHERNET_SERDES=y
CONFIG_DM_REGULATOR=y CONFIG_DM_REGULATOR=y
CONFIG_DM_REGULATOR_FIXED=y CONFIG_DM_REGULATOR_FIXED=y
CONFIG_DM_REGULATOR_GPIO=y CONFIG_DM_REGULATOR_GPIO=y
CONFIG_SCSI=y
CONFIG_DM_SCSI=y
CONFIG_BAUDRATE=1843200 CONFIG_BAUDRATE=1843200
CONFIG_SCIF_CONSOLE=y CONFIG_SCIF_CONSOLE=y
CONFIG_SPI=y CONFIG_SPI=y
CONFIG_DM_SPI=y CONFIG_DM_SPI=y
CONFIG_RENESAS_RPC_SPI=y CONFIG_RENESAS_RPC_SPI=y
CONFIG_UFS=y
CONFIG_UFS_RENESAS=y
CONFIG_FS_FAT_MAX_CLUSTSIZE=131072

View file

@ -83,6 +83,19 @@ config CLK_COMPOSITE_CCF
Enable this option if you want to (re-)use the Linux kernel's Common Enable this option if you want to (re-)use the Linux kernel's Common
Clock Framework [CCF] composite code in U-Boot's clock driver. Clock Framework [CCF] composite code in U-Boot's clock driver.
config CLK_GPIO
bool "GPIO-controlled clock gate driver"
depends on CLK
help
Enable this option to add GPIO-controlled clock gate driver.
config SPL_CLK_GPIO
bool "GPIO-controlled clock gate driver in SPL"
depends on SPL_CLK
help
Enable this option to add GPIO-controlled clock gate driver
in U-Boot SPL.
config CLK_BCM6345 config CLK_BCM6345
bool "Clock controller driver for BCM6345" bool "Clock controller driver for BCM6345"
depends on CLK && ARCH_BMIPS depends on CLK && ARCH_BMIPS

View file

@ -10,6 +10,7 @@ obj-$(CONFIG_$(SPL_TPL_)CLK) += clk_fixed_factor.o
obj-$(CONFIG_$(SPL_TPL_)CLK_CCF) += clk.o clk-divider.o clk-mux.o clk-gate.o obj-$(CONFIG_$(SPL_TPL_)CLK_CCF) += clk.o clk-divider.o clk-mux.o clk-gate.o
obj-$(CONFIG_$(SPL_TPL_)CLK_CCF) += clk-fixed-factor.o obj-$(CONFIG_$(SPL_TPL_)CLK_CCF) += clk-fixed-factor.o
obj-$(CONFIG_$(SPL_TPL_)CLK_COMPOSITE_CCF) += clk-composite.o obj-$(CONFIG_$(SPL_TPL_)CLK_COMPOSITE_CCF) += clk-composite.o
obj-$(CONFIG_$(SPL_TPL_)CLK_GPIO) += clk-gpio.o
obj-y += analogbits/ obj-y += analogbits/
obj-y += imx/ obj-y += imx/

66
drivers/clk/clk-gpio.c Normal file
View file

@ -0,0 +1,66 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2023 Marek Vasut <marek.vasut+renesas@mailbox.org>
*/
#include <asm/gpio.h>
#include <common.h>
#include <clk-uclass.h>
#include <dm.h>
struct clk_gpio_priv {
struct gpio_desc enable;
};
static int clk_gpio_enable(struct clk *clk)
{
struct clk_gpio_priv *priv = dev_get_priv(clk->dev);
dm_gpio_set_value(&priv->enable, 1);
return 0;
}
static int clk_gpio_disable(struct clk *clk)
{
struct clk_gpio_priv *priv = dev_get_priv(clk->dev);
dm_gpio_set_value(&priv->enable, 0);
return 0;
}
const struct clk_ops clk_gpio_ops = {
.enable = clk_gpio_enable,
.disable = clk_gpio_disable,
};
static int clk_gpio_probe(struct udevice *dev)
{
struct clk_gpio_priv *priv = dev_get_priv(dev);
return gpio_request_by_name(dev, "enable-gpios", 0,
&priv->enable, GPIOD_IS_OUT);
}
/*
* When implementing clk-mux-clock, use gpio_request_list_by_name
* and implement get_rate/set_rate/set_parent ops. This should be
* in a separate driver and with separate Kconfig option to enable
* that driver, since unlike Linux implementation, the U-Boot DM
* integration would be orthogonal to this driver.
*/
static const struct udevice_id clk_gpio_match[] = {
{ .compatible = "gpio-gate-clock" },
{ /* sentinel */ }
};
U_BOOT_DRIVER(gpio_gate_clock) = {
.name = "gpio_clock",
.id = UCLASS_CLK,
.of_match = clk_gpio_match,
.probe = clk_gpio_probe,
.priv_auto = sizeof(struct clk_gpio_priv),
.ops = &clk_gpio_ops,
.flags = DM_FLAG_PRE_RELOC,
};

View file

@ -21,4 +21,13 @@ config TI_J721E_UFS
This selects the glue layer driver for Cadence controller This selects the glue layer driver for Cadence controller
present on TI's J721E devices. present on TI's J721E devices.
config UFS_RENESAS
bool "Renesas specific hooks to UFS controller platform driver"
depends on UFS
select BOUNCE_BUFFER
help
This selects the Renesas specific additions to UFSHCD platform driver.
UFS host on Renesas needs some vendor specific configuration before
accessing the hardware.
endmenu endmenu

View file

@ -6,3 +6,4 @@
obj-$(CONFIG_UFS) += ufs.o ufs-uclass.o obj-$(CONFIG_UFS) += ufs.o ufs-uclass.o
obj-$(CONFIG_CADENCE_UFS) += cdns-platform.o obj-$(CONFIG_CADENCE_UFS) += cdns-platform.o
obj-$(CONFIG_TI_J721E_UFS) += ti-j721e-ufs.o obj-$(CONFIG_TI_J721E_UFS) += ti-j721e-ufs.o
obj-$(CONFIG_UFS_RENESAS) += ufs-renesas.o

412
drivers/ufs/ufs-renesas.c Normal file
View file

@ -0,0 +1,412 @@
// SPDX-License-Identifier: GPL-2.0 OR MIT
/*
* Renesas UFS host controller driver
*
* Copyright (C) 2022 Renesas Electronics Corporation
*/
#include <clk.h>
#include <dm.h>
#include <ufs.h>
#include <asm/io.h>
#include <dm/device_compat.h>
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/bug.h>
#include <linux/iopoll.h>
#include "ufs.h"
struct ufs_renesas_priv {
struct clk_bulk clks;
bool initialized; /* The hardware needs initialization once */
};
enum {
SET_PHY_INDEX_LO = 0,
SET_PHY_INDEX_HI,
TIMER_INDEX,
MAX_INDEX
};
enum ufs_renesas_init_param_mode {
MODE_RESTORE,
MODE_SET,
MODE_SAVE,
MODE_POLL,
MODE_WAIT,
MODE_WRITE,
};
#define PARAM_RESTORE(_reg, _index) \
{ .mode = MODE_RESTORE, .reg = _reg, .index = _index }
#define PARAM_SET(_index, _set) \
{ .mode = MODE_SET, .index = _index, .u.set = _set }
#define PARAM_SAVE(_reg, _mask, _index) \
{ .mode = MODE_SAVE, .reg = _reg, .mask = (u32)(_mask), \
.index = _index }
#define PARAM_POLL(_reg, _expected, _mask) \
{ .mode = MODE_POLL, .reg = _reg, .u.expected = _expected, \
.mask = (u32)(_mask) }
#define PARAM_WAIT(_delay_us) \
{ .mode = MODE_WAIT, .u.delay_us = _delay_us }
#define PARAM_WRITE(_reg, _val) \
{ .mode = MODE_WRITE, .reg = _reg, .u.val = _val }
#define PARAM_WRITE_D0_D4(_d0, _d4) \
PARAM_WRITE(0xd0, _d0), PARAM_WRITE(0xd4, _d4)
#define PARAM_WRITE_800_80C_POLL(_addr, _data_800) \
PARAM_WRITE_D0_D4(0x0000080c, 0x00000100), \
PARAM_WRITE_D0_D4(0x00000800, ((_data_800) << 16) | BIT(8) | (_addr)), \
PARAM_WRITE(0xd0, 0x0000080c), \
PARAM_POLL(0xd4, BIT(8), BIT(8))
#define PARAM_RESTORE_800_80C_POLL(_index) \
PARAM_WRITE_D0_D4(0x0000080c, 0x00000100), \
PARAM_WRITE(0xd0, 0x00000800), \
PARAM_RESTORE(0xd4, (_index)), \
PARAM_WRITE(0xd0, 0x0000080c), \
PARAM_POLL(0xd4, BIT(8), BIT(8))
#define PARAM_WRITE_804_80C_POLL(_addr, _data_804) \
PARAM_WRITE_D0_D4(0x0000080c, 0x00000100), \
PARAM_WRITE_D0_D4(0x00000804, ((_data_804) << 16) | BIT(8) | (_addr)), \
PARAM_WRITE(0xd0, 0x0000080c), \
PARAM_POLL(0xd4, BIT(8), BIT(8))
#define PARAM_WRITE_828_82C_POLL(_data_828) \
PARAM_WRITE_D0_D4(0x0000082c, 0x0f000000), \
PARAM_WRITE_D0_D4(0x00000828, _data_828), \
PARAM_WRITE(0xd0, 0x0000082c), \
PARAM_POLL(0xd4, _data_828, _data_828)
#define PARAM_WRITE_PHY(_addr16, _data16) \
PARAM_WRITE(0xf0, 1), \
PARAM_WRITE_800_80C_POLL(0x16, (_addr16) & 0xff), \
PARAM_WRITE_800_80C_POLL(0x17, ((_addr16) >> 8) & 0xff), \
PARAM_WRITE_800_80C_POLL(0x18, (_data16) & 0xff), \
PARAM_WRITE_800_80C_POLL(0x19, ((_data16) >> 8) & 0xff), \
PARAM_WRITE_800_80C_POLL(0x1c, 0x01), \
PARAM_WRITE_828_82C_POLL(0x0f000000), \
PARAM_WRITE(0xf0, 0)
#define PARAM_SET_PHY(_addr16, _data16) \
PARAM_WRITE(0xf0, 1), \
PARAM_WRITE_800_80C_POLL(0x16, (_addr16) & 0xff), \
PARAM_WRITE_800_80C_POLL(0x17, ((_addr16) >> 8) & 0xff), \
PARAM_WRITE_800_80C_POLL(0x1c, 0x01), \
PARAM_WRITE_828_82C_POLL(0x0f000000), \
PARAM_WRITE_804_80C_POLL(0x1a, 0), \
PARAM_WRITE(0xd0, 0x00000808), \
PARAM_SAVE(0xd4, 0xff, SET_PHY_INDEX_LO), \
PARAM_WRITE_804_80C_POLL(0x1b, 0), \
PARAM_WRITE(0xd0, 0x00000808), \
PARAM_SAVE(0xd4, 0xff, SET_PHY_INDEX_HI), \
PARAM_WRITE_828_82C_POLL(0x0f000000), \
PARAM_WRITE(0xf0, 0), \
PARAM_WRITE(0xf0, 1), \
PARAM_WRITE_800_80C_POLL(0x16, (_addr16) & 0xff), \
PARAM_WRITE_800_80C_POLL(0x17, ((_addr16) >> 8) & 0xff), \
PARAM_SET(SET_PHY_INDEX_LO, (((_data16) & 0xff) << 16) | BIT(8) | 0x18), \
PARAM_RESTORE_800_80C_POLL(SET_PHY_INDEX_LO), \
PARAM_SET(SET_PHY_INDEX_HI, ((((_data16) >> 8) & 0xff) << 16) | BIT(8) | 0x19), \
PARAM_RESTORE_800_80C_POLL(SET_PHY_INDEX_HI), \
PARAM_WRITE_800_80C_POLL(0x1c, 0x01), \
PARAM_WRITE_828_82C_POLL(0x0f000000), \
PARAM_WRITE(0xf0, 0)
#define PARAM_INDIRECT_WRITE(_gpio, _addr, _data_800) \
PARAM_WRITE(0xf0, _gpio), \
PARAM_WRITE_800_80C_POLL((_addr), _data_800), \
PARAM_WRITE_828_82C_POLL(0x0f000000), \
PARAM_WRITE(0xf0, 0)
#define PARAM_INDIRECT_POLL(_gpio, _addr, _expected, _mask) \
PARAM_WRITE(0xf0, _gpio), \
PARAM_WRITE_800_80C_POLL((_addr), 0), \
PARAM_WRITE(0xd0, 0x00000808), \
PARAM_POLL(0xd4, (_expected), (_mask)), \
PARAM_WRITE(0xf0, 0)
struct ufs_renesas_init_param {
enum ufs_renesas_init_param_mode mode;
u32 reg;
union {
u32 expected;
u32 delay_us;
u32 set;
u32 val;
} u;
u32 mask;
u32 index;
};
/* This setting is for SERIES B */
static const struct ufs_renesas_init_param ufs_param[] = {
PARAM_WRITE(0xc0, 0x49425308),
PARAM_WRITE_D0_D4(0x00000104, 0x00000002),
PARAM_WAIT(1),
PARAM_WRITE_D0_D4(0x00000828, 0x00000200),
PARAM_WAIT(1),
PARAM_WRITE_D0_D4(0x00000828, 0x00000000),
PARAM_WRITE_D0_D4(0x00000104, 0x00000001),
PARAM_WRITE_D0_D4(0x00000940, 0x00000001),
PARAM_WAIT(1),
PARAM_WRITE_D0_D4(0x00000940, 0x00000000),
PARAM_WRITE(0xc0, 0x49425308),
PARAM_WRITE(0xc0, 0x41584901),
PARAM_WRITE_D0_D4(0x0000080c, 0x00000100),
PARAM_WRITE_D0_D4(0x00000804, 0x00000000),
PARAM_WRITE(0xd0, 0x0000080c),
PARAM_POLL(0xd4, BIT(8), BIT(8)),
PARAM_WRITE(REG_CONTROLLER_ENABLE, 0x00000001),
PARAM_WRITE(0xd0, 0x00000804),
PARAM_POLL(0xd4, BIT(8) | BIT(6) | BIT(0), BIT(8) | BIT(6) | BIT(0)),
PARAM_WRITE(0xd0, 0x00000d00),
PARAM_SAVE(0xd4, 0x0000ffff, TIMER_INDEX),
PARAM_WRITE(0xd4, 0x00000000),
PARAM_WRITE_D0_D4(0x0000082c, 0x0f000000),
PARAM_WRITE_D0_D4(0x00000828, 0x08000000),
PARAM_WRITE(0xd0, 0x0000082c),
PARAM_POLL(0xd4, BIT(27), BIT(27)),
PARAM_WRITE(0xd0, 0x00000d2c),
PARAM_POLL(0xd4, BIT(0), BIT(0)),
/* phy setup */
PARAM_INDIRECT_WRITE(1, 0x01, 0x001f),
PARAM_INDIRECT_WRITE(7, 0x5d, 0x0014),
PARAM_INDIRECT_WRITE(7, 0x5e, 0x0014),
PARAM_INDIRECT_WRITE(7, 0x0d, 0x0003),
PARAM_INDIRECT_WRITE(7, 0x0e, 0x0007),
PARAM_INDIRECT_WRITE(7, 0x5f, 0x0003),
PARAM_INDIRECT_WRITE(7, 0x60, 0x0003),
PARAM_INDIRECT_WRITE(7, 0x5b, 0x00a6),
PARAM_INDIRECT_WRITE(7, 0x5c, 0x0003),
PARAM_INDIRECT_POLL(7, 0x3c, 0, BIT(7)),
PARAM_INDIRECT_POLL(7, 0x4c, 0, BIT(4)),
PARAM_INDIRECT_WRITE(1, 0x32, 0x0080),
PARAM_INDIRECT_WRITE(1, 0x1f, 0x0001),
PARAM_INDIRECT_WRITE(0, 0x2c, 0x0001),
PARAM_INDIRECT_WRITE(0, 0x32, 0x0087),
PARAM_INDIRECT_WRITE(1, 0x4d, 0x0061),
PARAM_INDIRECT_WRITE(4, 0x9b, 0x0009),
PARAM_INDIRECT_WRITE(4, 0xa6, 0x0005),
PARAM_INDIRECT_WRITE(4, 0xa5, 0x0058),
PARAM_INDIRECT_WRITE(1, 0x39, 0x0027),
PARAM_INDIRECT_WRITE(1, 0x47, 0x004c),
PARAM_INDIRECT_WRITE(7, 0x0d, 0x0002),
PARAM_INDIRECT_WRITE(7, 0x0e, 0x0007),
PARAM_WRITE_PHY(0x0028, 0x0061),
PARAM_WRITE_PHY(0x4014, 0x0061),
PARAM_SET_PHY(0x401c, BIT(2)),
PARAM_WRITE_PHY(0x4000, 0x0000),
PARAM_WRITE_PHY(0x4001, 0x0000),
PARAM_WRITE_PHY(0x10ae, 0x0001),
PARAM_WRITE_PHY(0x10ad, 0x0000),
PARAM_WRITE_PHY(0x10af, 0x0001),
PARAM_WRITE_PHY(0x10b6, 0x0001),
PARAM_WRITE_PHY(0x10ae, 0x0000),
PARAM_WRITE_PHY(0x10ae, 0x0001),
PARAM_WRITE_PHY(0x10ad, 0x0000),
PARAM_WRITE_PHY(0x10af, 0x0002),
PARAM_WRITE_PHY(0x10b6, 0x0001),
PARAM_WRITE_PHY(0x10ae, 0x0000),
PARAM_WRITE_PHY(0x10ae, 0x0001),
PARAM_WRITE_PHY(0x10ad, 0x0080),
PARAM_WRITE_PHY(0x10af, 0x0000),
PARAM_WRITE_PHY(0x10b6, 0x0001),
PARAM_WRITE_PHY(0x10ae, 0x0000),
PARAM_WRITE_PHY(0x10ae, 0x0001),
PARAM_WRITE_PHY(0x10ad, 0x0080),
PARAM_WRITE_PHY(0x10af, 0x001a),
PARAM_WRITE_PHY(0x10b6, 0x0001),
PARAM_WRITE_PHY(0x10ae, 0x0000),
PARAM_INDIRECT_WRITE(7, 0x70, 0x0016),
PARAM_INDIRECT_WRITE(7, 0x71, 0x0016),
PARAM_INDIRECT_WRITE(7, 0x72, 0x0014),
PARAM_INDIRECT_WRITE(7, 0x73, 0x0014),
PARAM_INDIRECT_WRITE(7, 0x74, 0x0000),
PARAM_INDIRECT_WRITE(7, 0x75, 0x0000),
PARAM_INDIRECT_WRITE(7, 0x76, 0x0010),
PARAM_INDIRECT_WRITE(7, 0x77, 0x0010),
PARAM_INDIRECT_WRITE(7, 0x78, 0x00ff),
PARAM_INDIRECT_WRITE(7, 0x79, 0x0000),
PARAM_INDIRECT_WRITE(7, 0x19, 0x0007),
PARAM_INDIRECT_WRITE(7, 0x1a, 0x0007),
PARAM_INDIRECT_WRITE(7, 0x24, 0x000c),
PARAM_INDIRECT_WRITE(7, 0x25, 0x000c),
PARAM_INDIRECT_WRITE(7, 0x62, 0x0000),
PARAM_INDIRECT_WRITE(7, 0x63, 0x0000),
PARAM_INDIRECT_WRITE(7, 0x5d, 0x0014),
PARAM_INDIRECT_WRITE(7, 0x5e, 0x0017),
PARAM_INDIRECT_WRITE(7, 0x5d, 0x0004),
PARAM_INDIRECT_WRITE(7, 0x5e, 0x0017),
PARAM_INDIRECT_POLL(7, 0x55, 0, BIT(6)),
PARAM_INDIRECT_POLL(7, 0x41, 0, BIT(7)),
/* end of phy setup */
PARAM_WRITE(0xf0, 0),
PARAM_WRITE(0xd0, 0x00000d00),
PARAM_RESTORE(0xd4, TIMER_INDEX),
};
static void ufs_renesas_reg_control(struct ufs_hba *hba,
const struct ufs_renesas_init_param *p)
{
static u32 save[MAX_INDEX];
int ret;
u32 val;
WARN_ON(p->index >= MAX_INDEX);
switch (p->mode) {
case MODE_RESTORE:
ufshcd_writel(hba, save[p->index], p->reg);
break;
case MODE_SET:
save[p->index] |= p->u.set;
break;
case MODE_SAVE:
save[p->index] = ufshcd_readl(hba, p->reg) & p->mask;
break;
case MODE_POLL:
ret = readl_poll_timeout(hba->mmio_base + p->reg, val,
(val & p->mask) == p->u.expected,
10000);
if (ret)
dev_err(hba->dev, "%s: poll failed %d (%08x, %08x, %08x)\n",
__func__, ret, val, p->mask, p->u.expected);
break;
case MODE_WAIT:
if (p->u.delay_us > 1000)
mdelay(DIV_ROUND_UP(p->u.delay_us, 1000));
else
udelay(p->u.delay_us);
break;
case MODE_WRITE:
ufshcd_writel(hba, p->u.val, p->reg);
break;
default:
break;
}
}
static void ufs_renesas_pre_init(struct ufs_hba *hba)
{
const struct ufs_renesas_init_param *p = ufs_param;
unsigned int i;
for (i = 0; i < ARRAY_SIZE(ufs_param); i++)
ufs_renesas_reg_control(hba, &p[i]);
}
static int ufs_renesas_hce_enable_notify(struct ufs_hba *hba,
enum ufs_notify_change_status status)
{
struct ufs_renesas_priv *priv = dev_get_priv(hba->dev);
if (priv->initialized)
return 0;
if (status == PRE_CHANGE)
ufs_renesas_pre_init(hba);
priv->initialized = true;
return 0;
}
static int ufs_renesas_init(struct ufs_hba *hba)
{
hba->quirks |= UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS | UFSHCD_QUIRK_HIBERN_FASTAUTO;
return 0;
}
static struct ufs_hba_ops ufs_renesas_vops = {
.init = ufs_renesas_init,
.hce_enable_notify = ufs_renesas_hce_enable_notify,
};
static int ufs_renesas_pltfm_bind(struct udevice *dev)
{
struct udevice *scsi_dev;
return ufs_scsi_bind(dev, &scsi_dev);
}
static int ufs_renesas_pltfm_probe(struct udevice *dev)
{
struct ufs_renesas_priv *priv = dev_get_priv(dev);
int err;
err = clk_get_bulk(dev, &priv->clks);
if (err < 0)
return err;
err = clk_enable_bulk(&priv->clks);
if (err)
goto err_clk_enable;
err = ufshcd_probe(dev, &ufs_renesas_vops);
if (err) {
dev_err(dev, "ufshcd_probe() failed %d\n", err);
goto err_ufshcd_probe;
}
return 0;
err_ufshcd_probe:
clk_disable_bulk(&priv->clks);
err_clk_enable:
clk_release_bulk(&priv->clks);
return err;
}
static int ufs_renesas_pltfm_remove(struct udevice *dev)
{
struct ufs_renesas_priv *priv = dev_get_priv(dev);
clk_disable_bulk(&priv->clks);
clk_release_bulk(&priv->clks);
return 0;
}
static const struct udevice_id ufs_renesas_pltfm_ids[] = {
{ .compatible = "renesas,r8a779f0-ufs" },
{ /* sentinel */ }
};
U_BOOT_DRIVER(ufs_renesas) = {
.name = "ufs-renesas",
.id = UCLASS_UFS,
.of_match = ufs_renesas_pltfm_ids,
.bind = ufs_renesas_pltfm_bind,
.probe = ufs_renesas_pltfm_probe,
.remove = ufs_renesas_pltfm_remove,
.priv_auto = sizeof(struct ufs_renesas_priv),
};