Xilinx changes for v2021.04-rc3

qspi:
 - Support for dual/quad mode
 - Fix speed handling
 
 clk:
 - Add clock enable function for zynq/zynqmp/versal
 
 gem:
 - Enable clock for Versal
 - Fix error path
 - Fix mdio deregistration path
 
 fpga:
 - Fix buffer alignment for ZynqMP
 
 xilinx:
 - Fix reset reason clearing in ZynqMP
 - Show silicon version in SPL for Zynq/ZynqMP
 - Fix DTB selection for ZynqMP
 - Rename zc1275 to zcu1275 to match DT name
 -----BEGIN PGP SIGNATURE-----
 
 iF0EABECAB0WIQQbPNTMvXmYlBPRwx7KSWXLKUoMIQUCYDUezQAKCRDKSWXLKUoM
 IbtgAJ9jZ+BOtwFaHR19TENC2DsHTINnnwCfSDn3fU0OFJRI0HD7pRxXr4xrb3M=
 =Kr8x
 -----END PGP SIGNATURE-----

Merge tag 'xilinx-for-v2021.04-rc3' of https://gitlab.denx.de/u-boot/custodians/u-boot-microblaze

Xilinx changes for v2021.04-rc3

qspi:
- Support for dual/quad mode
- Fix speed handling

clk:
- Add clock enable function for zynq/zynqmp/versal

gem:
- Enable clock for Versal
- Fix error path
- Fix mdio deregistration path

fpga:
- Fix buffer alignment for ZynqMP

xilinx:
- Fix reset reason clearing in ZynqMP
- Show silicon version in SPL for Zynq/ZynqMP
- Fix DTB selection for ZynqMP
- Rename zc1275 to zcu1275 to match DT name
This commit is contained in:
Tom Rini 2021-02-23 10:45:55 -05:00
commit cbe607b920
18 changed files with 208 additions and 134 deletions

View File

@ -128,8 +128,8 @@ struct apu_regs {
#define ZYNQMP_CSU_VERSION_EMPTY_SHIFT 20
#define ZYNQMP_SILICON_VER_MASK 0xF000
#define ZYNQMP_SILICON_VER_SHIFT 12
#define ZYNQMP_SILICON_VER_MASK 0xF
#define ZYNQMP_SILICON_VER_SHIFT 0
struct csu_regs {
u32 reserved0[4];

View File

@ -327,7 +327,7 @@ void *board_fdt_blob_setup(void)
if (!IS_ENABLED(CONFIG_SPL_BUILD) &&
!IS_ENABLED(CONFIG_VERSAL_NO_DDR) &&
!IS_ENABLED(CONFIG_VERSAL_NO_DDR)) {
!IS_ENABLED(CONFIG_ZYNQMP_NO_DDR)) {
fdt_blob = (void *)CONFIG_XILINX_OF_BOARD_DTB_ADDR;
if (fdt_magic(fdt_blob) == FDT_MAGIC)

View File

@ -25,6 +25,9 @@ DECLARE_GLOBAL_DATA_PTR;
int board_init(void)
{
if (IS_ENABLED(CONFIG_SPL_BUILD))
printf("Silicon version:\t%d\n", zynq_get_silicon_version());
return 0;
}

View File

@ -329,6 +329,7 @@ int board_init(void)
if (sizeof(CONFIG_ZYNQMP_SPL_PM_CFG_OBJ_FILE) > 1)
zynqmp_pmufw_load_config_object(zynqmp_pm_cfg_obj,
zynqmp_pm_cfg_obj_size);
printf("Silicon version:\t%d\n", zynqmp_get_silicon_version());
#else
if (CONFIG_IS_ENABLED(DM_I2C) && CONFIG_IS_ENABLED(I2C_EEPROM))
xilinx_read_eeprom();
@ -496,11 +497,7 @@ static int reset_reason(void)
env_set("reset_reason", reason);
ret = zynqmp_mmio_write((ulong)&crlapb_base->reset_reason, ~0, ~0);
if (ret)
return -EINVAL;
return ret;
return 0;
}
static int set_fdtfile(void)

View File

@ -718,9 +718,20 @@ static ulong versal_clk_set_rate(struct clk *clk, ulong rate)
return clk_rate;
}
static int versal_clk_enable(struct clk *clk)
{
struct versal_clk_priv *priv = dev_get_priv(clk->dev);
u32 clk_id;
clk_id = priv->clk[clk->id].clk_id;
return xilinx_pm_request(PM_CLOCK_ENABLE, clk_id, 0, 0, 0, NULL);
}
static struct clk_ops versal_clk_ops = {
.set_rate = versal_clk_set_rate,
.get_rate = versal_clk_get_rate,
.enable = versal_clk_enable,
};
static const struct udevice_id versal_clk_ids[] = {

View File

@ -445,11 +445,21 @@ static ulong zynq_clk_get_rate(struct clk *clk)
}
#endif
static int dummy_enable(struct clk *clk)
{
/*
* Add implementation but by default all clocks are enabled
* after power up which is only one supported case now.
*/
return 0;
}
static struct clk_ops zynq_clk_ops = {
.get_rate = zynq_clk_get_rate,
#ifndef CONFIG_SPL_BUILD
.set_rate = zynq_clk_set_rate,
#endif
.enable = dummy_enable,
};
static int zynq_clk_probe(struct udevice *dev)

View File

@ -199,6 +199,8 @@ static u32 zynqmp_clk_get_register(enum zynqmp_clk id)
return CRF_APB_DDR_CTRL;
case qspi_ref:
return CRL_APB_QSPI_REF_CTRL;
case usb3_dual_ref:
return CRL_APB_USB3_DUAL_REF_CTRL;
case gem0_ref:
return CRL_APB_GEM0_REF_CTRL;
case gem1_ref:
@ -207,6 +209,10 @@ static u32 zynqmp_clk_get_register(enum zynqmp_clk id)
return CRL_APB_GEM2_REF_CTRL;
case gem3_ref:
return CRL_APB_GEM3_REF_CTRL;
case usb0_bus_ref:
return CRL_APB_USB0_BUS_REF_CTRL;
case usb1_bus_ref:
return CRL_APB_USB1_BUS_REF_CTRL;
case uart0_ref:
return CRL_APB_UART0_REF_CTRL;
case uart1_ref:
@ -699,9 +705,52 @@ static int zynqmp_clk_probe(struct udevice *dev)
return 0;
}
static int zynqmp_clk_enable(struct clk *clk)
{
enum zynqmp_clk id = clk->id;
u32 reg, clk_ctrl, clkact_shift, mask;
int ret;
reg = zynqmp_clk_get_register(id);
debug("%s, clk_id:%x, clk_base:0x%x\n", __func__, id, reg);
switch (id) {
case usb0_bus_ref ... usb1:
clkact_shift = 25;
mask = 0x1;
break;
case gem0_ref ... gem3_ref:
clkact_shift = 25;
mask = 0x3;
break;
case qspi_ref ... can1_ref:
clkact_shift = 24;
mask = 0x1;
break;
default:
return -ENXIO;
}
ret = zynqmp_mmio_read(reg, &clk_ctrl);
if (ret) {
printf("%s mio read fail\n", __func__);
return -EIO;
}
clk_ctrl |= (mask << clkact_shift);
ret = zynqmp_mmio_write(reg, mask << clkact_shift, clk_ctrl);
if (ret) {
printf("%s mio write fail\n", __func__);
return -EIO;
}
return ret;
}
static struct clk_ops zynqmp_clk_ops = {
.set_rate = zynqmp_clk_set_rate,
.get_rate = zynqmp_clk_get_rate,
.enable = zynqmp_clk_enable,
};
static const struct udevice_id zynqmp_clk_ids[] = {

View File

@ -315,7 +315,7 @@ static u32 *zynq_align_dma_buffer(u32 *buf, u32 len, u32 swap)
if (new_buf > buf) {
debug("%s: Aligned buffer is after buffer start\n",
__func__);
new_buf -= ARCH_DMA_MINALIGN;
new_buf = (u32 *)((u32)new_buf - ARCH_DMA_MINALIGN);
}
printf("%s: Align buffer at %x to %x(swap %d)\n", __func__,
(u32)buf, (u32)new_buf, swap);

View File

@ -15,6 +15,7 @@
#include <linux/types.h>
#include <linux/io.h>
#include <linux/errno.h>
#include <dm/device_compat.h>
#include <dm/root.h>
#include <i2c.h>
#include <fdtdec.h>
@ -481,6 +482,12 @@ static int cdns_i2c_of_to_plat(struct udevice *dev)
i2c_bus->input_freq = clk_get_rate(&clk);
ret = clk_enable(&clk);
if (ret) {
dev_err(dev, "failed to enable clock\n");
return ret;
}
return 0;
}

View File

@ -577,7 +577,7 @@ static int arasan_sdhci_probe(struct udevice *dev)
debug("%s: CLK %ld\n", __func__, clock);
ret = clk_enable(&clk);
if (ret && ret != -ENOSYS) {
if (ret) {
dev_err(dev, "failed to enable clock\n");
return ret;
}

View File

@ -129,6 +129,8 @@
#define ZYNQ_GEM_FREQUENCY_100 25000000UL
#define ZYNQ_GEM_FREQUENCY_1000 125000000UL
#define RXCLK_EN BIT(0)
/* Device registers */
struct zynq_gem_regs {
u32 nwctrl; /* 0x0 - Network Control reg */
@ -205,10 +207,12 @@ struct zynq_gem_priv {
struct phy_device *phydev;
ofnode phy_of_node;
struct mii_dev *bus;
struct clk clk;
struct clk rx_clk;
struct clk tx_clk;
u32 max_speed;
bool int_pcs;
bool dma_64bit;
u32 clk_en_info;
};
static int phy_setup_op(struct zynq_gem_priv *priv, u32 phy_addr, u32 regnum,
@ -476,18 +480,25 @@ static int zynq_gem_init(struct udevice *dev)
break;
}
ret = clk_set_rate(&priv->clk, clk_rate);
if (IS_ERR_VALUE(ret) && ret != (unsigned long)-ENOSYS) {
ret = clk_set_rate(&priv->tx_clk, clk_rate);
if (IS_ERR_VALUE(ret)) {
dev_err(dev, "failed to set tx clock rate\n");
return ret;
}
ret = clk_enable(&priv->clk);
if (ret && ret != -ENOSYS) {
ret = clk_enable(&priv->tx_clk);
if (ret) {
dev_err(dev, "failed to enable tx clock\n");
return ret;
}
if (priv->clk_en_info & RXCLK_EN) {
ret = clk_enable(&priv->rx_clk);
if (ret) {
dev_err(dev, "failed to enable rx clock\n");
return ret;
}
}
setbits_le32(&regs->nwctrl, ZYNQ_GEM_NWCTRL_RXEN_MASK |
ZYNQ_GEM_NWCTRL_TXEN_MASK);
@ -694,10 +705,18 @@ static int zynq_gem_probe(struct udevice *dev)
priv->tx_bd = (struct emac_bd *)bd_space;
priv->rx_bd = (struct emac_bd *)((ulong)bd_space + BD_SEPRN_SPACE);
ret = clk_get_by_name(dev, "tx_clk", &priv->clk);
ret = clk_get_by_name(dev, "tx_clk", &priv->tx_clk);
if (ret < 0) {
dev_err(dev, "failed to get clock\n");
goto err1;
dev_err(dev, "failed to get tx_clock\n");
goto err2;
}
if (priv->clk_en_info & RXCLK_EN) {
ret = clk_get_by_name(dev, "rx_clk", &priv->rx_clk);
if (ret < 0) {
dev_err(dev, "failed to get rx_clock\n");
goto err2;
}
}
priv->bus = mdio_alloc();
@ -711,14 +730,16 @@ static int zynq_gem_probe(struct udevice *dev)
ret = zynq_phy_init(dev);
if (ret)
goto err2;
goto err3;
return ret;
err3:
mdio_unregister(priv->bus);
err2:
free(priv->rxbuffers);
err1:
free(priv->tx_bd);
err1:
free(priv->rxbuffers);
return ret;
}
@ -792,11 +813,13 @@ static int zynq_gem_of_to_plat(struct udevice *dev)
(ulong)priv->iobase, (ulong)priv->mdiobase, priv->phyaddr,
phy_string_for_interface(priv->interface));
priv->clk_en_info = dev_get_driver_data(dev);
return 0;
}
static const struct udevice_id zynq_gem_ids[] = {
{ .compatible = "cdns,versal-gem" },
{ .compatible = "cdns,versal-gem", .data = RXCLK_EN },
{ .compatible = "cdns,zynqmp-gem" },
{ .compatible = "cdns,zynq-gem" },
{ .compatible = "cdns,gem" },

View File

@ -127,7 +127,7 @@ static int zynq_serial_setbrg(struct udevice *dev, int baudrate)
debug("%s: CLK %ld\n", __func__, clock);
ret = clk_enable(&clk);
if (ret && ret != -ENOSYS) {
if (ret) {
dev_err(dev, "failed to enable clock\n");
return ret;
}

View File

@ -194,7 +194,7 @@ static int zynq_qspi_probe(struct udevice *bus)
}
ret = clk_enable(&clk);
if (ret && ret != -ENOSYS) {
if (ret) {
dev_err(bus, "failed to enable clock\n");
return ret;
}

View File

@ -144,7 +144,7 @@ static int zynq_spi_probe(struct udevice *bus)
}
ret = clk_enable(&clk);
if (ret && ret != -ENOSYS) {
if (ret) {
dev_err(bus, "failed to enable clock\n");
return ret;
}

View File

@ -17,6 +17,7 @@
#include <malloc.h>
#include <memalign.h>
#include <spi.h>
#include <spi-mem.h>
#include <ubi_uboot.h>
#include <wait_bit.h>
#include <dm/device_compat.h>
@ -172,8 +173,7 @@ struct zynqmp_qspi_priv {
unsigned int len;
int bytes_to_transfer;
int bytes_to_receive;
unsigned int is_inst;
unsigned int cs_change:1;
const struct spi_mem_op *op;
};
static int zynqmp_qspi_of_to_plat(struct udevice *bus)
@ -222,6 +222,21 @@ static u32 zynqmp_qspi_bus_select(struct zynqmp_qspi_priv *priv)
return gqspi_fifo_reg;
}
static u32 zynqmp_qspi_genfifo_mode(u8 buswidth)
{
switch (buswidth) {
case 1:
return GQSPI_SPI_MODE_SPI;
case 2:
return GQSPI_SPI_MODE_DUAL_SPI;
case 4:
return GQSPI_SPI_MODE_QSPI;
default:
debug("Unsupported bus width %u\n", buswidth);
return GQSPI_SPI_MODE_SPI;
}
}
static void zynqmp_qspi_fill_gen_fifo(struct zynqmp_qspi_priv *priv,
u32 gqspi_fifo_reg)
{
@ -306,12 +321,9 @@ static int zynqmp_qspi_set_speed(struct udevice *bus, uint speed)
if (speed > plat->frequency)
speed = plat->frequency;
/* Set the clock frequency */
confr = readl(&regs->confr);
if (speed == 0) {
/* Set baudrate x8, if the freq is 0 */
baud_rate_val = GQSPI_DFLT_BAUD_RATE_VAL;
} else if (plat->speed_hz != speed) {
if (plat->speed_hz != speed) {
/* Set the clock frequency */
/* If speed == 0, default to lowest speed */
while ((baud_rate_val < 8) &&
((plat->frequency /
(2 << baud_rate_val)) > speed))
@ -321,13 +333,15 @@ static int zynqmp_qspi_set_speed(struct udevice *bus, uint speed)
baud_rate_val = GQSPI_DFLT_BAUD_RATE_VAL;
plat->speed_hz = plat->frequency / (2 << baud_rate_val);
}
confr &= ~GQSPI_BAUD_DIV_MASK;
confr |= (baud_rate_val << 3);
writel(confr, &regs->confr);
zynqmp_qspi_set_tapdelay(bus, baud_rate_val);
debug("regs=%p, speed=%d\n", priv->regs, plat->speed_hz);
confr = readl(&regs->confr);
confr &= ~GQSPI_BAUD_DIV_MASK;
confr |= (baud_rate_val << 3);
writel(confr, &regs->confr);
zynqmp_qspi_set_tapdelay(bus, baud_rate_val);
debug("regs=%p, speed=%d\n", priv->regs, plat->speed_hz);
}
return 0;
}
@ -359,7 +373,7 @@ static int zynqmp_qspi_probe(struct udevice *bus)
debug("%s: CLK %ld\n", __func__, clock);
ret = clk_enable(&clk);
if (ret && ret != -ENOSYS) {
if (ret) {
dev_err(bus, "failed to enable clock\n");
return ret;
}
@ -446,21 +460,42 @@ static int zynqmp_qspi_fill_tx_fifo(struct zynqmp_qspi_priv *priv, u32 size)
static void zynqmp_qspi_genfifo_cmd(struct zynqmp_qspi_priv *priv)
{
const struct spi_mem_op *op = priv->op;
u32 gen_fifo_cmd;
u32 bytecount = 0;
u8 i, dummy_cycles, addr;
/* Send opcode */
gen_fifo_cmd = zynqmp_qspi_bus_select(priv);
gen_fifo_cmd |= zynqmp_qspi_genfifo_mode(op->cmd.buswidth);
gen_fifo_cmd |= GQSPI_GFIFO_TX;
gen_fifo_cmd |= op->cmd.opcode;
zynqmp_qspi_fill_gen_fifo(priv, gen_fifo_cmd);
/* Send address */
for (i = 0; i < op->addr.nbytes; i++) {
addr = op->addr.val >> (8 * (op->addr.nbytes - i - 1));
while (priv->len) {
gen_fifo_cmd = zynqmp_qspi_bus_select(priv);
gen_fifo_cmd |= GQSPI_GFIFO_TX | GQSPI_SPI_MODE_SPI;
gen_fifo_cmd |= *(u8 *)priv->tx_buf;
bytecount++;
priv->len--;
priv->tx_buf = (u8 *)priv->tx_buf + 1;
gen_fifo_cmd |= zynqmp_qspi_genfifo_mode(op->addr.buswidth);
gen_fifo_cmd |= GQSPI_GFIFO_TX;
gen_fifo_cmd |= addr;
debug("GFIFO_CMD_Cmd = 0x%x\n", gen_fifo_cmd);
zynqmp_qspi_fill_gen_fifo(priv, gen_fifo_cmd);
}
/* Send dummy */
if (op->dummy.nbytes) {
dummy_cycles = op->dummy.nbytes * 8 / op->dummy.buswidth;
gen_fifo_cmd = zynqmp_qspi_bus_select(priv);
gen_fifo_cmd |= zynqmp_qspi_genfifo_mode(op->dummy.buswidth);
gen_fifo_cmd &= ~(GQSPI_GFIFO_TX | GQSPI_GFIFO_RX);
gen_fifo_cmd |= GQSPI_GFIFO_DATA_XFR_MASK;
gen_fifo_cmd |= dummy_cycles;
zynqmp_qspi_fill_gen_fifo(priv, gen_fifo_cmd);
}
}
static u32 zynqmp_qspi_calc_exp(struct zynqmp_qspi_priv *priv,
@ -497,11 +532,10 @@ static int zynqmp_qspi_genfifo_fill_tx(struct zynqmp_qspi_priv *priv)
int ret = 0;
gen_fifo_cmd = zynqmp_qspi_bus_select(priv);
gen_fifo_cmd |= zynqmp_qspi_genfifo_mode(priv->op->data.buswidth);
gen_fifo_cmd |= GQSPI_GFIFO_TX |
GQSPI_GFIFO_DATA_XFR_MASK;
gen_fifo_cmd |= GQSPI_SPI_MODE_SPI;
while (priv->len) {
len = zynqmp_qspi_calc_exp(priv, &gen_fifo_cmd);
zynqmp_qspi_fill_gen_fifo(priv, gen_fifo_cmd);
@ -575,11 +609,10 @@ static int zynqmp_qspi_genfifo_fill_rx(struct zynqmp_qspi_priv *priv)
u32 actuallen = priv->len;
gen_fifo_cmd = zynqmp_qspi_bus_select(priv);
gen_fifo_cmd |= zynqmp_qspi_genfifo_mode(priv->op->data.buswidth);
gen_fifo_cmd |= GQSPI_GFIFO_RX |
GQSPI_GFIFO_DATA_XFR_MASK;
gen_fifo_cmd |= GQSPI_SPI_MODE_SPI;
/*
* Check if receive buffer is aligned to 4 byte and length
* is multiples of four byte as we are using dma to receive.
@ -596,62 +629,6 @@ static int zynqmp_qspi_genfifo_fill_rx(struct zynqmp_qspi_priv *priv)
return zynqmp_qspi_start_dma(priv, gen_fifo_cmd, buf);
}
static int zynqmp_qspi_start_transfer(struct zynqmp_qspi_priv *priv)
{
int ret = 0;
if (priv->is_inst) {
if (priv->tx_buf)
zynqmp_qspi_genfifo_cmd(priv);
else
return -EINVAL;
} else {
if (priv->tx_buf)
ret = zynqmp_qspi_genfifo_fill_tx(priv);
else if (priv->rx_buf)
ret = zynqmp_qspi_genfifo_fill_rx(priv);
else
return -EINVAL;
}
return ret;
}
static int zynqmp_qspi_transfer(struct zynqmp_qspi_priv *priv)
{
static unsigned int cs_change = 1;
int status = 0;
debug("%s\n", __func__);
while (1) {
/* Select the chip if required */
if (cs_change)
zynqmp_qspi_chipselect(priv, 1);
cs_change = priv->cs_change;
if (!priv->tx_buf && !priv->rx_buf && priv->len) {
status = -EINVAL;
break;
}
/* Request the transfer */
if (priv->len) {
status = zynqmp_qspi_start_transfer(priv);
priv->is_inst = 0;
if (status < 0)
break;
}
if (cs_change)
/* Deselect the chip */
zynqmp_qspi_chipselect(priv, 0);
break;
}
return status;
}
static int zynqmp_qspi_claim_bus(struct udevice *dev)
{
struct udevice *bus = dev->parent;
@ -674,45 +651,43 @@ static int zynqmp_qspi_release_bus(struct udevice *dev)
return 0;
}
int zynqmp_qspi_xfer(struct udevice *dev, unsigned int bitlen, const void *dout,
void *din, unsigned long flags)
static int zynqmp_qspi_exec_op(struct spi_slave *slave,
const struct spi_mem_op *op)
{
struct udevice *bus = dev->parent;
struct zynqmp_qspi_priv *priv = dev_get_priv(bus);
struct zynqmp_qspi_priv *priv = dev_get_priv(slave->dev->parent);
int ret = 0;
debug("%s: priv: 0x%08lx bitlen: %d dout: 0x%08lx ", __func__,
(unsigned long)priv, bitlen, (unsigned long)dout);
debug("din: 0x%08lx flags: 0x%lx\n", (unsigned long)din, flags);
priv->op = op;
priv->tx_buf = op->data.buf.out;
priv->rx_buf = op->data.buf.in;
priv->len = op->data.nbytes;
priv->tx_buf = dout;
priv->rx_buf = din;
priv->len = bitlen / 8;
zynqmp_qspi_chipselect(priv, 1);
/*
* Assume that the beginning of a transfer with bits to
* transmit must contain a device command.
*/
if (dout && flags & SPI_XFER_BEGIN)
priv->is_inst = 1;
else
priv->is_inst = 0;
/* Send opcode, addr, dummy */
zynqmp_qspi_genfifo_cmd(priv);
if (flags & SPI_XFER_END)
priv->cs_change = 1;
else
priv->cs_change = 0;
/* Request the transfer */
if (op->data.dir == SPI_MEM_DATA_IN)
ret = zynqmp_qspi_genfifo_fill_rx(priv);
else if (op->data.dir == SPI_MEM_DATA_OUT)
ret = zynqmp_qspi_genfifo_fill_tx(priv);
zynqmp_qspi_transfer(priv);
zynqmp_qspi_chipselect(priv, 0);
return 0;
return ret;
}
static const struct spi_controller_mem_ops zynqmp_qspi_mem_ops = {
.exec_op = zynqmp_qspi_exec_op,
};
static const struct dm_spi_ops zynqmp_qspi_ops = {
.claim_bus = zynqmp_qspi_claim_bus,
.release_bus = zynqmp_qspi_release_bus,
.xfer = zynqmp_qspi_xfer,
.set_speed = zynqmp_qspi_set_speed,
.set_mode = zynqmp_qspi_set_mode,
.mem_ops = &zynqmp_qspi_mem_ops,
};
static const struct udevice_id zynqmp_qspi_ids[] = {

View File

@ -90,9 +90,8 @@ static int xlnx_wwdt_start(struct udevice *dev, u64 timeout, ulong flags)
/* Calculate timeout count */
count = timeout * clock_f;
/* clk_enable will return -ENOSYS when it is not implemented */
ret = clk_enable(&wdt->clk);
if (ret && ret != -ENOSYS) {
if (ret) {
dev_err(dev, "failed to enable clock\n");
return ret;
}