// SPDX-License-Identifier: GPL-2.0 /* * RTC driver for the interal RTC block in the Amlogic Meson6, Meson8, * Meson8b and Meson8m2 SoCs. * * The RTC is split in to two parts, the AHB front end and a simple serial * connection to the actual registers. This driver manages both parts. * * Copyright (c) 2018 Martin Blumenstingl <martin.blumenstingl@googlemail.com> * Copyright (c) 2015 Ben Dooks <ben.dooks@codethink.co.uk> for Codethink Ltd * Based on origin by Carlo Caione <carlo@endlessm.com>
*/
static u32 meson_rtc_get_data(struct meson_rtc *rtc)
{
u32 tmp, val = 0; int bit;
for (bit = 0; bit < RTC_DATA_BITS; bit++) {
meson_rtc_sclk_pulse(rtc);
val <<= 1;
regmap_read(rtc->peripheral, RTC_ADDR1, &tmp);
val |= tmp & RTC_ADDR1_SDO;
}
return val;
}
staticint meson_rtc_get_bus(struct meson_rtc *rtc)
{ int ret, retries;
u32 val;
/* prepare bus for transfers, set all lines low */
val = RTC_ADDR0_LINE_SDI | RTC_ADDR0_LINE_SEN | RTC_ADDR0_LINE_SCLK;
regmap_update_bits(rtc->peripheral, RTC_ADDR0, val, 0);
for (retries = 0; retries < 3; retries++) { /* wait for the bus to be ready */ if (!regmap_read_poll_timeout(rtc->peripheral, RTC_ADDR1, val,
val & RTC_ADDR1_S_READY, 10,
10000)) return 0;
dev_warn(rtc->dev, "failed to get bus, resetting RTC\n");
ret = reset_control_reset(rtc->reset); if (ret) return ret;
}
dev_err(rtc->dev, "bus is not ready\n"); return -ETIMEDOUT;
}
/* write the static value and start the auto serializer */
tmp = FIELD_PREP(RTC_ADDR0_DATA, (data & 0xff)) | RTC_ADDR0_START_SER;
regmap_update_bits(rtc->peripheral, RTC_ADDR0,
RTC_ADDR0_DATA | RTC_ADDR0_START_SER, tmp);
/* wait for the auto serializer to complete */ return regmap_read_poll_timeout(rtc->peripheral, RTC_REG4, tmp,
!(tmp & RTC_ADDR0_WAIT_SER), 10,
10000);
}
rtc->vdd = devm_regulator_get(dev, "vdd"); if (IS_ERR(rtc->vdd)) {
dev_err(dev, "failed to get the vdd-supply\n"); return PTR_ERR(rtc->vdd);
}
ret = regulator_enable(rtc->vdd); if (ret) {
dev_err(dev, "failed to enable vdd-supply\n"); return ret;
}
ret = meson_rtc_write_static(rtc, MESON_STATIC_DEFAULT); if (ret) {
dev_err(dev, "failed to set static values\n"); goto out_disable_vdd;
}
rtc->serial = devm_regmap_init(dev, &meson_rtc_serial_bus, rtc,
&meson_rtc_serial_regmap_config); if (IS_ERR(rtc->serial)) {
dev_err(dev, "failed to create serial regmap\n");
ret = PTR_ERR(rtc->serial); goto out_disable_vdd;
}
/* * check if we can read RTC counter, if not then the RTC is probably * not functional. If it isn't probably best to not bind.
*/
ret = regmap_read(rtc->serial, RTC_COUNTER, &tm); if (ret) {
dev_err(dev, "cannot read RTC counter, RTC not functional\n"); goto out_disable_vdd;
}
meson_rtc_nvmem_config.priv = rtc;
ret = devm_rtc_nvmem_register(rtc_dev, &meson_rtc_nvmem_config); if (ret) goto out_disable_vdd;
ret = devm_rtc_register_device(rtc_dev); if (ret) goto out_disable_vdd;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.