1 /* $NetBSD: rs5c316_mainbus.c,v 1.1 2010/04/06 15:54:29 nonaka Exp $ */ 2 3 /*- 4 * Copyright (c) 2009 NONAKA Kimihiro <nonaka@netbsd.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: rs5c316_mainbus.c,v 1.1 2010/04/06 15:54:29 nonaka Exp $"); 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/device.h> 35 #include <sys/kernel.h> 36 37 #include <dev/clock_subr.h> 38 #include <dev/ic/rs5c313var.h> 39 40 #include <machine/autoconf.h> 41 42 #include <sh3/devreg.h> 43 #include <sh3/pfcreg.h> 44 45 #include <evbsh3/ap_ms104_sh4/ap_ms104_sh4reg.h> 46 #include <evbsh3/ap_ms104_sh4/ap_ms104_sh4var.h> 47 48 /* chip access methods */ 49 static void rtc_begin(struct rs5c313_softc *); 50 static void rtc_ce(struct rs5c313_softc *, int); 51 static void rtc_dir(struct rs5c313_softc *, int); 52 static void rtc_clk(struct rs5c313_softc *, int); 53 static int rtc_read(struct rs5c313_softc *); 54 static void rtc_write(struct rs5c313_softc *, int); 55 56 static struct rs5c313_ops rs5c316_mainbus_ops = { 57 .rs5c313_op_begin = rtc_begin, 58 .rs5c313_op_ce = rtc_ce, 59 .rs5c313_op_clk = rtc_clk, 60 .rs5c313_op_dir = rtc_dir, 61 .rs5c313_op_read = rtc_read, 62 .rs5c313_op_write = rtc_write, 63 }; 64 65 /* autoconf glue */ 66 static int rs5c316_mainbus_match(device_t, cfdata_t, void *); 67 static void rs5c316_mainbus_attach(device_t, device_t, void *); 68 69 CFATTACH_DECL_NEW(rs5c313_mainbus, sizeof(struct rs5c313_softc), 70 rs5c316_mainbus_match, rs5c316_mainbus_attach, NULL, NULL); 71 72 #define ndelay(x) delay(((x) + 999) / 1000) 73 74 static int 75 rs5c316_mainbus_match(device_t parent, cfdata_t cf, void *aux) 76 { 77 struct mainbus_attach_args *maa = (struct mainbus_attach_args *)aux; 78 79 if (strcmp(maa->ma_name, "rs5c313rtc") != 0) 80 return 0; 81 return 1; 82 } 83 84 85 static void 86 rs5c316_mainbus_attach(device_t parent, device_t self, void *aux) 87 { 88 struct rs5c313_softc *sc = device_private(self); 89 uint32_t reg; 90 91 sc->sc_dev = self; 92 sc->sc_model = MODEL_5C316; 93 sc->sc_ops = &rs5c316_mainbus_ops; 94 95 /* setup gpio pin */ 96 reg = _reg_read_4(SH4_PCTRA); 97 reg &= ~(3 << (GPIO_PIN_RTC_CE * 2)); 98 reg |= (1 << (GPIO_PIN_RTC_CE * 2)); /* output */ 99 reg &= ~(3 << (GPIO_PIN_RTC_SCLK * 2)); 100 reg |= (1 << (GPIO_PIN_RTC_SCLK * 2)); /* output */ 101 reg &= ~(3 << (GPIO_PIN_RTC_SIO * 2)); 102 reg |= (1 << (GPIO_PIN_RTC_SIO * 2)); /* output */ 103 _reg_write_4(SH4_PCTRA, reg); 104 105 rs5c313_attach(sc); 106 } 107 108 static void 109 rtc_begin(struct rs5c313_softc *sc) 110 { 111 112 /* nothing to do */ 113 } 114 115 static void 116 rtc_ce(struct rs5c313_softc *sc, int onoff) 117 { 118 uint16_t 119 120 reg = _reg_read_2(SH4_PDTRA); 121 if (onoff) { 122 reg |= (1 << GPIO_PIN_RTC_CE); 123 } else { 124 reg &= ~(1 << GPIO_PIN_RTC_CE); 125 } 126 _reg_write_2(SH4_PDTRA, reg); 127 ndelay(600); 128 } 129 130 static void 131 rtc_clk(struct rs5c313_softc *sc, int onoff) 132 { 133 uint16_t reg; 134 135 reg = _reg_read_2(SH4_PDTRA); 136 if (onoff) { 137 reg |= (1 << GPIO_PIN_RTC_SCLK); 138 } else { 139 reg &= ~(1 << GPIO_PIN_RTC_SCLK); 140 } 141 _reg_write_2(SH4_PDTRA, reg); 142 } 143 144 static void 145 rtc_dir(struct rs5c313_softc *sc, int output) 146 { 147 uint32_t reg; 148 149 reg = _reg_read_4(SH4_PCTRA); 150 reg &= ~(3 << (GPIO_PIN_RTC_SIO * 2)); /* input */ 151 if (output) { 152 reg |= (1 << (GPIO_PIN_RTC_SIO * 2)); /* output */ 153 } 154 _reg_write_4(SH4_PCTRA, reg); 155 } 156 157 static int 158 rtc_read(struct rs5c313_softc *sc) 159 { 160 int bit; 161 162 ndelay(300); 163 164 bit = (_reg_read_2(SH4_PDTRA) & (1 << GPIO_PIN_RTC_SIO)) ? 1 : 0; 165 166 rtc_clk(sc, 0); 167 ndelay(300); 168 rtc_clk(sc, 1); 169 170 return bit; 171 } 172 173 static void 174 rtc_write(struct rs5c313_softc *sc, int bit) 175 { 176 uint16_t reg; 177 178 reg = _reg_read_2(SH4_PDTRA); 179 if (bit) 180 reg |= (1 << GPIO_PIN_RTC_SIO); 181 else 182 reg &= ~(1 << GPIO_PIN_RTC_SIO); 183 _reg_write_2(SH4_PDTRA, reg); 184 185 ndelay(300); 186 187 rtc_clk(sc, 0); 188 ndelay(300); 189 rtc_clk(sc, 1); 190 } 191