[PATCH 2/2] rtc: Introduce ti-k3-rtc

Vignesh Raghavendra vigneshr at ti.com
Fri Apr 15 01:03:14 PDT 2022


Hi,

On 12/04/22 1:01 pm, Nishanth Menon wrote:
> +/**
> + * k3rtc_fence  - Ensure a register sync took place between the two domains
> + * @priv:      pointer to priv data
> + *
> + * Return: 0 if the sync took place, else returns -ETIMEDOUT
> + */
> +static int k3rtc_fence(struct ti_k3_rtc *priv)
> +{
> +	u32 timeout = priv->sync_timeout_us;
> +	u32 mask = K3RTC_RD_PEND_BIT | K3RTC_WR_PEND_BIT;
> +	u32 val = 0;
> +
> +	while (timeout--) {
> +		val = k3rtc_readl(priv, REG_K3RTC_SYNCPEND);
> +		if (!(val & mask))
> +			return 0;
> +		usleep_range(1, 2);
> +	}

readl_poll_timeout() ?

> +
> +	pr_err("RTC Fence timeout: 0x%08x\n", val);

Can we use dev_err()?  Provides better indication of the driver throwing
error.

> +	return -ETIMEDOUT;
> +}
> +
> +static inline int k3rtc_check_unlocked(struct ti_k3_rtc *priv)
> +{
> +	u32 val;
> +
> +	val = k3rtc_readl(priv, REG_K3RTC_GENERAL_CTL);
> +	return (val & K3RTC_UNLOCK_BIT) ? 0 : 1;
> +}
> +
> +static int k3rtc_unlock_rtc(struct ti_k3_rtc *priv)
> +{
> +	u32 timeout = priv->sync_timeout_us;
> +	int ret;
> +
> +	ret = k3rtc_check_unlocked(priv);
> +	if (!ret)
> +		return ret;
> +
> +	k3rtc_writel(priv, REG_K3RTC_KICK0, K3RTC_KICK0_UNLOCK_VALUE);
> +	k3rtc_writel(priv, REG_K3RTC_KICK1, K3RTC_KICK1_UNLOCK_VALUE);
> +
> +	/* Skip fence since we are going to check the unlock bit as fence */
> +	while (timeout--) {
> +		ret = k3rtc_check_unlocked(priv);
> +		if (!ret)
> +			return ret;
> +		usleep_range(1, 2);
> +	}

readl_poll_timeout() ?

> +
> +	return -ETIMEDOUT;
> +}
> +
> +static int k3rtc_configure(struct device *dev)
> +{
> +	int ret;
> +	u32 ctl;
> +	struct ti_k3_rtc *priv = dev_get_drvdata(dev);
> +
> +	/*
> +	 * HWBUG: The compare statemachine is broken if the RTC module
> +	 * is NOT unlocked in under one second of boot - which is pretty long
> +	 * time from the perspective of Linux driver (module load, u-boot
> +	 * shell all can take much longer than this.
> +	 *
> +	 * In such occurrence, it is assumed that the RTC module is un-usable
> +	 */
> +	if (priv->soc->unlock_irq_erratum) {
> +		ret = k3rtc_check_unlocked(priv);
> +		/* If there is an error OR if we are locked, return error */
> +		if (ret) {
> +			dev_err(dev, HW_ERR "Erratum i2327 unlock QUIRK! Cannot operate!!\n");
> +			return -EFAULT;
> +		}
> +	} else {
> +		/* May Need to explicitly unlock first time */
> +		ret = k3rtc_unlock_rtc(priv);
> +		if (ret) {
> +			dev_err(dev, "Failed to unlock(%d)!\n", ret);
> +			return ret;
> +		}
> +	}
> +
> +	/* Enable Shadow register sync on 32k clk boundary */
> +	ctl = k3rtc_readl(priv, REG_K3RTC_GENERAL_CTL);
> +	ctl |= K3RTC_O32K_OSC_DEP_EN_BIT;
> +	k3rtc_writel(priv, REG_K3RTC_GENERAL_CTL, ctl);
> +
> +	/*
> +	 * Wait at least 2 clk sync time before proceeding further programming.
> +	 * This ensures that the 32k based sync is active.
> +	 */
> +	usleep_range(priv->sync_timeout_us, priv->sync_timeout_us + 5);
> +
> +	/* We need to ensure fence here to make sure sync here */
> +	ret = k3rtc_fence(priv);
> +	if (ret) {
> +		dev_err(dev, "Failed fence osc_dep enable(%d) - is 32k clk working?!\n",
> +			ret);
> +		return ret;
> +	}
> +
> +	/* Lets just make sure we get consistent time value */
> +	ctl &= ~K3RTC_CNT_FMODE_MASK;
> +	/*
> +	 * FMODE setting: Reading lower seconds will freeze value on higher
> +	 * seconds. This also implies that we must *ALWAYS* read lower seconds
> +	 * prior to reading higher seconds
> +	 */
> +	ctl |= K3RTC_CNT_FMODE_S_CNT_VALUE;
> +	k3rtc_writel(priv, REG_K3RTC_GENERAL_CTL, ctl);
> +
> +	/* Clear any spurious IRQ sources if any */
> +	k3rtc_writel(priv, REG_K3RTC_IRQSTATUS_SYS,
> +		     K3RTC_EVENT_ON_OFF_BIT | K3RTC_EVENT_OFF_ON_BIT);
> +	/* Disable all IRQs */
> +	k3rtc_writel(priv, REG_K3RTC_IRQENABLE_CLR_SYS,
> +		     K3RTC_EVENT_ON_OFF_BIT | K3RTC_EVENT_OFF_ON_BIT);
> +
> +	/* And.. Let us Sync the writes in */
> +	ret = k3rtc_fence(priv);
> +	if (ret) {
> +		dev_err(dev, "Failed to fence(%d)!\n", ret);
> +		return ret;

nit: this can be dropped as next statement will return error code anyway

> +	}
> +
> +	return ret;
> +}
> +

[...]

> +
> +static const struct ti_k3_rtc_soc_data ti_k3_am62_data = {
> +	.unlock_irq_erratum = true,
> +};
> +
> +static const struct of_device_id ti_k3_rtc_of_match_table[] = {
> +	{.compatible = "ti,am62-rtc", .data = &ti_k3_am62_data},
> +	{}
> +};
> +MODULE_DEVICE_TABLE(of, ti_k3_rtc_of_match_table);
> +
> +#ifdef CONFIG_PM_SLEEP
> +static int ti_k3_rtc_suspend(struct device *dev)

 __maybe_unused preferred instead of #ifdef for better compile coverage
but upto you.

> +{
> +	struct ti_k3_rtc *priv = dev_get_drvdata(dev);
> +
> +	if (device_may_wakeup(dev))
> +		enable_irq_wake(priv->irq);
> +	return 0;
> +}
> +
> +static int ti_k3_rtc_resume(struct device *dev)
> +{
> +	struct ti_k3_rtc *priv = dev_get_drvdata(dev);
> +
> +	if (device_may_wakeup(dev))
> +		disable_irq_wake(priv->irq);
> +	return 0;
> +}
> +#endif
> +
> +static SIMPLE_DEV_PM_OPS(ti_k3_rtc_pm_ops, ti_k3_rtc_suspend, ti_k3_rtc_resume);
> +
> +static struct platform_driver ti_k3_rtc_driver = {
> +	.probe = ti_k3_rtc_probe,
> +	.driver = {
> +		   .name = "rtc-ti-k3",
> +		   .of_match_table = ti_k3_rtc_of_match_table,
> +		   .pm = &ti_k3_rtc_pm_ops,
> +		   },
Extra tab?

> +};
> +module_platform_driver(ti_k3_rtc_driver);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("TI K3 RTC driver");
> +MODULE_AUTHOR("Nishanth Menon");
> +MODULE_ALIAS("platform:rtc-ti-k3");
> -- 2.31.1



More information about the linux-arm-kernel mailing list