186559400SEmmanuel Gil Peyrot // SPDX-License-Identifier: GPL-2.0 286559400SEmmanuel Gil Peyrot /* 386559400SEmmanuel Gil Peyrot * Nintendo GameCube, Wii and Wii U RTC driver 486559400SEmmanuel Gil Peyrot * 586559400SEmmanuel Gil Peyrot * This driver is for the MX23L4005, more specifically its real-time clock and 686559400SEmmanuel Gil Peyrot * SRAM storage. The value returned by the RTC counter must be added with the 786559400SEmmanuel Gil Peyrot * offset stored in a bias register in SRAM (on the GameCube and Wii) or in 886559400SEmmanuel Gil Peyrot * /config/rtc.xml (on the Wii U). The latter being very impractical to access 986559400SEmmanuel Gil Peyrot * from Linux, this driver assumes the bootloader has read it and stored it in 1086559400SEmmanuel Gil Peyrot * SRAM like for the other two consoles. 1186559400SEmmanuel Gil Peyrot * 1286559400SEmmanuel Gil Peyrot * This device sits on a bus named EXI (which is similar to SPI), channel 0, 1386559400SEmmanuel Gil Peyrot * device 1. This driver assumes no other user of the EXI bus, which is 1486559400SEmmanuel Gil Peyrot * currently the case but would have to be reworked to add support for other 1586559400SEmmanuel Gil Peyrot * GameCube hardware exposed on this bus. 1686559400SEmmanuel Gil Peyrot * 1786559400SEmmanuel Gil Peyrot * References: 1886559400SEmmanuel Gil Peyrot * - https://wiiubrew.org/wiki/Hardware/RTC 1986559400SEmmanuel Gil Peyrot * - https://wiibrew.org/wiki/MX23L4005 2086559400SEmmanuel Gil Peyrot * 2186559400SEmmanuel Gil Peyrot * Copyright (C) 2018 rw-r-r-0644 2286559400SEmmanuel Gil Peyrot * Copyright (C) 2021 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr> 2386559400SEmmanuel Gil Peyrot * 2486559400SEmmanuel Gil Peyrot * Based on rtc-gcn.c 2586559400SEmmanuel Gil Peyrot * Copyright (C) 2004-2009 The GameCube Linux Team 2686559400SEmmanuel Gil Peyrot * Copyright (C) 2005,2008,2009 Albert Herranz 2786559400SEmmanuel Gil Peyrot * Based on gamecube_time.c from Torben Nielsen. 2886559400SEmmanuel Gil Peyrot */ 2986559400SEmmanuel Gil Peyrot 3086559400SEmmanuel Gil Peyrot #include <linux/init.h> 3186559400SEmmanuel Gil Peyrot #include <linux/module.h> 3286559400SEmmanuel Gil Peyrot #include <linux/of.h> 3386559400SEmmanuel Gil Peyrot #include <linux/of_address.h> 3486559400SEmmanuel Gil Peyrot #include <linux/platform_device.h> 3586559400SEmmanuel Gil Peyrot #include <linux/regmap.h> 3686559400SEmmanuel Gil Peyrot #include <linux/rtc.h> 3786559400SEmmanuel Gil Peyrot #include <linux/time.h> 3886559400SEmmanuel Gil Peyrot 3986559400SEmmanuel Gil Peyrot /* EXI registers */ 4086559400SEmmanuel Gil Peyrot #define EXICSR 0 4186559400SEmmanuel Gil Peyrot #define EXICR 12 4286559400SEmmanuel Gil Peyrot #define EXIDATA 16 4386559400SEmmanuel Gil Peyrot 4486559400SEmmanuel Gil Peyrot /* EXI register values */ 4586559400SEmmanuel Gil Peyrot #define EXICSR_DEV 0x380 4686559400SEmmanuel Gil Peyrot #define EXICSR_DEV1 0x100 4786559400SEmmanuel Gil Peyrot #define EXICSR_CLK 0x070 4886559400SEmmanuel Gil Peyrot #define EXICSR_CLK_1MHZ 0x000 4986559400SEmmanuel Gil Peyrot #define EXICSR_CLK_2MHZ 0x010 5086559400SEmmanuel Gil Peyrot #define EXICSR_CLK_4MHZ 0x020 5186559400SEmmanuel Gil Peyrot #define EXICSR_CLK_8MHZ 0x030 5286559400SEmmanuel Gil Peyrot #define EXICSR_CLK_16MHZ 0x040 5386559400SEmmanuel Gil Peyrot #define EXICSR_CLK_32MHZ 0x050 5486559400SEmmanuel Gil Peyrot #define EXICSR_INT 0x008 5586559400SEmmanuel Gil Peyrot #define EXICSR_INTSET 0x008 5686559400SEmmanuel Gil Peyrot 5786559400SEmmanuel Gil Peyrot #define EXICR_TSTART 0x001 5886559400SEmmanuel Gil Peyrot #define EXICR_TRSMODE 0x002 5986559400SEmmanuel Gil Peyrot #define EXICR_TRSMODE_IMM 0x000 6086559400SEmmanuel Gil Peyrot #define EXICR_TRSTYPE 0x00C 6186559400SEmmanuel Gil Peyrot #define EXICR_TRSTYPE_R 0x000 6286559400SEmmanuel Gil Peyrot #define EXICR_TRSTYPE_W 0x004 6386559400SEmmanuel Gil Peyrot #define EXICR_TLEN 0x030 6486559400SEmmanuel Gil Peyrot #define EXICR_TLEN32 0x030 6586559400SEmmanuel Gil Peyrot 6686559400SEmmanuel Gil Peyrot /* EXI registers values to access the RTC */ 6786559400SEmmanuel Gil Peyrot #define RTC_EXICSR (EXICSR_DEV1 | EXICSR_CLK_8MHZ | EXICSR_INTSET) 6886559400SEmmanuel Gil Peyrot #define RTC_EXICR_W (EXICR_TSTART | EXICR_TRSMODE_IMM | EXICR_TRSTYPE_W | EXICR_TLEN32) 6986559400SEmmanuel Gil Peyrot #define RTC_EXICR_R (EXICR_TSTART | EXICR_TRSMODE_IMM | EXICR_TRSTYPE_R | EXICR_TLEN32) 7086559400SEmmanuel Gil Peyrot #define RTC_EXIDATA_W 0x80000000 7186559400SEmmanuel Gil Peyrot 7286559400SEmmanuel Gil Peyrot /* RTC registers */ 7386559400SEmmanuel Gil Peyrot #define RTC_COUNTER 0x200000 7486559400SEmmanuel Gil Peyrot #define RTC_SRAM 0x200001 7586559400SEmmanuel Gil Peyrot #define RTC_SRAM_BIAS 0x200004 7686559400SEmmanuel Gil Peyrot #define RTC_SNAPSHOT 0x204000 7786559400SEmmanuel Gil Peyrot #define RTC_ONTMR 0x210000 7886559400SEmmanuel Gil Peyrot #define RTC_OFFTMR 0x210001 7986559400SEmmanuel Gil Peyrot #define RTC_TEST0 0x210004 8086559400SEmmanuel Gil Peyrot #define RTC_TEST1 0x210005 8186559400SEmmanuel Gil Peyrot #define RTC_TEST2 0x210006 8286559400SEmmanuel Gil Peyrot #define RTC_TEST3 0x210007 8386559400SEmmanuel Gil Peyrot #define RTC_CONTROL0 0x21000c 8486559400SEmmanuel Gil Peyrot #define RTC_CONTROL1 0x21000d 8586559400SEmmanuel Gil Peyrot 86*322539a0SEmmanuel Gil Peyrot /* RTC flags */ 87*322539a0SEmmanuel Gil Peyrot #define RTC_CONTROL0_UNSTABLE_POWER 0x00000800 88*322539a0SEmmanuel Gil Peyrot #define RTC_CONTROL0_LOW_BATTERY 0x00000200 89*322539a0SEmmanuel Gil Peyrot 9086559400SEmmanuel Gil Peyrot struct priv { 9186559400SEmmanuel Gil Peyrot struct regmap *regmap; 9286559400SEmmanuel Gil Peyrot void __iomem *iob; 9386559400SEmmanuel Gil Peyrot u32 rtc_bias; 9486559400SEmmanuel Gil Peyrot }; 9586559400SEmmanuel Gil Peyrot 9686559400SEmmanuel Gil Peyrot static int exi_read(void *context, u32 reg, u32 *data) 9786559400SEmmanuel Gil Peyrot { 9886559400SEmmanuel Gil Peyrot struct priv *d = (struct priv *)context; 9986559400SEmmanuel Gil Peyrot void __iomem *iob = d->iob; 10086559400SEmmanuel Gil Peyrot 10186559400SEmmanuel Gil Peyrot /* The spin loops here loop about 15~16 times each, so there is no need 10286559400SEmmanuel Gil Peyrot * to use a more expensive sleep method. 10386559400SEmmanuel Gil Peyrot */ 10486559400SEmmanuel Gil Peyrot 10586559400SEmmanuel Gil Peyrot /* Write register offset */ 10686559400SEmmanuel Gil Peyrot iowrite32be(RTC_EXICSR, iob + EXICSR); 10786559400SEmmanuel Gil Peyrot iowrite32be(reg << 8, iob + EXIDATA); 10886559400SEmmanuel Gil Peyrot iowrite32be(RTC_EXICR_W, iob + EXICR); 10986559400SEmmanuel Gil Peyrot while (!(ioread32be(iob + EXICSR) & EXICSR_INTSET)) 11086559400SEmmanuel Gil Peyrot cpu_relax(); 11186559400SEmmanuel Gil Peyrot 11286559400SEmmanuel Gil Peyrot /* Read data */ 11386559400SEmmanuel Gil Peyrot iowrite32be(RTC_EXICSR, iob + EXICSR); 11486559400SEmmanuel Gil Peyrot iowrite32be(RTC_EXICR_R, iob + EXICR); 11586559400SEmmanuel Gil Peyrot while (!(ioread32be(iob + EXICSR) & EXICSR_INTSET)) 11686559400SEmmanuel Gil Peyrot cpu_relax(); 11786559400SEmmanuel Gil Peyrot *data = ioread32be(iob + EXIDATA); 11886559400SEmmanuel Gil Peyrot 11986559400SEmmanuel Gil Peyrot /* Clear channel parameters */ 12086559400SEmmanuel Gil Peyrot iowrite32be(0, iob + EXICSR); 12186559400SEmmanuel Gil Peyrot 12286559400SEmmanuel Gil Peyrot return 0; 12386559400SEmmanuel Gil Peyrot } 12486559400SEmmanuel Gil Peyrot 12586559400SEmmanuel Gil Peyrot static int exi_write(void *context, u32 reg, u32 data) 12686559400SEmmanuel Gil Peyrot { 12786559400SEmmanuel Gil Peyrot struct priv *d = (struct priv *)context; 12886559400SEmmanuel Gil Peyrot void __iomem *iob = d->iob; 12986559400SEmmanuel Gil Peyrot 13086559400SEmmanuel Gil Peyrot /* The spin loops here loop about 15~16 times each, so there is no need 13186559400SEmmanuel Gil Peyrot * to use a more expensive sleep method. 13286559400SEmmanuel Gil Peyrot */ 13386559400SEmmanuel Gil Peyrot 13486559400SEmmanuel Gil Peyrot /* Write register offset */ 13586559400SEmmanuel Gil Peyrot iowrite32be(RTC_EXICSR, iob + EXICSR); 13686559400SEmmanuel Gil Peyrot iowrite32be(RTC_EXIDATA_W | (reg << 8), iob + EXIDATA); 13786559400SEmmanuel Gil Peyrot iowrite32be(RTC_EXICR_W, iob + EXICR); 13886559400SEmmanuel Gil Peyrot while (!(ioread32be(iob + EXICSR) & EXICSR_INTSET)) 13986559400SEmmanuel Gil Peyrot cpu_relax(); 14086559400SEmmanuel Gil Peyrot 14186559400SEmmanuel Gil Peyrot /* Write data */ 14286559400SEmmanuel Gil Peyrot iowrite32be(RTC_EXICSR, iob + EXICSR); 14386559400SEmmanuel Gil Peyrot iowrite32be(data, iob + EXIDATA); 14486559400SEmmanuel Gil Peyrot iowrite32be(RTC_EXICR_W, iob + EXICR); 14586559400SEmmanuel Gil Peyrot while (!(ioread32be(iob + EXICSR) & EXICSR_INTSET)) 14686559400SEmmanuel Gil Peyrot cpu_relax(); 14786559400SEmmanuel Gil Peyrot 14886559400SEmmanuel Gil Peyrot /* Clear channel parameters */ 14986559400SEmmanuel Gil Peyrot iowrite32be(0, iob + EXICSR); 15086559400SEmmanuel Gil Peyrot 15186559400SEmmanuel Gil Peyrot return 0; 15286559400SEmmanuel Gil Peyrot } 15386559400SEmmanuel Gil Peyrot 15486559400SEmmanuel Gil Peyrot static const struct regmap_bus exi_bus = { 15586559400SEmmanuel Gil Peyrot /* TODO: is that true? Not that it matters here, but still. */ 15686559400SEmmanuel Gil Peyrot .fast_io = true, 15786559400SEmmanuel Gil Peyrot .reg_read = exi_read, 15886559400SEmmanuel Gil Peyrot .reg_write = exi_write, 15986559400SEmmanuel Gil Peyrot }; 16086559400SEmmanuel Gil Peyrot 16186559400SEmmanuel Gil Peyrot static int gamecube_rtc_read_time(struct device *dev, struct rtc_time *t) 16286559400SEmmanuel Gil Peyrot { 16386559400SEmmanuel Gil Peyrot struct priv *d = dev_get_drvdata(dev); 16486559400SEmmanuel Gil Peyrot int ret; 16586559400SEmmanuel Gil Peyrot u32 counter; 16686559400SEmmanuel Gil Peyrot time64_t timestamp; 16786559400SEmmanuel Gil Peyrot 16886559400SEmmanuel Gil Peyrot ret = regmap_read(d->regmap, RTC_COUNTER, &counter); 16986559400SEmmanuel Gil Peyrot if (ret) 17086559400SEmmanuel Gil Peyrot return ret; 17186559400SEmmanuel Gil Peyrot 17286559400SEmmanuel Gil Peyrot /* Add the counter and the bias to obtain the timestamp */ 17386559400SEmmanuel Gil Peyrot timestamp = (time64_t)d->rtc_bias + counter; 17486559400SEmmanuel Gil Peyrot rtc_time64_to_tm(timestamp, t); 17586559400SEmmanuel Gil Peyrot 17686559400SEmmanuel Gil Peyrot return 0; 17786559400SEmmanuel Gil Peyrot } 17886559400SEmmanuel Gil Peyrot 17986559400SEmmanuel Gil Peyrot static int gamecube_rtc_set_time(struct device *dev, struct rtc_time *t) 18086559400SEmmanuel Gil Peyrot { 18186559400SEmmanuel Gil Peyrot struct priv *d = dev_get_drvdata(dev); 18286559400SEmmanuel Gil Peyrot time64_t timestamp; 18386559400SEmmanuel Gil Peyrot 18486559400SEmmanuel Gil Peyrot /* Subtract the timestamp and the bias to obtain the counter value */ 18586559400SEmmanuel Gil Peyrot timestamp = rtc_tm_to_time64(t); 18686559400SEmmanuel Gil Peyrot return regmap_write(d->regmap, RTC_COUNTER, timestamp - d->rtc_bias); 18786559400SEmmanuel Gil Peyrot } 18886559400SEmmanuel Gil Peyrot 189*322539a0SEmmanuel Gil Peyrot static int gamecube_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) 190*322539a0SEmmanuel Gil Peyrot { 191*322539a0SEmmanuel Gil Peyrot struct priv *d = dev_get_drvdata(dev); 192*322539a0SEmmanuel Gil Peyrot int value; 193*322539a0SEmmanuel Gil Peyrot int control0; 194*322539a0SEmmanuel Gil Peyrot int ret; 195*322539a0SEmmanuel Gil Peyrot 196*322539a0SEmmanuel Gil Peyrot switch (cmd) { 197*322539a0SEmmanuel Gil Peyrot case RTC_VL_READ: 198*322539a0SEmmanuel Gil Peyrot ret = regmap_read(d->regmap, RTC_CONTROL0, &control0); 199*322539a0SEmmanuel Gil Peyrot if (ret) 200*322539a0SEmmanuel Gil Peyrot return ret; 201*322539a0SEmmanuel Gil Peyrot 202*322539a0SEmmanuel Gil Peyrot value = 0; 203*322539a0SEmmanuel Gil Peyrot if (control0 & RTC_CONTROL0_UNSTABLE_POWER) 204*322539a0SEmmanuel Gil Peyrot value |= RTC_VL_DATA_INVALID; 205*322539a0SEmmanuel Gil Peyrot if (control0 & RTC_CONTROL0_LOW_BATTERY) 206*322539a0SEmmanuel Gil Peyrot value |= RTC_VL_BACKUP_LOW; 207*322539a0SEmmanuel Gil Peyrot return put_user(value, (unsigned int __user *)arg); 208*322539a0SEmmanuel Gil Peyrot 209*322539a0SEmmanuel Gil Peyrot default: 210*322539a0SEmmanuel Gil Peyrot return -ENOIOCTLCMD; 211*322539a0SEmmanuel Gil Peyrot } 212*322539a0SEmmanuel Gil Peyrot } 213*322539a0SEmmanuel Gil Peyrot 21486559400SEmmanuel Gil Peyrot static const struct rtc_class_ops gamecube_rtc_ops = { 21586559400SEmmanuel Gil Peyrot .read_time = gamecube_rtc_read_time, 21686559400SEmmanuel Gil Peyrot .set_time = gamecube_rtc_set_time, 217*322539a0SEmmanuel Gil Peyrot .ioctl = gamecube_rtc_ioctl, 21886559400SEmmanuel Gil Peyrot }; 21986559400SEmmanuel Gil Peyrot 22086559400SEmmanuel Gil Peyrot static int gamecube_rtc_read_offset_from_sram(struct priv *d) 22186559400SEmmanuel Gil Peyrot { 22286559400SEmmanuel Gil Peyrot struct device_node *np; 22386559400SEmmanuel Gil Peyrot int ret; 22486559400SEmmanuel Gil Peyrot struct resource res; 22586559400SEmmanuel Gil Peyrot void __iomem *hw_srnprot; 22686559400SEmmanuel Gil Peyrot u32 old; 22786559400SEmmanuel Gil Peyrot 22886559400SEmmanuel Gil Peyrot np = of_find_compatible_node(NULL, NULL, "nintendo,latte-srnprot"); 22986559400SEmmanuel Gil Peyrot if (!np) 23086559400SEmmanuel Gil Peyrot np = of_find_compatible_node(NULL, NULL, 23186559400SEmmanuel Gil Peyrot "nintendo,hollywood-srnprot"); 23286559400SEmmanuel Gil Peyrot if (!np) { 23386559400SEmmanuel Gil Peyrot pr_info("HW_SRNPROT not found, assuming a GameCube\n"); 23486559400SEmmanuel Gil Peyrot return regmap_read(d->regmap, RTC_SRAM_BIAS, &d->rtc_bias); 23586559400SEmmanuel Gil Peyrot } 23686559400SEmmanuel Gil Peyrot 23786559400SEmmanuel Gil Peyrot ret = of_address_to_resource(np, 0, &res); 23886559400SEmmanuel Gil Peyrot if (ret) { 23986559400SEmmanuel Gil Peyrot pr_err("no io memory range found\n"); 24086559400SEmmanuel Gil Peyrot return -1; 24186559400SEmmanuel Gil Peyrot } 24286559400SEmmanuel Gil Peyrot 24386559400SEmmanuel Gil Peyrot hw_srnprot = ioremap(res.start, resource_size(&res)); 24486559400SEmmanuel Gil Peyrot old = ioread32be(hw_srnprot); 24586559400SEmmanuel Gil Peyrot 24686559400SEmmanuel Gil Peyrot /* TODO: figure out why we use this magic constant. I obtained it by 24786559400SEmmanuel Gil Peyrot * reading the leftover value after boot, after IOSU already ran. 24886559400SEmmanuel Gil Peyrot * 24986559400SEmmanuel Gil Peyrot * On my Wii U, setting this register to 1 prevents the console from 25086559400SEmmanuel Gil Peyrot * rebooting properly, so wiiubrew.org must be missing something. 25186559400SEmmanuel Gil Peyrot * 25286559400SEmmanuel Gil Peyrot * See https://wiiubrew.org/wiki/Hardware/Latte_registers 25386559400SEmmanuel Gil Peyrot */ 25486559400SEmmanuel Gil Peyrot if (old != 0x7bf) 25586559400SEmmanuel Gil Peyrot iowrite32be(0x7bf, hw_srnprot); 25686559400SEmmanuel Gil Peyrot 25786559400SEmmanuel Gil Peyrot /* Get the offset from RTC SRAM. 25886559400SEmmanuel Gil Peyrot * 25986559400SEmmanuel Gil Peyrot * Its default location on the GameCube and on the Wii is in the SRAM, 26086559400SEmmanuel Gil Peyrot * while on the Wii U the bootloader needs to fill it with the contents 26186559400SEmmanuel Gil Peyrot * of /config/rtc.xml on the SLC (the eMMC). We don’t do that from 26286559400SEmmanuel Gil Peyrot * Linux since it requires implementing a proprietary filesystem and do 26386559400SEmmanuel Gil Peyrot * file decryption, instead we require the bootloader to fill the same 26486559400SEmmanuel Gil Peyrot * SRAM address as on previous consoles. 26586559400SEmmanuel Gil Peyrot */ 26686559400SEmmanuel Gil Peyrot ret = regmap_read(d->regmap, RTC_SRAM_BIAS, &d->rtc_bias); 26786559400SEmmanuel Gil Peyrot if (ret) { 26886559400SEmmanuel Gil Peyrot pr_err("failed to get the RTC bias\n"); 26986559400SEmmanuel Gil Peyrot return -1; 27086559400SEmmanuel Gil Peyrot } 27186559400SEmmanuel Gil Peyrot 27286559400SEmmanuel Gil Peyrot /* Reset SRAM access to how it was before, our job here is done. */ 27386559400SEmmanuel Gil Peyrot if (old != 0x7bf) 27486559400SEmmanuel Gil Peyrot iowrite32be(old, hw_srnprot); 27586559400SEmmanuel Gil Peyrot iounmap(hw_srnprot); 27686559400SEmmanuel Gil Peyrot 27786559400SEmmanuel Gil Peyrot return 0; 27886559400SEmmanuel Gil Peyrot } 27986559400SEmmanuel Gil Peyrot 28086559400SEmmanuel Gil Peyrot static const struct regmap_range rtc_rd_ranges[] = { 28186559400SEmmanuel Gil Peyrot regmap_reg_range(0x200000, 0x200010), 28286559400SEmmanuel Gil Peyrot regmap_reg_range(0x204000, 0x204000), 28386559400SEmmanuel Gil Peyrot regmap_reg_range(0x210000, 0x210001), 28486559400SEmmanuel Gil Peyrot regmap_reg_range(0x210004, 0x210007), 28586559400SEmmanuel Gil Peyrot regmap_reg_range(0x21000c, 0x21000d), 28686559400SEmmanuel Gil Peyrot }; 28786559400SEmmanuel Gil Peyrot 28886559400SEmmanuel Gil Peyrot static const struct regmap_access_table rtc_rd_regs = { 28986559400SEmmanuel Gil Peyrot .yes_ranges = rtc_rd_ranges, 29086559400SEmmanuel Gil Peyrot .n_yes_ranges = ARRAY_SIZE(rtc_rd_ranges), 29186559400SEmmanuel Gil Peyrot }; 29286559400SEmmanuel Gil Peyrot 29386559400SEmmanuel Gil Peyrot static const struct regmap_range rtc_wr_ranges[] = { 29486559400SEmmanuel Gil Peyrot regmap_reg_range(0x200000, 0x200010), 29586559400SEmmanuel Gil Peyrot regmap_reg_range(0x204000, 0x204000), 29686559400SEmmanuel Gil Peyrot regmap_reg_range(0x210000, 0x210001), 29786559400SEmmanuel Gil Peyrot regmap_reg_range(0x21000d, 0x21000d), 29886559400SEmmanuel Gil Peyrot }; 29986559400SEmmanuel Gil Peyrot 30086559400SEmmanuel Gil Peyrot static const struct regmap_access_table rtc_wr_regs = { 30186559400SEmmanuel Gil Peyrot .yes_ranges = rtc_wr_ranges, 30286559400SEmmanuel Gil Peyrot .n_yes_ranges = ARRAY_SIZE(rtc_wr_ranges), 30386559400SEmmanuel Gil Peyrot }; 30486559400SEmmanuel Gil Peyrot 30586559400SEmmanuel Gil Peyrot static const struct regmap_config gamecube_rtc_regmap_config = { 30686559400SEmmanuel Gil Peyrot .reg_bits = 24, 30786559400SEmmanuel Gil Peyrot .val_bits = 32, 30886559400SEmmanuel Gil Peyrot .rd_table = &rtc_rd_regs, 30986559400SEmmanuel Gil Peyrot .wr_table = &rtc_wr_regs, 31086559400SEmmanuel Gil Peyrot .max_register = 0x21000d, 31186559400SEmmanuel Gil Peyrot .name = "gamecube-rtc", 31286559400SEmmanuel Gil Peyrot }; 31386559400SEmmanuel Gil Peyrot 31486559400SEmmanuel Gil Peyrot static int gamecube_rtc_probe(struct platform_device *pdev) 31586559400SEmmanuel Gil Peyrot { 31686559400SEmmanuel Gil Peyrot struct device *dev = &pdev->dev; 31786559400SEmmanuel Gil Peyrot struct rtc_device *rtc; 31886559400SEmmanuel Gil Peyrot struct priv *d; 31986559400SEmmanuel Gil Peyrot int ret; 32086559400SEmmanuel Gil Peyrot 32186559400SEmmanuel Gil Peyrot d = devm_kzalloc(dev, sizeof(struct priv), GFP_KERNEL); 32286559400SEmmanuel Gil Peyrot if (IS_ERR(d)) 32386559400SEmmanuel Gil Peyrot return PTR_ERR(d); 32486559400SEmmanuel Gil Peyrot 32586559400SEmmanuel Gil Peyrot d->iob = devm_platform_ioremap_resource(pdev, 0); 32686559400SEmmanuel Gil Peyrot if (IS_ERR(d->iob)) 32786559400SEmmanuel Gil Peyrot return PTR_ERR(d->iob); 32886559400SEmmanuel Gil Peyrot 32986559400SEmmanuel Gil Peyrot d->regmap = devm_regmap_init(dev, &exi_bus, d, 33086559400SEmmanuel Gil Peyrot &gamecube_rtc_regmap_config); 33186559400SEmmanuel Gil Peyrot if (IS_ERR(d->regmap)) 33286559400SEmmanuel Gil Peyrot return PTR_ERR(d->regmap); 33386559400SEmmanuel Gil Peyrot 33486559400SEmmanuel Gil Peyrot ret = gamecube_rtc_read_offset_from_sram(d); 33586559400SEmmanuel Gil Peyrot if (ret) 33686559400SEmmanuel Gil Peyrot return ret; 33786559400SEmmanuel Gil Peyrot dev_dbg(dev, "SRAM bias: 0x%x", d->rtc_bias); 33886559400SEmmanuel Gil Peyrot 33986559400SEmmanuel Gil Peyrot dev_set_drvdata(dev, d); 34086559400SEmmanuel Gil Peyrot 34186559400SEmmanuel Gil Peyrot rtc = devm_rtc_allocate_device(dev); 34286559400SEmmanuel Gil Peyrot if (IS_ERR(rtc)) 34386559400SEmmanuel Gil Peyrot return PTR_ERR(rtc); 34486559400SEmmanuel Gil Peyrot 34586559400SEmmanuel Gil Peyrot /* We can represent further than that, but it depends on the stored 34686559400SEmmanuel Gil Peyrot * bias and we can’t modify it persistently on all supported consoles, 34786559400SEmmanuel Gil Peyrot * so here we pretend to be limited to 2106. 34886559400SEmmanuel Gil Peyrot */ 34986559400SEmmanuel Gil Peyrot rtc->range_min = 0; 35086559400SEmmanuel Gil Peyrot rtc->range_max = U32_MAX; 35186559400SEmmanuel Gil Peyrot rtc->ops = &gamecube_rtc_ops; 35286559400SEmmanuel Gil Peyrot 35386559400SEmmanuel Gil Peyrot devm_rtc_register_device(rtc); 35486559400SEmmanuel Gil Peyrot 35586559400SEmmanuel Gil Peyrot return 0; 35686559400SEmmanuel Gil Peyrot } 35786559400SEmmanuel Gil Peyrot 35886559400SEmmanuel Gil Peyrot static const struct of_device_id gamecube_rtc_of_match[] = { 35986559400SEmmanuel Gil Peyrot {.compatible = "nintendo,latte-exi" }, 36086559400SEmmanuel Gil Peyrot {.compatible = "nintendo,hollywood-exi" }, 36186559400SEmmanuel Gil Peyrot {.compatible = "nintendo,flipper-exi" }, 36286559400SEmmanuel Gil Peyrot { } 36386559400SEmmanuel Gil Peyrot }; 36486559400SEmmanuel Gil Peyrot MODULE_DEVICE_TABLE(of, gamecube_rtc_of_match); 36586559400SEmmanuel Gil Peyrot 36686559400SEmmanuel Gil Peyrot static struct platform_driver gamecube_rtc_driver = { 36786559400SEmmanuel Gil Peyrot .probe = gamecube_rtc_probe, 36886559400SEmmanuel Gil Peyrot .driver = { 36986559400SEmmanuel Gil Peyrot .name = "rtc-gamecube", 37086559400SEmmanuel Gil Peyrot .of_match_table = gamecube_rtc_of_match, 37186559400SEmmanuel Gil Peyrot }, 37286559400SEmmanuel Gil Peyrot }; 37386559400SEmmanuel Gil Peyrot module_platform_driver(gamecube_rtc_driver); 37486559400SEmmanuel Gil Peyrot 37586559400SEmmanuel Gil Peyrot MODULE_AUTHOR("Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>"); 37686559400SEmmanuel Gil Peyrot MODULE_DESCRIPTION("Nintendo GameCube, Wii and Wii U RTC driver"); 37786559400SEmmanuel Gil Peyrot MODULE_LICENSE("GPL"); 378