1/* 2 * RTC I/O Bridge interfaces for CSR SiRFprimaII 3 * ARM access the registers of SYSRTC, GPSRTC and PWRC through this module 4 * 5 * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. 6 * 7 * Licensed under GPLv2 or later. 8 */ 9 10#include <linux/kernel.h> 11#include <linux/module.h> 12#include <linux/io.h> 13#include <linux/of.h> 14#include <linux/of_address.h> 15#include <linux/of_device.h> 16#include <linux/of_platform.h> 17 18#define SIRFSOC_CPUIOBRG_CTRL 0x00 19#define SIRFSOC_CPUIOBRG_WRBE 0x04 20#define SIRFSOC_CPUIOBRG_ADDR 0x08 21#define SIRFSOC_CPUIOBRG_DATA 0x0c 22 23/* 24 * suspend asm codes will access this address to make system deepsleep 25 * after DRAM becomes self-refresh 26 */ 27void __iomem *sirfsoc_rtciobrg_base; 28static DEFINE_SPINLOCK(rtciobrg_lock); 29 30/* 31 * symbols without lock are only used by suspend asm codes 32 * and these symbols are not exported too 33 */ 34void sirfsoc_rtc_iobrg_wait_sync(void) 35{ 36 while (readl_relaxed(sirfsoc_rtciobrg_base + SIRFSOC_CPUIOBRG_CTRL)) 37 cpu_relax(); 38} 39 40void sirfsoc_rtc_iobrg_besyncing(void) 41{ 42 unsigned long flags; 43 44 spin_lock_irqsave(&rtciobrg_lock, flags); 45 46 sirfsoc_rtc_iobrg_wait_sync(); 47 48 spin_unlock_irqrestore(&rtciobrg_lock, flags); 49} 50EXPORT_SYMBOL_GPL(sirfsoc_rtc_iobrg_besyncing); 51 52u32 __sirfsoc_rtc_iobrg_readl(u32 addr) 53{ 54 sirfsoc_rtc_iobrg_wait_sync(); 55 56 writel_relaxed(0x00, sirfsoc_rtciobrg_base + SIRFSOC_CPUIOBRG_WRBE); 57 writel_relaxed(addr, sirfsoc_rtciobrg_base + SIRFSOC_CPUIOBRG_ADDR); 58 writel_relaxed(0x01, sirfsoc_rtciobrg_base + SIRFSOC_CPUIOBRG_CTRL); 59 60 sirfsoc_rtc_iobrg_wait_sync(); 61 62 return readl_relaxed(sirfsoc_rtciobrg_base + SIRFSOC_CPUIOBRG_DATA); 63} 64 65u32 sirfsoc_rtc_iobrg_readl(u32 addr) 66{ 67 unsigned long flags, val; 68 69 spin_lock_irqsave(&rtciobrg_lock, flags); 70 71 val = __sirfsoc_rtc_iobrg_readl(addr); 72 73 spin_unlock_irqrestore(&rtciobrg_lock, flags); 74 75 return val; 76} 77EXPORT_SYMBOL_GPL(sirfsoc_rtc_iobrg_readl); 78 79void sirfsoc_rtc_iobrg_pre_writel(u32 val, u32 addr) 80{ 81 sirfsoc_rtc_iobrg_wait_sync(); 82 83 writel_relaxed(0xf1, sirfsoc_rtciobrg_base + SIRFSOC_CPUIOBRG_WRBE); 84 writel_relaxed(addr, sirfsoc_rtciobrg_base + SIRFSOC_CPUIOBRG_ADDR); 85 86 writel_relaxed(val, sirfsoc_rtciobrg_base + SIRFSOC_CPUIOBRG_DATA); 87} 88 89void sirfsoc_rtc_iobrg_writel(u32 val, u32 addr) 90{ 91 unsigned long flags; 92 93 spin_lock_irqsave(&rtciobrg_lock, flags); 94 95 sirfsoc_rtc_iobrg_pre_writel(val, addr); 96 97 writel_relaxed(0x01, sirfsoc_rtciobrg_base + SIRFSOC_CPUIOBRG_CTRL); 98 99 sirfsoc_rtc_iobrg_wait_sync(); 100 101 spin_unlock_irqrestore(&rtciobrg_lock, flags); 102} 103EXPORT_SYMBOL_GPL(sirfsoc_rtc_iobrg_writel); 104 105static const struct of_device_id rtciobrg_ids[] = { 106 { .compatible = "sirf,prima2-rtciobg" }, 107 {} 108}; 109 110static int sirfsoc_rtciobrg_probe(struct platform_device *op) 111{ 112 struct device_node *np = op->dev.of_node; 113 114 sirfsoc_rtciobrg_base = of_iomap(np, 0); 115 if (!sirfsoc_rtciobrg_base) 116 panic("unable to map rtc iobrg registers\n"); 117 118 return 0; 119} 120 121static struct platform_driver sirfsoc_rtciobrg_driver = { 122 .probe = sirfsoc_rtciobrg_probe, 123 .driver = { 124 .name = "sirfsoc-rtciobrg", 125 .of_match_table = rtciobrg_ids, 126 }, 127}; 128 129static int __init sirfsoc_rtciobrg_init(void) 130{ 131 return platform_driver_register(&sirfsoc_rtciobrg_driver); 132} 133postcore_initcall(sirfsoc_rtciobrg_init); 134 135MODULE_AUTHOR("Zhiwu Song <zhiwu.song@csr.com>, " 136 "Barry Song <baohua.song@csr.com>"); 137MODULE_DESCRIPTION("CSR SiRFprimaII rtc io bridge"); 138MODULE_LICENSE("GPL v2"); 139