Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

rtc: support for the Amlogic Meson RTC

Add support for the RTC block on the 32-bit Amlogic Meson6, Meson8,
Meson8b and Meson8m2 SoCs.

The RTC is split in to two parts, which are both managed by this driver:
- the AHB front end
- and a simple serial connection to the actual registers

The RTC_COUNTER register which holds the time is 32-bits wide.

There are four 32-bit wide (in total: 16 bytes) "regmem" registers which
are exposed using nvmem. On Amlogic's 3.10 kernel this is used to store
data which needs to survive a suspend / resume cycle.

Signed-off-by: Ben Dooks <ben.dooks@codethink.co.uk>
[resurrected Ben's patches after 2 years]
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>

authored by

Martin Blumenstingl and committed by
Alexandre Belloni
d8fe6009 1366e010

+422
+11
drivers/rtc/Kconfig
··· 1294 1294 This driver can also be built as a module, if so, the module 1295 1295 will be called "rtc-imxdi". 1296 1296 1297 + config RTC_DRV_MESON 1298 + tristate "Amlogic Meson RTC" 1299 + depends on (ARM && ARCH_MESON) || COMPILE_TEST 1300 + select REGMAP_MMIO 1301 + help 1302 + Support for the RTC block on the Amlogic Meson6, Meson8, Meson8b 1303 + and Meson8m2 SoCs. 1304 + 1305 + This driver can also be built as a module, if so, the module 1306 + will be called "rtc-meson". 1307 + 1297 1308 config RTC_DRV_OMAP 1298 1309 tristate "TI OMAP Real Time Clock" 1299 1310 depends on ARCH_OMAP || ARCH_DAVINCI || COMPILE_TEST
+1
drivers/rtc/Makefile
··· 101 101 obj-$(CONFIG_RTC_DRV_MAX8998) += rtc-max8998.o 102 102 obj-$(CONFIG_RTC_DRV_MC13XXX) += rtc-mc13xxx.o 103 103 obj-$(CONFIG_RTC_DRV_MCP795) += rtc-mcp795.o 104 + obj-$(CONFIG_RTC_DRV_MESON) += rtc-meson.o 104 105 obj-$(CONFIG_RTC_DRV_MOXART) += rtc-moxart.o 105 106 obj-$(CONFIG_RTC_DRV_MPC5121) += rtc-mpc5121.o 106 107 obj-$(CONFIG_RTC_DRV_MSM6242) += rtc-msm6242.o
+410
drivers/rtc/rtc-meson.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * RTC driver for the interal RTC block in the Amlogic Meson6, Meson8, 4 + * Meson8b and Meson8m2 SoCs. 5 + * 6 + * The RTC is split in to two parts, the AHB front end and a simple serial 7 + * connection to the actual registers. This driver manages both parts. 8 + * 9 + * Copyright (c) 2018 Martin Blumenstingl <martin.blumenstingl@googlemail.com> 10 + * Copyright (c) 2015 Ben Dooks <ben.dooks@codethink.co.uk> for Codethink Ltd 11 + * Based on origin by Carlo Caione <carlo@endlessm.com> 12 + */ 13 + 14 + #include <linux/bitfield.h> 15 + #include <linux/delay.h> 16 + #include <linux/io.h> 17 + #include <linux/kernel.h> 18 + #include <linux/module.h> 19 + #include <linux/nvmem-provider.h> 20 + #include <linux/of.h> 21 + #include <linux/platform_device.h> 22 + #include <linux/regmap.h> 23 + #include <linux/regulator/consumer.h> 24 + #include <linux/reset.h> 25 + #include <linux/rtc.h> 26 + 27 + /* registers accessed from cpu bus */ 28 + #define RTC_ADDR0 0x00 29 + #define RTC_ADDR0_LINE_SCLK BIT(0) 30 + #define RTC_ADDR0_LINE_SEN BIT(1) 31 + #define RTC_ADDR0_LINE_SDI BIT(2) 32 + #define RTC_ADDR0_START_SER BIT(17) 33 + #define RTC_ADDR0_WAIT_SER BIT(22) 34 + #define RTC_ADDR0_DATA GENMASK(31, 24) 35 + 36 + #define RTC_ADDR1 0x04 37 + #define RTC_ADDR1_SDO BIT(0) 38 + #define RTC_ADDR1_S_READY BIT(1) 39 + 40 + #define RTC_ADDR2 0x08 41 + #define RTC_ADDR3 0x0c 42 + 43 + #define RTC_REG4 0x10 44 + #define RTC_REG4_STATIC_VALUE GENMASK(7, 0) 45 + 46 + /* rtc registers accessed via rtc-serial interface */ 47 + #define RTC_COUNTER (0) 48 + #define RTC_SEC_ADJ (2) 49 + #define RTC_REGMEM_0 (4) 50 + #define RTC_REGMEM_1 (5) 51 + #define RTC_REGMEM_2 (6) 52 + #define RTC_REGMEM_3 (7) 53 + 54 + #define RTC_ADDR_BITS (3) /* number of address bits to send */ 55 + #define RTC_DATA_BITS (32) /* number of data bits to tx/rx */ 56 + 57 + #define MESON_STATIC_BIAS_CUR (0x5 << 1) 58 + #define MESON_STATIC_VOLTAGE (0x3 << 11) 59 + #define MESON_STATIC_DEFAULT (MESON_STATIC_BIAS_CUR | MESON_STATIC_VOLTAGE) 60 + 61 + struct meson_rtc { 62 + struct rtc_device *rtc; /* rtc device we created */ 63 + struct device *dev; /* device we bound from */ 64 + struct reset_control *reset; /* reset source */ 65 + struct regulator *vdd; /* voltage input */ 66 + struct regmap *peripheral; /* peripheral registers */ 67 + struct regmap *serial; /* serial registers */ 68 + }; 69 + 70 + static const struct regmap_config meson_rtc_peripheral_regmap_config = { 71 + .name = "peripheral-registers", 72 + .reg_bits = 8, 73 + .val_bits = 32, 74 + .reg_stride = 4, 75 + .max_register = RTC_REG4, 76 + .fast_io = true, 77 + }; 78 + 79 + /* RTC front-end serialiser controls */ 80 + 81 + static void meson_rtc_sclk_pulse(struct meson_rtc *rtc) 82 + { 83 + udelay(5); 84 + regmap_update_bits(rtc->peripheral, RTC_ADDR0, RTC_ADDR0_LINE_SCLK, 0); 85 + udelay(5); 86 + regmap_update_bits(rtc->peripheral, RTC_ADDR0, RTC_ADDR0_LINE_SCLK, 87 + RTC_ADDR0_LINE_SCLK); 88 + } 89 + 90 + static void meson_rtc_send_bit(struct meson_rtc *rtc, unsigned int bit) 91 + { 92 + regmap_update_bits(rtc->peripheral, RTC_ADDR0, RTC_ADDR0_LINE_SDI, 93 + bit ? RTC_ADDR0_LINE_SDI : 0); 94 + meson_rtc_sclk_pulse(rtc); 95 + } 96 + 97 + static void meson_rtc_send_bits(struct meson_rtc *rtc, u32 data, 98 + unsigned int nr) 99 + { 100 + u32 bit = 1 << (nr - 1); 101 + 102 + while (bit) { 103 + meson_rtc_send_bit(rtc, data & bit); 104 + bit >>= 1; 105 + } 106 + } 107 + 108 + static void meson_rtc_set_dir(struct meson_rtc *rtc, u32 mode) 109 + { 110 + regmap_update_bits(rtc->peripheral, RTC_ADDR0, RTC_ADDR0_LINE_SEN, 0); 111 + regmap_update_bits(rtc->peripheral, RTC_ADDR0, RTC_ADDR0_LINE_SDI, 0); 112 + meson_rtc_send_bit(rtc, mode); 113 + regmap_update_bits(rtc->peripheral, RTC_ADDR0, RTC_ADDR0_LINE_SDI, 0); 114 + } 115 + 116 + static u32 meson_rtc_get_data(struct meson_rtc *rtc) 117 + { 118 + u32 tmp, val = 0; 119 + int bit; 120 + 121 + for (bit = 0; bit < RTC_DATA_BITS; bit++) { 122 + meson_rtc_sclk_pulse(rtc); 123 + val <<= 1; 124 + 125 + regmap_read(rtc->peripheral, RTC_ADDR1, &tmp); 126 + val |= tmp & RTC_ADDR1_SDO; 127 + } 128 + 129 + return val; 130 + } 131 + 132 + static int meson_rtc_get_bus(struct meson_rtc *rtc) 133 + { 134 + int ret, retries = 3; 135 + u32 val; 136 + 137 + /* prepare bus for transfers, set all lines low */ 138 + val = RTC_ADDR0_LINE_SDI | RTC_ADDR0_LINE_SEN | RTC_ADDR0_LINE_SCLK; 139 + regmap_update_bits(rtc->peripheral, RTC_ADDR0, val, 0); 140 + 141 + for (retries = 0; retries < 3; retries++) { 142 + /* wait for the bus to be ready */ 143 + if (!regmap_read_poll_timeout(rtc->peripheral, RTC_ADDR1, val, 144 + val & RTC_ADDR1_S_READY, 10, 145 + 10000)) 146 + return 0; 147 + 148 + dev_warn(rtc->dev, "failed to get bus, resetting RTC\n"); 149 + 150 + ret = reset_control_reset(rtc->reset); 151 + if (ret) 152 + return ret; 153 + } 154 + 155 + dev_err(rtc->dev, "bus is not ready\n"); 156 + return -ETIMEDOUT; 157 + } 158 + 159 + static int meson_rtc_serial_bus_reg_read(void *context, unsigned int reg, 160 + unsigned int *data) 161 + { 162 + struct meson_rtc *rtc = context; 163 + int ret; 164 + 165 + ret = meson_rtc_get_bus(rtc); 166 + if (ret) 167 + return ret; 168 + 169 + regmap_update_bits(rtc->peripheral, RTC_ADDR0, RTC_ADDR0_LINE_SEN, 170 + RTC_ADDR0_LINE_SEN); 171 + meson_rtc_send_bits(rtc, reg, RTC_ADDR_BITS); 172 + meson_rtc_set_dir(rtc, 0); 173 + *data = meson_rtc_get_data(rtc); 174 + 175 + return 0; 176 + } 177 + 178 + static int meson_rtc_serial_bus_reg_write(void *context, unsigned int reg, 179 + unsigned int data) 180 + { 181 + struct meson_rtc *rtc = context; 182 + int ret; 183 + 184 + ret = meson_rtc_get_bus(rtc); 185 + if (ret) 186 + return ret; 187 + 188 + regmap_update_bits(rtc->peripheral, RTC_ADDR0, RTC_ADDR0_LINE_SEN, 189 + RTC_ADDR0_LINE_SEN); 190 + meson_rtc_send_bits(rtc, data, RTC_DATA_BITS); 191 + meson_rtc_send_bits(rtc, reg, RTC_ADDR_BITS); 192 + meson_rtc_set_dir(rtc, 1); 193 + 194 + return 0; 195 + } 196 + 197 + static const struct regmap_bus meson_rtc_serial_bus = { 198 + .reg_read = meson_rtc_serial_bus_reg_read, 199 + .reg_write = meson_rtc_serial_bus_reg_write, 200 + }; 201 + 202 + static const struct regmap_config meson_rtc_serial_regmap_config = { 203 + .name = "serial-registers", 204 + .reg_bits = 4, 205 + .reg_stride = 1, 206 + .val_bits = 32, 207 + .max_register = RTC_REGMEM_3, 208 + .fast_io = false, 209 + }; 210 + 211 + static int meson_rtc_write_static(struct meson_rtc *rtc, u32 data) 212 + { 213 + u32 tmp; 214 + 215 + regmap_write(rtc->peripheral, RTC_REG4, 216 + FIELD_PREP(RTC_REG4_STATIC_VALUE, (data >> 8))); 217 + 218 + /* write the static value and start the auto serializer */ 219 + tmp = FIELD_PREP(RTC_ADDR0_DATA, (data & 0xff)) | RTC_ADDR0_START_SER; 220 + regmap_update_bits(rtc->peripheral, RTC_ADDR0, 221 + RTC_ADDR0_DATA | RTC_ADDR0_START_SER, tmp); 222 + 223 + /* wait for the auto serializer to complete */ 224 + return regmap_read_poll_timeout(rtc->peripheral, RTC_REG4, tmp, 225 + !(tmp & RTC_ADDR0_WAIT_SER), 10, 226 + 10000); 227 + } 228 + 229 + /* RTC interface layer functions */ 230 + 231 + static int meson_rtc_gettime(struct device *dev, struct rtc_time *tm) 232 + { 233 + struct meson_rtc *rtc = dev_get_drvdata(dev); 234 + u32 time; 235 + int ret; 236 + 237 + ret = regmap_read(rtc->serial, RTC_COUNTER, &time); 238 + if (!ret) 239 + rtc_time64_to_tm(time, tm); 240 + 241 + return ret; 242 + } 243 + 244 + static int meson_rtc_settime(struct device *dev, struct rtc_time *tm) 245 + { 246 + struct meson_rtc *rtc = dev_get_drvdata(dev); 247 + 248 + return regmap_write(rtc->serial, RTC_COUNTER, rtc_tm_to_time64(tm)); 249 + } 250 + 251 + static const struct rtc_class_ops meson_rtc_ops = { 252 + .read_time = meson_rtc_gettime, 253 + .set_time = meson_rtc_settime, 254 + }; 255 + 256 + /* NVMEM interface layer functions */ 257 + 258 + static int meson_rtc_regmem_read(void *context, unsigned int offset, 259 + void *buf, size_t bytes) 260 + { 261 + struct meson_rtc *rtc = context; 262 + unsigned int read_offset, read_size; 263 + 264 + read_offset = RTC_REGMEM_0 + (offset / 4); 265 + read_size = bytes / 4; 266 + 267 + return regmap_bulk_read(rtc->serial, read_offset, buf, read_size); 268 + } 269 + 270 + static int meson_rtc_regmem_write(void *context, unsigned int offset, 271 + void *buf, size_t bytes) 272 + { 273 + struct meson_rtc *rtc = context; 274 + unsigned int write_offset, write_size; 275 + 276 + write_offset = RTC_REGMEM_0 + (offset / 4); 277 + write_size = bytes / 4; 278 + 279 + return regmap_bulk_write(rtc->serial, write_offset, buf, write_size); 280 + } 281 + 282 + static int meson_rtc_probe(struct platform_device *pdev) 283 + { 284 + struct nvmem_config meson_rtc_nvmem_config = { 285 + .name = "meson-rtc-regmem", 286 + .type = NVMEM_TYPE_BATTERY_BACKED, 287 + .word_size = 4, 288 + .stride = 4, 289 + .size = 4 * 4, 290 + .reg_read = meson_rtc_regmem_read, 291 + .reg_write = meson_rtc_regmem_write, 292 + }; 293 + struct device *dev = &pdev->dev; 294 + struct meson_rtc *rtc; 295 + struct resource *res; 296 + void __iomem *base; 297 + int ret; 298 + u32 tm; 299 + 300 + rtc = devm_kzalloc(dev, sizeof(struct meson_rtc), GFP_KERNEL); 301 + if (!rtc) 302 + return -ENOMEM; 303 + 304 + rtc->rtc = devm_rtc_allocate_device(dev); 305 + if (IS_ERR(rtc->rtc)) 306 + return PTR_ERR(rtc->rtc); 307 + 308 + platform_set_drvdata(pdev, rtc); 309 + 310 + rtc->dev = dev; 311 + 312 + rtc->rtc->ops = &meson_rtc_ops; 313 + rtc->rtc->range_max = U32_MAX; 314 + 315 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 316 + base = devm_ioremap_resource(dev, res); 317 + if (IS_ERR(base)) 318 + return PTR_ERR(base); 319 + 320 + rtc->peripheral = devm_regmap_init_mmio(dev, base, 321 + &meson_rtc_peripheral_regmap_config); 322 + if (IS_ERR(rtc->peripheral)) { 323 + dev_err(dev, "failed to create peripheral regmap\n"); 324 + return PTR_ERR(rtc->peripheral); 325 + } 326 + 327 + rtc->reset = devm_reset_control_get(dev, NULL); 328 + if (IS_ERR(rtc->reset)) { 329 + dev_err(dev, "missing reset line\n"); 330 + return PTR_ERR(rtc->reset); 331 + } 332 + 333 + rtc->vdd = devm_regulator_get(dev, "vdd"); 334 + if (IS_ERR(rtc->vdd)) { 335 + dev_err(dev, "failed to get the vdd-supply\n"); 336 + return PTR_ERR(rtc->vdd); 337 + } 338 + 339 + ret = regulator_enable(rtc->vdd); 340 + if (ret) { 341 + dev_err(dev, "failed to enable vdd-supply\n"); 342 + return ret; 343 + } 344 + 345 + ret = meson_rtc_write_static(rtc, MESON_STATIC_DEFAULT); 346 + if (ret) { 347 + dev_err(dev, "failed to set static values\n"); 348 + goto out_disable_vdd; 349 + } 350 + 351 + rtc->serial = devm_regmap_init(dev, &meson_rtc_serial_bus, rtc, 352 + &meson_rtc_serial_regmap_config); 353 + if (IS_ERR(rtc->serial)) { 354 + dev_err(dev, "failed to create serial regmap\n"); 355 + ret = PTR_ERR(rtc->serial); 356 + goto out_disable_vdd; 357 + } 358 + 359 + /* 360 + * check if we can read RTC counter, if not then the RTC is probably 361 + * not functional. If it isn't probably best to not bind. 362 + */ 363 + ret = regmap_read(rtc->serial, RTC_COUNTER, &tm); 364 + if (ret) { 365 + dev_err(dev, "cannot read RTC counter, RTC not functional\n"); 366 + goto out_disable_vdd; 367 + } 368 + 369 + meson_rtc_nvmem_config.priv = rtc; 370 + ret = rtc_nvmem_register(rtc->rtc, &meson_rtc_nvmem_config); 371 + if (ret) 372 + goto out_disable_vdd; 373 + 374 + ret = rtc_register_device(rtc->rtc); 375 + if (ret) 376 + goto out_unregister_nvmem; 377 + 378 + return 0; 379 + 380 + out_unregister_nvmem: 381 + rtc_nvmem_unregister(rtc->rtc); 382 + 383 + out_disable_vdd: 384 + regulator_disable(rtc->vdd); 385 + return ret; 386 + } 387 + 388 + static const struct of_device_id meson_rtc_dt_match[] = { 389 + { .compatible = "amlogic,meson6-rtc", }, 390 + { .compatible = "amlogic,meson8-rtc", }, 391 + { .compatible = "amlogic,meson8b-rtc", }, 392 + { .compatible = "amlogic,meson8m2-rtc", }, 393 + { }, 394 + }; 395 + MODULE_DEVICE_TABLE(of, meson_rtc_dt_match); 396 + 397 + static struct platform_driver meson_rtc_driver = { 398 + .probe = meson_rtc_probe, 399 + .driver = { 400 + .name = "meson-rtc", 401 + .of_match_table = of_match_ptr(meson_rtc_dt_match), 402 + }, 403 + }; 404 + module_platform_driver(meson_rtc_driver); 405 + 406 + MODULE_DESCRIPTION("Amlogic Meson RTC Driver"); 407 + MODULE_AUTHOR("Ben Dooks <ben.doosk@codethink.co.uk>"); 408 + MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>"); 409 + MODULE_LICENSE("GPL v2"); 410 + MODULE_ALIAS("platform:meson-rtc");