| @@ -1,496 +1,489 @@ | | | @@ -1,496 +1,489 @@ |
1 | /* $NetBSD: voyager.c,v 1.6 2011/10/20 22:04:10 macallan Exp $ */ | | 1 | /* $NetBSD: voyager.c,v 1.7 2011/12/07 09:08:00 macallan Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 2009, 2011 Michael Lorenz | | 4 | * Copyright (c) 2009, 2011 Michael Lorenz |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Redistribution and use in source and binary forms, with or without | | 7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions | | 8 | * modification, are permitted provided that the following conditions |
9 | * are met: | | 9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright | | 10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. | | 11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright | | 12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the | | 13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. | | 14 | * documentation and/or other materials provided with the distribution. |
15 | * | | 15 | * |
16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | | 16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
17 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | | 17 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | | 18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
19 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | | 19 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | | 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
21 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | | 21 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
22 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | | 22 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
23 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | | 23 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | | 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | | 25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | */ | | 26 | */ |
27 | | | 27 | |
28 | #include <sys/cdefs.h> | | 28 | #include <sys/cdefs.h> |
29 | __KERNEL_RCSID(0, "$NetBSD: voyager.c,v 1.6 2011/10/20 22:04:10 macallan Exp $"); | | 29 | __KERNEL_RCSID(0, "$NetBSD: voyager.c,v 1.7 2011/12/07 09:08:00 macallan Exp $"); |
30 | | | 30 | |
31 | #include <sys/param.h> | | 31 | #include <sys/param.h> |
32 | #include <sys/systm.h> | | 32 | #include <sys/systm.h> |
33 | #include <sys/kernel.h> | | 33 | #include <sys/kernel.h> |
34 | #include <sys/device.h> | | 34 | #include <sys/device.h> |
35 | #include <sys/malloc.h> | | 35 | #include <sys/malloc.h> |
36 | #include <sys/lwp.h> | | 36 | #include <sys/lwp.h> |
37 | #include <sys/kauth.h> | | 37 | #include <sys/kauth.h> |
38 | | | 38 | |
39 | #include <dev/pci/pcivar.h> | | 39 | #include <dev/pci/pcivar.h> |
40 | #include <dev/pci/pcireg.h> | | 40 | #include <dev/pci/pcireg.h> |
41 | #include <dev/pci/pcidevs.h> | | 41 | #include <dev/pci/pcidevs.h> |
42 | #include <dev/pci/pciio.h> | | 42 | #include <dev/pci/pciio.h> |
43 | #include <dev/ic/sm502reg.h> | | 43 | #include <dev/ic/sm502reg.h> |
44 | #include <dev/i2c/i2cvar.h> | | 44 | #include <dev/i2c/i2cvar.h> |
45 | #include <dev/i2c/i2c_bitbang.h> | | 45 | #include <dev/i2c/i2c_bitbang.h> |
46 | | | 46 | |
47 | #include <sys/evcnt.h> | | 47 | #include <sys/evcnt.h> |
48 | #include <sys/bitops.h> | | 48 | #include <sys/bitops.h> |
49 | | | 49 | |
50 | #include <dev/pci/voyagervar.h> | | 50 | #include <dev/pci/voyagervar.h> |
51 | | | 51 | |
52 | #include "opt_voyager.h" | | 52 | #include "opt_voyager.h" |
53 | | | 53 | |
54 | #ifdef VOYAGER_DEBUG | | 54 | #ifdef VOYAGER_DEBUG |
55 | #define DPRINTF aprint_normal | | 55 | #define DPRINTF aprint_normal |
56 | #else | | 56 | #else |
57 | #define DPRINTF while (0) printf | | 57 | #define DPRINTF while (0) printf |
58 | #endif | | 58 | #endif |
59 | | | 59 | |
60 | /* interrupt stuff */ | | 60 | /* interrupt stuff */ |
61 | struct voyager_intr { | | 61 | struct voyager_intr { |
62 | int (*vih_func)(void *); | | 62 | int (*vih_func)(void *); |
63 | void *vih_arg; | | 63 | void *vih_arg; |
64 | struct evcnt vih_count; | | 64 | struct evcnt vih_count; |
65 | char vih_name[32]; | | 65 | char vih_name[32]; |
66 | }; | | 66 | }; |
67 | | | 67 | |
68 | struct voyager_softc { | | 68 | struct voyager_softc { |
69 | device_t sc_dev; | | 69 | device_t sc_dev; |
70 | | | 70 | |
71 | pci_chipset_tag_t sc_pc; | | 71 | pci_chipset_tag_t sc_pc; |
72 | pcitag_t sc_pcitag; | | 72 | pcitag_t sc_pcitag; |
73 | | | 73 | |
74 | bus_space_tag_t sc_memt; | | 74 | bus_space_tag_t sc_memt; |
75 | bus_space_tag_t sc_iot; | | 75 | bus_space_tag_t sc_iot; |
76 | | | 76 | |
77 | bus_space_handle_t sc_fbh, sc_regh; | | 77 | bus_space_handle_t sc_fbh, sc_regh; |
78 | bus_addr_t sc_fb, sc_reg; | | 78 | bus_addr_t sc_fb, sc_reg; |
79 | bus_size_t sc_fbsize, sc_regsize; | | 79 | bus_size_t sc_fbsize, sc_regsize; |
80 | | | 80 | |
81 | struct i2c_controller sc_i2c; | | 81 | struct i2c_controller sc_i2c; |
82 | kmutex_t sc_i2c_lock; | | 82 | kmutex_t sc_i2c_lock; |
83 | | | 83 | |
84 | /* interrupt dispatcher */ | | 84 | /* interrupt dispatcher */ |
85 | void *sc_ih; | | 85 | void *sc_ih; |
86 | struct voyager_intr sc_intrs[32]; | | 86 | struct voyager_intr sc_intrs[32]; |
87 | }; | | 87 | }; |
88 | | | 88 | |
89 | static int voyager_match(device_t, cfdata_t, void *); | | 89 | static int voyager_match(device_t, cfdata_t, void *); |
90 | static void voyager_attach(device_t, device_t, void *); | | 90 | static void voyager_attach(device_t, device_t, void *); |
91 | static int voyager_print(void *, const char *); | | 91 | static int voyager_print(void *, const char *); |
92 | static int voyager_intr(void *); | | 92 | static int voyager_intr(void *); |
93 | | | 93 | |
94 | CFATTACH_DECL_NEW(voyager, sizeof(struct voyager_softc), | | 94 | CFATTACH_DECL_NEW(voyager, sizeof(struct voyager_softc), |
95 | voyager_match, voyager_attach, NULL, NULL); | | 95 | voyager_match, voyager_attach, NULL, NULL); |
96 | | | 96 | |
97 | /* I2C glue */ | | 97 | /* I2C glue */ |
98 | static int voyager_i2c_acquire_bus(void *, int); | | 98 | static int voyager_i2c_acquire_bus(void *, int); |
99 | static void voyager_i2c_release_bus(void *, int); | | 99 | static void voyager_i2c_release_bus(void *, int); |
100 | static int voyager_i2c_send_start(void *, int); | | 100 | static int voyager_i2c_send_start(void *, int); |
101 | static int voyager_i2c_send_stop(void *, int); | | 101 | static int voyager_i2c_send_stop(void *, int); |
102 | static int voyager_i2c_initiate_xfer(void *, i2c_addr_t, int); | | 102 | static int voyager_i2c_initiate_xfer(void *, i2c_addr_t, int); |
103 | static int voyager_i2c_read_byte(void *, uint8_t *, int); | | 103 | static int voyager_i2c_read_byte(void *, uint8_t *, int); |
104 | static int voyager_i2c_write_byte(void *, uint8_t, int); | | 104 | static int voyager_i2c_write_byte(void *, uint8_t, int); |
105 | | | 105 | |
106 | /* I2C bitbang glue */ | | 106 | /* I2C bitbang glue */ |
107 | static void voyager_i2cbb_set_bits(void *, uint32_t); | | 107 | static void voyager_i2cbb_set_bits(void *, uint32_t); |
108 | static void voyager_i2cbb_set_dir(void *, uint32_t); | | 108 | static void voyager_i2cbb_set_dir(void *, uint32_t); |
109 | static uint32_t voyager_i2cbb_read(void *); | | 109 | static uint32_t voyager_i2cbb_read(void *); |
110 | | | 110 | |
111 | static const struct i2c_bitbang_ops voyager_i2cbb_ops = { | | 111 | static const struct i2c_bitbang_ops voyager_i2cbb_ops = { |
112 | voyager_i2cbb_set_bits, | | 112 | voyager_i2cbb_set_bits, |
113 | voyager_i2cbb_set_dir, | | 113 | voyager_i2cbb_set_dir, |
114 | voyager_i2cbb_read, | | 114 | voyager_i2cbb_read, |
115 | { | | 115 | { |
116 | 1 << 13, | | 116 | 1 << 13, |
117 | 1 << 6, | | 117 | 1 << 6, |
118 | 1 << 13, | | 118 | 1 << 13, |
119 | 0 | | 119 | 0 |
120 | } | | 120 | } |
121 | }; | | 121 | }; |
122 | #define GPIO_I2C_BITS ((1 << 6) | (1 << 13)) | | 122 | #define GPIO_I2C_BITS ((1 << 6) | (1 << 13)) |
123 | | | 123 | |
124 | #ifdef VOYAGER_DEBUG | | 124 | #ifdef VOYAGER_DEBUG |
125 | static void voyager_print_pwm(struct voyager_softc *, int); | | 125 | static void voyager_print_pwm(struct voyager_softc *, int); |
126 | #endif | | 126 | #endif |
127 | | | 127 | |
128 | static int | | 128 | static int |
129 | voyager_match(device_t parent, cfdata_t match, void *aux) | | 129 | voyager_match(device_t parent, cfdata_t match, void *aux) |
130 | { | | 130 | { |
131 | struct pci_attach_args *pa = (struct pci_attach_args *)aux; | | 131 | struct pci_attach_args *pa = (struct pci_attach_args *)aux; |
132 | | | 132 | |
133 | if (PCI_CLASS(pa->pa_class) != PCI_CLASS_DISPLAY) | | 133 | if (PCI_CLASS(pa->pa_class) != PCI_CLASS_DISPLAY) |
134 | return 0; | | 134 | return 0; |
135 | if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_SILMOTION) | | 135 | if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_SILMOTION) |
136 | return 0; | | 136 | return 0; |
137 | | | 137 | |
138 | /* only chip tested on so far - may need a list */ | | 138 | /* only chip tested on so far - may need a list */ |
139 | if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_SILMOTION_SM502) | | 139 | if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_SILMOTION_SM502) |
140 | return 100; | | 140 | return 100; |
141 | return (0); | | 141 | return (0); |
142 | } | | 142 | } |
143 | | | 143 | |
144 | static void | | 144 | static void |
145 | voyager_attach(device_t parent, device_t self, void *aux) | | 145 | voyager_attach(device_t parent, device_t self, void *aux) |
146 | { | | 146 | { |
147 | struct voyager_softc *sc = device_private(self); | | 147 | struct voyager_softc *sc = device_private(self); |
148 | struct pci_attach_args *pa = aux; | | 148 | struct pci_attach_args *pa = aux; |
149 | pci_intr_handle_t ih; | | 149 | pci_intr_handle_t ih; |
150 | char devinfo[256]; | | 150 | char devinfo[256]; |
151 | struct voyager_attach_args vaa; | | 151 | struct voyager_attach_args vaa; |
152 | struct i2cbus_attach_args iba; | | 152 | struct i2cbus_attach_args iba; |
153 | uint32_t reg; | | 153 | uint32_t reg; |
154 | const char *intrstr; | | 154 | const char *intrstr; |
155 | int i; | | 155 | int i; |
156 | | | 156 | |
157 | sc->sc_pc = pa->pa_pc; | | 157 | sc->sc_pc = pa->pa_pc; |
158 | sc->sc_pcitag = pa->pa_tag; | | 158 | sc->sc_pcitag = pa->pa_tag; |
159 | sc->sc_memt = pa->pa_memt; | | 159 | sc->sc_memt = pa->pa_memt; |
160 | sc->sc_iot = pa->pa_iot; | | 160 | sc->sc_iot = pa->pa_iot; |
161 | sc->sc_dev = self; | | 161 | sc->sc_dev = self; |
162 | | | 162 | |
163 | pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo, sizeof(devinfo)); | | 163 | pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo, sizeof(devinfo)); |
164 | aprint_normal(": %s\n", devinfo); | | 164 | aprint_normal(": %s\n", devinfo); |
165 | | | 165 | |
166 | if (pci_mapreg_map(pa, 0x14, PCI_MAPREG_TYPE_MEM, 0, | | 166 | if (pci_mapreg_map(pa, 0x14, PCI_MAPREG_TYPE_MEM, 0, |
167 | &sc->sc_memt, &sc->sc_regh, &sc->sc_reg, &sc->sc_regsize)) { | | 167 | &sc->sc_memt, &sc->sc_regh, &sc->sc_reg, &sc->sc_regsize)) { |
168 | aprint_error("%s: failed to map registers.\n", | | 168 | aprint_error("%s: failed to map registers.\n", |
169 | device_xname(sc->sc_dev)); | | 169 | device_xname(sc->sc_dev)); |
170 | } | | 170 | } |
171 | | | 171 | |
172 | if (pci_mapreg_map(pa, 0x10, PCI_MAPREG_TYPE_MEM, | | 172 | if (pci_mapreg_map(pa, 0x10, PCI_MAPREG_TYPE_MEM, |
173 | BUS_SPACE_MAP_LINEAR, | | 173 | BUS_SPACE_MAP_LINEAR, |
174 | &sc->sc_memt, &sc->sc_fbh, &sc->sc_fb, &sc->sc_fbsize)) { | | 174 | &sc->sc_memt, &sc->sc_fbh, &sc->sc_fb, &sc->sc_fbsize)) { |
175 | aprint_error("%s: failed to map the frame buffer.\n", | | 175 | aprint_error("%s: failed to map the frame buffer.\n", |
176 | device_xname(sc->sc_dev)); | | 176 | device_xname(sc->sc_dev)); |
177 | } | | 177 | } |
178 | | | 178 | |
179 | /* disable all interrupts */ | | 179 | /* disable all interrupts */ |
180 | bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_INTR_MASK, 0); | | 180 | bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_INTR_MASK, 0); |
181 | | | 181 | |
182 | /* initialize handler list */ | | 182 | /* initialize handler list */ |
183 | for (i = 0; i < 32; i++) { | | 183 | for (i = 0; i < 32; i++) { |
184 | sc->sc_intrs[i].vih_func = NULL; | | 184 | sc->sc_intrs[i].vih_func = NULL; |
185 | snprintf(sc->sc_intrs[i].vih_name, 32, "int %d", i); | | 185 | snprintf(sc->sc_intrs[i].vih_name, 32, "int %d", i); |
186 | evcnt_attach_dynamic(&sc->sc_intrs[i].vih_count, | | 186 | evcnt_attach_dynamic(&sc->sc_intrs[i].vih_count, |
187 | EVCNT_TYPE_INTR, NULL, "voyager", sc->sc_intrs[i].vih_name); | | 187 | EVCNT_TYPE_INTR, NULL, "voyager", sc->sc_intrs[i].vih_name); |
188 | } | | 188 | } |
189 | | | 189 | |
190 | /* Map and establish the interrupt. */ | | 190 | /* Map and establish the interrupt. */ |
191 | if (pci_intr_map(pa, &ih)) { | | 191 | if (pci_intr_map(pa, &ih)) { |
192 | aprint_error_dev(self, "couldn't map interrupt\n"); | | 192 | aprint_error_dev(self, "couldn't map interrupt\n"); |
193 | return; | | 193 | return; |
194 | } | | 194 | } |
195 | | | 195 | |
196 | intrstr = pci_intr_string(sc->sc_pc, ih); | | 196 | intrstr = pci_intr_string(sc->sc_pc, ih); |
197 | sc->sc_ih = pci_intr_establish(sc->sc_pc, ih, IPL_AUDIO, voyager_intr, sc); | | 197 | sc->sc_ih = pci_intr_establish(sc->sc_pc, ih, IPL_AUDIO, voyager_intr, sc); |
198 | if (sc->sc_ih == NULL) { | | 198 | if (sc->sc_ih == NULL) { |
199 | aprint_error_dev(self, "couldn't establish interrupt"); | | 199 | aprint_error_dev(self, "couldn't establish interrupt"); |
200 | if (intrstr != NULL) | | 200 | if (intrstr != NULL) |
201 | aprint_error(" at %s", intrstr); | | 201 | aprint_error(" at %s", intrstr); |
202 | aprint_error("\n"); | | 202 | aprint_error("\n"); |
203 | return; | | 203 | return; |
204 | } | | 204 | } |
205 | aprint_normal_dev(self, "interrupting at %s\n", intrstr); | | 205 | aprint_normal_dev(self, "interrupting at %s\n", intrstr); |
206 | | | 206 | |
207 | #ifdef VOYAGER_DEBUG | | 207 | #ifdef VOYAGER_DEBUG |
208 | voyager_print_pwm(sc, SM502_PWM0); | | 208 | voyager_print_pwm(sc, SM502_PWM0); |
209 | voyager_print_pwm(sc, SM502_PWM1); | | 209 | voyager_print_pwm(sc, SM502_PWM1); |
210 | voyager_print_pwm(sc, SM502_PWM2); | | 210 | voyager_print_pwm(sc, SM502_PWM2); |
211 | #endif | | 211 | #endif |
212 | | | 212 | |
213 | /* attach the framebuffer driver */ | | 213 | /* attach the framebuffer driver */ |
214 | vaa.vaa_memh = sc->sc_fbh; | | 214 | vaa.vaa_memh = sc->sc_fbh; |
215 | vaa.vaa_mem_pa = sc->sc_fb; | | 215 | vaa.vaa_mem_pa = sc->sc_fb; |
216 | vaa.vaa_regh = sc->sc_regh; | | 216 | vaa.vaa_regh = sc->sc_regh; |
217 | vaa.vaa_reg_pa = sc->sc_reg; | | 217 | vaa.vaa_reg_pa = sc->sc_reg; |
218 | vaa.vaa_tag = sc->sc_memt; | | 218 | vaa.vaa_tag = sc->sc_memt; |
219 | vaa.vaa_pc = sc->sc_pc; | | 219 | vaa.vaa_pc = sc->sc_pc; |
220 | vaa.vaa_pcitag = sc->sc_pcitag; | | 220 | vaa.vaa_pcitag = sc->sc_pcitag; |
221 | strcpy(vaa.vaa_name, "voyagerfb"); | | 221 | strcpy(vaa.vaa_name, "voyagerfb"); |
222 | config_found_ia(sc->sc_dev, "voyagerbus", &vaa, voyager_print); | | 222 | config_found_ia(sc->sc_dev, "voyagerbus", &vaa, voyager_print); |
223 | strcpy(vaa.vaa_name, "pwmclock"); | | 223 | strcpy(vaa.vaa_name, "pwmclock"); |
224 | config_found_ia(sc->sc_dev, "voyagerbus", &vaa, voyager_print); | | 224 | config_found_ia(sc->sc_dev, "voyagerbus", &vaa, voyager_print); |
| | | 225 | strcpy(vaa.vaa_name, "vac"); |
| | | 226 | config_found_ia(sc->sc_dev, "voyagerbus", &vaa, voyager_print); |
| | | 227 | |
| | | 228 | /* we use this mutex wether there's an i2c bus or not */ |
| | | 229 | mutex_init(&sc->sc_i2c_lock, MUTEX_DEFAULT, IPL_NONE); |
225 | | | 230 | |
| | | 231 | /* |
| | | 232 | * see if the i2c pins are configured as gpio and if so, use them |
| | | 233 | * should probably be a compile time option |
| | | 234 | */ |
226 | reg = bus_space_read_4(sc->sc_memt, sc->sc_regh, SM502_GPIO0_CONTROL); | | 235 | reg = bus_space_read_4(sc->sc_memt, sc->sc_regh, SM502_GPIO0_CONTROL); |
227 | if ((reg & GPIO_I2C_BITS) == 0) { | | 236 | if ((reg & GPIO_I2C_BITS) == 0) { |
228 | /* both bits as outputs */ | | 237 | /* both bits as outputs */ |
229 | reg = bus_space_read_4(sc->sc_memt, sc->sc_regh, SM502_GPIO_DIR0); | | 238 | voyager_gpio_dir(sc, 0xffffffff, GPIO_I2C_BITS); |
230 | reg |= GPIO_I2C_BITS; | | | |
231 | bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_GPIO_DIR0, reg); | | | |
232 | | | 239 | |
233 | /* Fill in the i2c tag */ | | 240 | /* Fill in the i2c tag */ |
234 | sc->sc_i2c.ic_cookie = sc; | | 241 | sc->sc_i2c.ic_cookie = sc; |
235 | sc->sc_i2c.ic_acquire_bus = voyager_i2c_acquire_bus; | | 242 | sc->sc_i2c.ic_acquire_bus = voyager_i2c_acquire_bus; |
236 | sc->sc_i2c.ic_release_bus = voyager_i2c_release_bus; | | 243 | sc->sc_i2c.ic_release_bus = voyager_i2c_release_bus; |
237 | sc->sc_i2c.ic_send_start = voyager_i2c_send_start; | | 244 | sc->sc_i2c.ic_send_start = voyager_i2c_send_start; |
238 | sc->sc_i2c.ic_send_stop = voyager_i2c_send_stop; | | 245 | sc->sc_i2c.ic_send_stop = voyager_i2c_send_stop; |
239 | sc->sc_i2c.ic_initiate_xfer = voyager_i2c_initiate_xfer; | | 246 | sc->sc_i2c.ic_initiate_xfer = voyager_i2c_initiate_xfer; |
240 | sc->sc_i2c.ic_read_byte = voyager_i2c_read_byte; | | 247 | sc->sc_i2c.ic_read_byte = voyager_i2c_read_byte; |
241 | sc->sc_i2c.ic_write_byte = voyager_i2c_write_byte; | | 248 | sc->sc_i2c.ic_write_byte = voyager_i2c_write_byte; |
242 | sc->sc_i2c.ic_exec = NULL; | | 249 | sc->sc_i2c.ic_exec = NULL; |
243 | mutex_init(&sc->sc_i2c_lock, MUTEX_DEFAULT, IPL_NONE); | | | |
244 | iba.iba_tag = &sc->sc_i2c; | | 250 | iba.iba_tag = &sc->sc_i2c; |
245 | config_found_ia(self, "i2cbus", &iba, iicbus_print); | | 251 | config_found_ia(self, "i2cbus", &iba, iicbus_print); |
246 | } | | 252 | } |
| | | 253 | voyager_control_gpio(sc, ~(1 << 16), 0); |
| | | 254 | voyager_gpio_dir(sc, 0xffffffff, 1 << 16); |
| | | 255 | voyager_write_gpio(sc, 0xffffffff, 1 << 16); |
247 | } | | 256 | } |
248 | | | 257 | |
249 | static int | | 258 | static int |
250 | voyager_print(void *aux, const char *what) | | 259 | voyager_print(void *aux, const char *what) |
251 | { | | 260 | { |
252 | /*struct voyager_attach_args *vaa = aux;*/ | | 261 | /*struct voyager_attach_args *vaa = aux;*/ |
253 | | | 262 | |
254 | if (what == NULL) | | 263 | if (what == NULL) |
255 | return 0; | | 264 | return 0; |
256 | | | 265 | |
257 | printf("%s:", what); | | 266 | printf("%s:", what); |
258 | | | 267 | |
259 | return 0; | | 268 | return 0; |
260 | } | | 269 | } |
261 | | | 270 | |
262 | static void | | 271 | static void |
263 | voyager_i2cbb_set_bits(void *cookie, uint32_t bits) | | 272 | voyager_i2cbb_set_bits(void *cookie, uint32_t bits) |
264 | { | | 273 | { |
265 | struct voyager_softc *sc = cookie; | | 274 | struct voyager_softc *sc = cookie; |
266 | uint32_t reg; | | 275 | uint32_t reg; |
267 | | | 276 | |
268 | reg = bus_space_read_4(sc->sc_memt, sc->sc_regh, SM502_GPIO_DATA0); | | 277 | reg = bus_space_read_4(sc->sc_memt, sc->sc_regh, SM502_GPIO_DATA0); |
269 | reg &= ~GPIO_I2C_BITS; | | 278 | reg &= ~GPIO_I2C_BITS; |
270 | reg |= bits; | | 279 | reg |= bits; |
271 | bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_GPIO_DATA0, reg); | | 280 | bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_GPIO_DATA0, reg); |
272 | } | | 281 | } |
273 | | | 282 | |
274 | static void | | 283 | static void |
275 | voyager_i2cbb_set_dir(void *cookie, uint32_t bits) | | 284 | voyager_i2cbb_set_dir(void *cookie, uint32_t bits) |
276 | { | | 285 | { |
277 | struct voyager_softc *sc = cookie; | | 286 | struct voyager_softc *sc = cookie; |
278 | uint32_t reg; | | 287 | uint32_t reg; |
279 | | | 288 | |
280 | reg = bus_space_read_4(sc->sc_memt, sc->sc_regh, SM502_GPIO_DIR0); | | 289 | reg = bus_space_read_4(sc->sc_memt, sc->sc_regh, SM502_GPIO_DIR0); |
281 | reg &= ~(1 << 13); | | 290 | reg &= ~(1 << 13); |
282 | reg |= bits; | | 291 | reg |= bits; |
283 | bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_GPIO_DIR0, reg); | | 292 | bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_GPIO_DIR0, reg); |
284 | } | | 293 | } |
285 | | | 294 | |
286 | static uint32_t | | 295 | static uint32_t |
287 | voyager_i2cbb_read(void *cookie) | | 296 | voyager_i2cbb_read(void *cookie) |
288 | { | | 297 | { |
289 | struct voyager_softc *sc = cookie; | | 298 | struct voyager_softc *sc = cookie; |
290 | uint32_t reg; | | 299 | uint32_t reg; |
291 | | | 300 | |
292 | reg = bus_space_read_4(sc->sc_memt, sc->sc_regh, SM502_GPIO_DATA0); | | 301 | reg = bus_space_read_4(sc->sc_memt, sc->sc_regh, SM502_GPIO_DATA0); |
293 | return reg; | | 302 | return reg; |
294 | } | | 303 | } |
295 | | | 304 | |
296 | /* higher level I2C stuff */ | | 305 | /* higher level I2C stuff */ |
297 | static int | | 306 | static int |
298 | voyager_i2c_acquire_bus(void *cookie, int flags) | | 307 | voyager_i2c_acquire_bus(void *cookie, int flags) |
299 | { | | 308 | { |
300 | struct voyager_softc *sc = cookie; | | 309 | struct voyager_softc *sc = cookie; |
301 | | | 310 | |
302 | mutex_enter(&sc->sc_i2c_lock); | | 311 | mutex_enter(&sc->sc_i2c_lock); |
303 | return 0; | | 312 | return 0; |
304 | } | | 313 | } |
305 | | | 314 | |
306 | static void | | 315 | static void |
307 | voyager_i2c_release_bus(void *cookie, int flags) | | 316 | voyager_i2c_release_bus(void *cookie, int flags) |
308 | { | | 317 | { |
309 | struct voyager_softc *sc = cookie; | | 318 | struct voyager_softc *sc = cookie; |
310 | | | 319 | |
311 | mutex_exit(&sc->sc_i2c_lock); | | 320 | mutex_exit(&sc->sc_i2c_lock); |
312 | } | | 321 | } |
313 | | | 322 | |
314 | static int | | 323 | static int |
315 | voyager_i2c_send_start(void *cookie, int flags) | | 324 | voyager_i2c_send_start(void *cookie, int flags) |
316 | { | | 325 | { |
317 | return (i2c_bitbang_send_start(cookie, flags, &voyager_i2cbb_ops)); | | 326 | return (i2c_bitbang_send_start(cookie, flags, &voyager_i2cbb_ops)); |
318 | } | | 327 | } |
319 | | | 328 | |
320 | static int | | 329 | static int |
321 | voyager_i2c_send_stop(void *cookie, int flags) | | 330 | voyager_i2c_send_stop(void *cookie, int flags) |
322 | { | | 331 | { |
323 | | | 332 | |
324 | return (i2c_bitbang_send_stop(cookie, flags, &voyager_i2cbb_ops)); | | 333 | return (i2c_bitbang_send_stop(cookie, flags, &voyager_i2cbb_ops)); |
325 | } | | 334 | } |
326 | | | 335 | |
327 | static int | | 336 | static int |
328 | voyager_i2c_initiate_xfer(void *cookie, i2c_addr_t addr, int flags) | | 337 | voyager_i2c_initiate_xfer(void *cookie, i2c_addr_t addr, int flags) |
329 | { | | 338 | { |
330 | /* | | 339 | /* |
331 | * for some reason i2c_bitbang_initiate_xfer left-shifts | | 340 | * for some reason i2c_bitbang_initiate_xfer left-shifts |
332 | * the I2C-address and then sets the direction bit | | 341 | * the I2C-address and then sets the direction bit |
333 | */ | | 342 | */ |
334 | return (i2c_bitbang_initiate_xfer(cookie, addr, flags, | | 343 | return (i2c_bitbang_initiate_xfer(cookie, addr, flags, |
335 | &voyager_i2cbb_ops)); | | 344 | &voyager_i2cbb_ops)); |
336 | } | | 345 | } |
337 | | | 346 | |
338 | static int | | 347 | static int |
339 | voyager_i2c_read_byte(void *cookie, uint8_t *valp, int flags) | | 348 | voyager_i2c_read_byte(void *cookie, uint8_t *valp, int flags) |
340 | { | | 349 | { |
341 | int ret; | | 350 | int ret; |
342 | | | 351 | |
343 | ret = i2c_bitbang_read_byte(cookie, valp, flags, &voyager_i2cbb_ops); | | 352 | ret = i2c_bitbang_read_byte(cookie, valp, flags, &voyager_i2cbb_ops); |
344 | return ret; | | 353 | return ret; |
345 | } | | 354 | } |
346 | | | 355 | |
347 | static int | | 356 | static int |
348 | voyager_i2c_write_byte(void *cookie, uint8_t val, int flags) | | 357 | voyager_i2c_write_byte(void *cookie, uint8_t val, int flags) |
349 | { | | 358 | { |
350 | int ret; | | 359 | int ret; |
351 | | | 360 | |
352 | ret = i2c_bitbang_write_byte(cookie, val, flags, &voyager_i2cbb_ops); | | 361 | ret = i2c_bitbang_write_byte(cookie, val, flags, &voyager_i2cbb_ops); |
353 | delay(500); | | 362 | delay(500); |
354 | return ret; | | 363 | return ret; |
355 | } | | 364 | } |
356 | | | 365 | |
357 | /* gpio stuff */ | | | |
358 | void | | 366 | void |
359 | voyager_write_gpio(void *cookie, uint32_t mask, uint32_t bits) | | 367 | voyager_twiddle_bits(void *cookie, int regnum, uint32_t mask, uint32_t bits) |
360 | { | | 368 | { |
361 | struct voyager_softc *sc = cookie; | | 369 | struct voyager_softc *sc = cookie; |
362 | uint32_t reg; | | 370 | uint32_t reg; |
363 | | | 371 | |
364 | /* don't interfere with i2c ops */ | | 372 | /* don't interfere with i2c ops */ |
365 | mutex_enter(&sc->sc_i2c_lock); | | 373 | mutex_enter(&sc->sc_i2c_lock); |
366 | reg = bus_space_read_4(sc->sc_memt, sc->sc_regh, SM502_GPIO_DATA0); | | 374 | reg = bus_space_read_4(sc->sc_memt, sc->sc_regh, regnum); |
367 | reg &= mask; | | | |
368 | reg |= bits; | | | |
369 | bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_GPIO_DATA0, reg); | | | |
370 | mutex_exit(&sc->sc_i2c_lock); | | | |
371 | } | | | |
372 | | | | |
373 | void | | | |
374 | voyager_control_gpio(void *cookie, uint32_t mask, uint32_t bits) | | | |
375 | { | | | |
376 | struct voyager_softc *sc = cookie; | | | |
377 | uint32_t reg; | | | |
378 | | | | |
379 | /* don't interfere with i2c ops */ | | | |
380 | mutex_enter(&sc->sc_i2c_lock); | | | |
381 | reg = bus_space_read_4(sc->sc_memt, sc->sc_regh, SM502_GPIO0_CONTROL); | | | |
382 | reg &= mask; | | 375 | reg &= mask; |
383 | reg |= bits; | | 376 | reg |= bits; |
384 | bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_GPIO0_CONTROL, reg); | | 377 | bus_space_write_4(sc->sc_memt, sc->sc_regh, regnum, reg); |
385 | mutex_exit(&sc->sc_i2c_lock); | | 378 | mutex_exit(&sc->sc_i2c_lock); |
386 | } | | 379 | } |
387 | | | 380 | |
388 | static int | | 381 | static int |
389 | voyager_intr(void *cookie) | | 382 | voyager_intr(void *cookie) |
390 | { | | 383 | { |
391 | struct voyager_softc *sc = cookie; | | 384 | struct voyager_softc *sc = cookie; |
392 | struct voyager_intr *ih; | | 385 | struct voyager_intr *ih; |
393 | uint32_t intrs; | | 386 | uint32_t intrs; |
394 | uint32_t mask, bit; | | 387 | uint32_t mask, bit; |
395 | int num; | | 388 | int num; |
396 | | | 389 | |
397 | intrs = bus_space_read_4(sc->sc_memt, sc->sc_regh, SM502_INTR_STATUS); | | 390 | intrs = bus_space_read_4(sc->sc_memt, sc->sc_regh, SM502_INTR_STATUS); |
398 | mask = bus_space_read_4(sc->sc_memt, sc->sc_regh, SM502_INTR_MASK); | | 391 | mask = bus_space_read_4(sc->sc_memt, sc->sc_regh, SM502_INTR_MASK); |
399 | intrs &= mask; | | 392 | intrs &= mask; |
400 | | | 393 | |
401 | while (intrs != 0) { | | 394 | while (intrs != 0) { |
402 | num = ffs32(intrs) - 1; | | 395 | num = ffs32(intrs) - 1; |
403 | bit = 1 << num; | | 396 | bit = 1 << num; |
404 | intrs &= ~bit; | | 397 | intrs &= ~bit; |
405 | ih = &sc->sc_intrs[num]; | | 398 | ih = &sc->sc_intrs[num]; |
406 | if (ih->vih_func != NULL) { | | 399 | if (ih->vih_func != NULL) { |
407 | ih->vih_func(ih->vih_arg); | | 400 | ih->vih_func(ih->vih_arg); |
408 | } | | 401 | } |
409 | ih->vih_count.ev_count++; | | 402 | ih->vih_count.ev_count++; |
410 | } | | 403 | } |
411 | return 0; | | 404 | return 0; |
412 | } | | 405 | } |
413 | | | 406 | |
414 | void * | | 407 | void * |
415 | voyager_establish_intr(device_t dev, int bit, int (*handler)(void *), void *arg) | | 408 | voyager_establish_intr(device_t dev, int bit, int (*handler)(void *), void *arg) |
416 | { | | 409 | { |
417 | struct voyager_softc *sc = device_private(dev); | | 410 | struct voyager_softc *sc = device_private(dev); |
418 | struct voyager_intr *ih; | | 411 | struct voyager_intr *ih; |
419 | uint32_t reg; | | 412 | uint32_t reg; |
420 | | | 413 | |
421 | if ((bit < 0) || (bit > 31)) { | | 414 | if ((bit < 0) || (bit > 31)) { |
422 | aprint_error_dev(dev, "bogus interrupt %d\n", bit); | | 415 | aprint_error_dev(dev, "bogus interrupt %d\n", bit); |
423 | return NULL; | | 416 | return NULL; |
424 | } | | 417 | } |
425 | | | 418 | |
426 | ih = &sc->sc_intrs[bit]; | | 419 | ih = &sc->sc_intrs[bit]; |
427 | if (ih->vih_func != NULL) { | | 420 | if (ih->vih_func != NULL) { |
428 | aprint_error_dev(dev, "interrupt %d is already in use\n", bit); | | 421 | aprint_error_dev(dev, "interrupt %d is already in use\n", bit); |
429 | return NULL; | | 422 | return NULL; |
430 | } | | 423 | } |
431 | ih->vih_func = handler; | | 424 | ih->vih_func = handler; |
432 | ih->vih_arg = arg; | | 425 | ih->vih_arg = arg; |
433 | reg = bus_space_read_4(sc->sc_memt, sc->sc_regh, SM502_INTR_MASK); | | 426 | reg = bus_space_read_4(sc->sc_memt, sc->sc_regh, SM502_INTR_MASK); |
434 | reg |= 1 << bit; | | 427 | reg |= 1 << bit; |
435 | bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_INTR_MASK, reg); | | 428 | bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_INTR_MASK, reg); |
436 | | | 429 | |
437 | return (void *)(uintptr_t)(0x80000000 | bit); | | 430 | return (void *)(uintptr_t)(0x80000000 | bit); |
438 | } | | 431 | } |
439 | | | 432 | |
440 | void | | 433 | void |
441 | voyager_disestablish_intr(device_t dev, void *ih) | | 434 | voyager_disestablish_intr(device_t dev, void *ih) |
442 | { | | 435 | { |
443 | } | | 436 | } |
444 | | | 437 | |
445 | /* timer */ | | 438 | /* timer */ |
446 | #ifdef VOYAGER_DEBUG | | 439 | #ifdef VOYAGER_DEBUG |
447 | static void | | 440 | static void |
448 | voyager_print_pwm(struct voyager_softc *sc, int pwmreg) | | 441 | voyager_print_pwm(struct voyager_softc *sc, int pwmreg) |
449 | { | | 442 | { |
450 | uint32_t reg; | | 443 | uint32_t reg; |
451 | | | 444 | |
452 | reg = bus_space_read_4(sc->sc_memt, sc->sc_regh, pwmreg); | | 445 | reg = bus_space_read_4(sc->sc_memt, sc->sc_regh, pwmreg); |
453 | aprint_debug_dev(sc->sc_dev, "%08x: %08x = %d Hz, %d high, %d low\n", | | 446 | aprint_debug_dev(sc->sc_dev, "%08x: %08x = %d Hz, %d high, %d low\n", |
454 | pwmreg, reg, | | 447 | pwmreg, reg, |
455 | 96000000 / (1 << ((reg & SM502_PWM_CLOCK_DIV_MASK) >> SM502_PWM_CLOCK_DIV_SHIFT)), | | 448 | 96000000 / (1 << ((reg & SM502_PWM_CLOCK_DIV_MASK) >> SM502_PWM_CLOCK_DIV_SHIFT)), |
456 | (reg & SM502_PWM_CLOCK_HIGH_MASK) >> SM502_PWM_CLOCK_HIGH_SHIFT, | | 449 | (reg & SM502_PWM_CLOCK_HIGH_MASK) >> SM502_PWM_CLOCK_HIGH_SHIFT, |
457 | (reg & SM502_PWM_CLOCK_LOW_MASK) >> SM502_PWM_CLOCK_LOW_SHIFT); | | 450 | (reg & SM502_PWM_CLOCK_LOW_MASK) >> SM502_PWM_CLOCK_LOW_SHIFT); |
458 | } | | 451 | } |
459 | #endif | | 452 | #endif |
460 | | | 453 | |
461 | uint32_t | | 454 | uint32_t |
462 | voyager_set_pwm(int freq, int duty_cycle) | | 455 | voyager_set_pwm(int freq, int duty_cycle) |
463 | { | | 456 | { |
464 | int ifreq, factor, bit, steps; | | 457 | int ifreq, factor, bit, steps; |
465 | uint32_t reg = 0, hi, lo; | | 458 | uint32_t reg = 0, hi, lo; |
466 | | | 459 | |
467 | /* | | 460 | /* |
468 | * find the smallest divider that gets us within 4096 steps of the | | 461 | * find the smallest divider that gets us within 4096 steps of the |
469 | * target frequency | | 462 | * target frequency |
470 | */ | | 463 | */ |
471 | ifreq = freq * 4096; | | 464 | ifreq = freq * 4096; |
472 | factor = 96000000 / ifreq; | | 465 | factor = 96000000 / ifreq; |
473 | bit = fls32(factor); | | 466 | bit = fls32(factor); |
474 | factor = 1 << bit; | | 467 | factor = 1 << bit; |
475 | steps = 96000000 / (factor * freq); | | 468 | steps = 96000000 / (factor * freq); |
476 | /* can't have it all off */ | | 469 | /* can't have it all off */ |
477 | if (duty_cycle < 1) | | 470 | if (duty_cycle < 1) |
478 | duty_cycle = 1; | | 471 | duty_cycle = 1; |
479 | /* can't be always on either */ | | 472 | /* can't be always on either */ |
480 | if (duty_cycle > 999) | | 473 | if (duty_cycle > 999) |
481 | duty_cycle = 999; | | 474 | duty_cycle = 999; |
482 | hi = steps * duty_cycle / 1000; | | 475 | hi = steps * duty_cycle / 1000; |
483 | if (hi < 1) | | 476 | if (hi < 1) |
484 | hi = 1; | | 477 | hi = 1; |
485 | lo = steps - hi; | | 478 | lo = steps - hi; |
486 | if (lo < 1) { | | 479 | if (lo < 1) { |
487 | hi = steps - 1; | | 480 | hi = steps - 1; |
488 | lo = 1; | | 481 | lo = 1; |
489 | } | | 482 | } |
490 | DPRINTF("%d hz -> %d, %d, %d / %d\n", freq, factor, steps, lo, hi); | | 483 | DPRINTF("%d hz -> %d, %d, %d / %d\n", freq, factor, steps, lo, hi); |
491 | reg = ((hi - 1) & 0xfff) << SM502_PWM_CLOCK_HIGH_SHIFT; | | 484 | reg = ((hi - 1) & 0xfff) << SM502_PWM_CLOCK_HIGH_SHIFT; |
492 | reg |= ((lo - 1) & 0xfff) << SM502_PWM_CLOCK_LOW_SHIFT; | | 485 | reg |= ((lo - 1) & 0xfff) << SM502_PWM_CLOCK_LOW_SHIFT; |
493 | reg |= (bit & 0xf) << SM502_PWM_CLOCK_DIV_SHIFT; | | 486 | reg |= (bit & 0xf) << SM502_PWM_CLOCK_DIV_SHIFT; |
494 | DPRINTF("reg: %08x\n", reg); | | 487 | DPRINTF("reg: %08x\n", reg); |
495 | return reg; | | 488 | return reg; |
496 | } | | 489 | } |