[RFC 2/3] rtc: Add Realtek RTD1295

Andreas Färber afaerber at suse.de
Sun Aug 20 14:10:16 PDT 2017


Hi Alexandre,

Am 20.08.2017 um 10:32 schrieb Alexandre Belloni:
> On 20/08/2017 at 03:36:30 +0200, Andreas Färber wrote:
>> +static int rtd119x_rtc_read_time(struct device *dev, struct rtc_time *tm)
>> +{
>> +	struct rtd119x_rtc *data = dev_get_drvdata(dev);
>> +	time64_t t;
>> +	u32 day;
>> +
>> +	day = readl_relaxed(data->base + RTD_RTCDATE_LOW);
>> +	day |= readl_relaxed(data->base + RTD_RTCDATE_HIGH) << 8;
> 
> Is RTD_RTCDATE_HIGH latched when RTD_RTCDATE_LOW is read?

I do not have an answer to that.

> If this is not
> the case, you probably want to handle a possible update between both
> readl_relaxed.

Are you proposing to disable the RTC while reading the registers, or
something related to my choice of _relaxed? (it follows an explanation
by Marc Zyngier on the irq mux series) Inconsistencies might not be
limited to the date.

>> +	t = mktime64(data->base_year, 1, 1, 0, 0, 0);
>> +	t += day * 24 * 60 * 60;
>> +	rtc_time64_to_tm(t, tm);

BTW is there any more efficient way to get from year+days to
day/month/year without going via seconds?

>> +	tm->tm_sec  = readl_relaxed(data->base + RTD_RTCSEC) >> 1;
>> +	tm->tm_min  = readl_relaxed(data->base + RTD_RTCMIN);
>> +	tm->tm_hour = readl_relaxed(data->base + RTD_RTCHR);
>> +
>> +	return rtc_valid_tm(tm);
>> +}
>> +
>> +static int rtd119x_rtc_set_time(struct device *dev, struct rtc_time *tm)
>> +{
>> +	struct rtd119x_rtc *data = dev_get_drvdata(dev);
>> +	time64_t time_base, new_time, time_delta;
>> +	unsigned long day;
>> +
>> +	if (tm->tm_year < data->base_year)
>> +		return -EINVAL;
>> +
>> +	time_base = mktime64(data->base_year, 1, 1, 0, 0, 0);
>> +	new_time = rtc_tm_to_time64(tm);
>> +	time_delta = new_time - time_base;
>> +	day = time_delta / (24 * 60 * 60);
>> +	if (day > 0x7fff)
>> +		return -EINVAL;
>> +
>> +	rtd119x_rtc_set_enabled(dev, false);
>> +
>> +	writel_relaxed(tm->tm_sec,  data->base + RTD_RTCSEC);
>> +	writel_relaxed(tm->tm_min,  data->base + RTD_RTCMIN);
>> +	writel_relaxed(tm->tm_hour, data->base + RTD_RTCHR);
>> +	writel_relaxed(day & 0xff, data->base + RTD_RTCDATE_LOW);
>> +	writel_relaxed((day >> 8) & 0x7f, data->base + RTD_RTCDATE_HIGH);
>> +
>> +	rtd119x_rtc_set_enabled(dev, true);
>> +
>> +	return 0;
>> +}
>> +
>> +static int rtd119x_rtc_open(struct device *dev)
>> +{
>> +	struct rtd119x_rtc *data = dev_get_drvdata(dev);
>> +	u32 val;
>> +	int ret;
>> +
>> +	ret = clk_prepare_enable(data->clk);
>> +	if (ret)
>> +		return ret;
>> +
>> +	val = readl_relaxed(data->base + RTD_RTCACR);
>> +	dev_info(dev, "rtcacr = 0x%08x\n", val);
>> +	if (!(val & BIT(7))) {
>> +	}
> 
> I don't see the point of reading that register, and not doing anything
> with it.

Thanks for spotting this. The story is that the old downstream has code
for this case, but in my testing I didn't run into that path and forgot.
Explanations are largely missing in the vendor code. That code should
probably be added here in v2 and the dev_info() dropped, rather than
dropping the current no-op expression.

>> +
>> +	rtd119x_rtc_set_enabled(dev, true);
>> +
> 
> This is certainly not what you want. The RTC device is usually not
> opened so enabling the RTC when open and disabling it when closed will
> not work on most systems. This is probably true for the clock too. i.e
> what you do here should be done in probe.

I did test the probe path to work, but I can change it again. The
downstream code had it in probe, but looking at rtc_class_ops I saw
those hooks and thought they'd serve a purpose - what are they for then?
(Any chance you can improve the documentation comments to avoid such
misunderstandings? :))

>> +	return 0;
>> +}
[snip]

Regards,
Andreas

-- 
SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)



More information about the linux-arm-kernel mailing list