Deleted Added
full compact
gpioiic.c (213237) gpioiic.c (213277)
1/*-
2 * Copyright (c) 2009 Oleksandr Tymoshenko <gonzo@freebsd.org>
3 * Copyright (c) 2010 Luiz Otavio O Souza
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
1/*-
2 * Copyright (c) 2009 Oleksandr Tymoshenko <gonzo@freebsd.org>
3 * Copyright (c) 2010 Luiz Otavio O Souza
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
26 */
27
28#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: head/sys/dev/gpio/gpioiic.c 213237 2010-09-28 03:24:53Z gonzo $");
29__FBSDID("$FreeBSD: head/sys/dev/gpio/gpioiic.c 213277 2010-09-29 20:53:33Z gonzo $");
29
30#include <sys/param.h>
31#include <sys/systm.h>
32#include <sys/bio.h>
33#include <sys/bus.h>
34#include <sys/conf.h>
35#include <sys/kernel.h>
36#include <sys/kthread.h>
37#include <sys/lock.h>
38#include <sys/malloc.h>
39#include <sys/module.h>
40#include <sys/mutex.h>
41
42#include <sys/gpio.h>
43#include "gpiobus_if.h"
44
45#include <dev/iicbus/iiconf.h>
46#include <dev/iicbus/iicbus.h>
47
48#include "iicbb_if.h"
49
50#define SCL_PIN 0 /* gpiobus mapped pin 6 */
51#define SDA_PIN 1 /* gpiobus mapped pin 7 */
52
53struct gpioiic_softc
54{
55 device_t sc_dev;
56 device_t sc_busdev;
57 struct mtx sc_mtx;
58 struct cdev *sc_leddev;
59};
60
61static int gpioiic_probe(device_t);
62static int gpioiic_attach(device_t);
63
64/* iicbb interface */
65static void gpioiic_reset_bus(device_t);
66static int gpioiic_callback(device_t, int, caddr_t);
67static void gpioiic_setsda(device_t, int);
68static void gpioiic_setscl(device_t, int);
69static int gpioiic_getsda(device_t);
70static int gpioiic_getscl(device_t);
71static int gpioiic_reset(device_t, u_char, u_char, u_char *);
72
73
74static int
75gpioiic_probe(device_t dev)
76{
77
78 device_set_desc(dev, "GPIO I2C bit-banging driver");
79 return (0);
80}
81
82static int
83gpioiic_attach(device_t dev)
84{
85 struct gpioiic_softc *sc = device_get_softc(dev);
86 device_t bitbang;
87
88 sc->sc_dev = dev;
89 sc->sc_busdev = device_get_parent(dev);
90
91 /* add generic bit-banging code */
92 bitbang = device_add_child(dev, "iicbb", -1);
93 device_probe_and_attach(bitbang);
94
95 return (0);
96}
97
98/*
99 * Reset bus by setting SDA first and then SCL.
100 * Must always be called with gpio bus locked.
101 */
102static void
103gpioiic_reset_bus(device_t dev)
104{
105 struct gpioiic_softc *sc = device_get_softc(dev);
106
107 GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, SDA_PIN,
108 GPIO_PIN_INPUT);
109 GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, SCL_PIN,
110 GPIO_PIN_INPUT);
111}
112
113static int
114gpioiic_callback(device_t dev, int index, caddr_t data)
115{
116 struct gpioiic_softc *sc = device_get_softc(dev);
117 int error = 0;
118
119 switch (index) {
120 case IIC_REQUEST_BUS:
121 GPIOBUS_LOCK_BUS(sc->sc_busdev);
122 GPIOBUS_ACQUIRE_BUS(sc->sc_busdev, sc->sc_dev);
123 GPIOBUS_UNLOCK_BUS(sc->sc_busdev);
124 break;
125 case IIC_RELEASE_BUS:
126 GPIOBUS_LOCK_BUS(sc->sc_busdev);
127 GPIOBUS_RELEASE_BUS(sc->sc_busdev, sc->sc_dev);
128 GPIOBUS_UNLOCK_BUS(sc->sc_busdev);
129 break;
130 default:
131 error = EINVAL;
132 }
133
134 return(error);
135}
136
137static void
138gpioiic_setsda(device_t dev, int val)
139{
140 struct gpioiic_softc *sc = device_get_softc(dev);
141
142 GPIOBUS_LOCK_BUS(sc->sc_busdev);
143 if (val == 0) {
144 GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev, SDA_PIN, 0);
145 GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, SDA_PIN,
146 GPIO_PIN_OUTPUT);
147 } else {
148 GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, SDA_PIN,
149 GPIO_PIN_INPUT);
150 }
151 GPIOBUS_UNLOCK_BUS(sc->sc_busdev);
152}
153
154static void
155gpioiic_setscl(device_t dev, int val)
156{
157 struct gpioiic_softc *sc = device_get_softc(dev);
158
159 GPIOBUS_LOCK_BUS(sc->sc_busdev);
160 if (val == 0) {
161 GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev, SCL_PIN, 0);
162 GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, SCL_PIN,
163 GPIO_PIN_OUTPUT);
164 } else {
165 GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, SCL_PIN,
166 GPIO_PIN_INPUT);
167 }
168 GPIOBUS_UNLOCK_BUS(sc->sc_busdev);
169}
170
171static int
172gpioiic_getscl(device_t dev)
173{
174 struct gpioiic_softc *sc = device_get_softc(dev);
175 unsigned int val;
176
177 GPIOBUS_LOCK_BUS(sc->sc_busdev);
178 GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, SCL_PIN,
179 GPIO_PIN_INPUT);
180 GPIOBUS_PIN_GET(sc->sc_busdev, sc->sc_dev, SCL_PIN, &val);
181 GPIOBUS_UNLOCK_BUS(sc->sc_busdev);
182
183 return ((int)val);
184}
185
186static int
187gpioiic_getsda(device_t dev)
188{
189 struct gpioiic_softc *sc = device_get_softc(dev);
190 unsigned int val;
191
192 GPIOBUS_LOCK_BUS(sc->sc_busdev);
193 GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, SDA_PIN,
194 GPIO_PIN_INPUT);
195 GPIOBUS_PIN_GET(sc->sc_busdev, sc->sc_dev, SDA_PIN, &val);
196 GPIOBUS_UNLOCK_BUS(sc->sc_busdev);
197
198 return ((int)val);
199}
200
201static int
202gpioiic_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
203{
204 struct gpioiic_softc *sc = device_get_softc(dev);
205
206 GPIOBUS_LOCK_BUS(sc->sc_busdev);
207 GPIOBUS_ACQUIRE_BUS(sc->sc_busdev, sc->sc_dev);
208
209 gpioiic_reset_bus(sc->sc_dev);
210
211 GPIOBUS_RELEASE_BUS(sc->sc_busdev, sc->sc_dev);
212 GPIOBUS_UNLOCK_BUS(sc->sc_busdev);
213
214 return (IIC_ENOADDR);
215}
216
217static devclass_t gpioiic_devclass;
218
219static device_method_t gpioiic_methods[] = {
220 /* Device interface */
221 DEVMETHOD(device_probe, gpioiic_probe),
222 DEVMETHOD(device_attach, gpioiic_attach),
223 DEVMETHOD(device_detach, bus_generic_detach),
224
225 /* iicbb interface */
226 DEVMETHOD(iicbb_callback, gpioiic_callback),
227 DEVMETHOD(iicbb_setsda, gpioiic_setsda),
228 DEVMETHOD(iicbb_setscl, gpioiic_setscl),
229 DEVMETHOD(iicbb_getsda, gpioiic_getsda),
230 DEVMETHOD(iicbb_getscl, gpioiic_getscl),
231 DEVMETHOD(iicbb_reset, gpioiic_reset),
232
233 { 0, 0 }
234};
235
236static driver_t gpioiic_driver = {
237 "gpioiic",
238 gpioiic_methods,
239 sizeof(struct gpioiic_softc),
240};
241
242DRIVER_MODULE(gpioiic, gpiobus, gpioiic_driver, gpioiic_devclass, 0, 0);
243DRIVER_MODULE(iicbb, gpioiic, iicbb_driver, iicbb_devclass, 0, 0);
244MODULE_DEPEND(gpioiic, iicbb, IICBB_MINVER, IICBB_PREFVER, IICBB_MAXVER);
245MODULE_DEPEND(gpioiic, gpiobus, 1, 1, 1);
30
31#include <sys/param.h>
32#include <sys/systm.h>
33#include <sys/bio.h>
34#include <sys/bus.h>
35#include <sys/conf.h>
36#include <sys/kernel.h>
37#include <sys/kthread.h>
38#include <sys/lock.h>
39#include <sys/malloc.h>
40#include <sys/module.h>
41#include <sys/mutex.h>
42
43#include <sys/gpio.h>
44#include "gpiobus_if.h"
45
46#include <dev/iicbus/iiconf.h>
47#include <dev/iicbus/iicbus.h>
48
49#include "iicbb_if.h"
50
51#define SCL_PIN 0 /* gpiobus mapped pin 6 */
52#define SDA_PIN 1 /* gpiobus mapped pin 7 */
53
54struct gpioiic_softc
55{
56 device_t sc_dev;
57 device_t sc_busdev;
58 struct mtx sc_mtx;
59 struct cdev *sc_leddev;
60};
61
62static int gpioiic_probe(device_t);
63static int gpioiic_attach(device_t);
64
65/* iicbb interface */
66static void gpioiic_reset_bus(device_t);
67static int gpioiic_callback(device_t, int, caddr_t);
68static void gpioiic_setsda(device_t, int);
69static void gpioiic_setscl(device_t, int);
70static int gpioiic_getsda(device_t);
71static int gpioiic_getscl(device_t);
72static int gpioiic_reset(device_t, u_char, u_char, u_char *);
73
74
75static int
76gpioiic_probe(device_t dev)
77{
78
79 device_set_desc(dev, "GPIO I2C bit-banging driver");
80 return (0);
81}
82
83static int
84gpioiic_attach(device_t dev)
85{
86 struct gpioiic_softc *sc = device_get_softc(dev);
87 device_t bitbang;
88
89 sc->sc_dev = dev;
90 sc->sc_busdev = device_get_parent(dev);
91
92 /* add generic bit-banging code */
93 bitbang = device_add_child(dev, "iicbb", -1);
94 device_probe_and_attach(bitbang);
95
96 return (0);
97}
98
99/*
100 * Reset bus by setting SDA first and then SCL.
101 * Must always be called with gpio bus locked.
102 */
103static void
104gpioiic_reset_bus(device_t dev)
105{
106 struct gpioiic_softc *sc = device_get_softc(dev);
107
108 GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, SDA_PIN,
109 GPIO_PIN_INPUT);
110 GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, SCL_PIN,
111 GPIO_PIN_INPUT);
112}
113
114static int
115gpioiic_callback(device_t dev, int index, caddr_t data)
116{
117 struct gpioiic_softc *sc = device_get_softc(dev);
118 int error = 0;
119
120 switch (index) {
121 case IIC_REQUEST_BUS:
122 GPIOBUS_LOCK_BUS(sc->sc_busdev);
123 GPIOBUS_ACQUIRE_BUS(sc->sc_busdev, sc->sc_dev);
124 GPIOBUS_UNLOCK_BUS(sc->sc_busdev);
125 break;
126 case IIC_RELEASE_BUS:
127 GPIOBUS_LOCK_BUS(sc->sc_busdev);
128 GPIOBUS_RELEASE_BUS(sc->sc_busdev, sc->sc_dev);
129 GPIOBUS_UNLOCK_BUS(sc->sc_busdev);
130 break;
131 default:
132 error = EINVAL;
133 }
134
135 return(error);
136}
137
138static void
139gpioiic_setsda(device_t dev, int val)
140{
141 struct gpioiic_softc *sc = device_get_softc(dev);
142
143 GPIOBUS_LOCK_BUS(sc->sc_busdev);
144 if (val == 0) {
145 GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev, SDA_PIN, 0);
146 GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, SDA_PIN,
147 GPIO_PIN_OUTPUT);
148 } else {
149 GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, SDA_PIN,
150 GPIO_PIN_INPUT);
151 }
152 GPIOBUS_UNLOCK_BUS(sc->sc_busdev);
153}
154
155static void
156gpioiic_setscl(device_t dev, int val)
157{
158 struct gpioiic_softc *sc = device_get_softc(dev);
159
160 GPIOBUS_LOCK_BUS(sc->sc_busdev);
161 if (val == 0) {
162 GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev, SCL_PIN, 0);
163 GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, SCL_PIN,
164 GPIO_PIN_OUTPUT);
165 } else {
166 GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, SCL_PIN,
167 GPIO_PIN_INPUT);
168 }
169 GPIOBUS_UNLOCK_BUS(sc->sc_busdev);
170}
171
172static int
173gpioiic_getscl(device_t dev)
174{
175 struct gpioiic_softc *sc = device_get_softc(dev);
176 unsigned int val;
177
178 GPIOBUS_LOCK_BUS(sc->sc_busdev);
179 GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, SCL_PIN,
180 GPIO_PIN_INPUT);
181 GPIOBUS_PIN_GET(sc->sc_busdev, sc->sc_dev, SCL_PIN, &val);
182 GPIOBUS_UNLOCK_BUS(sc->sc_busdev);
183
184 return ((int)val);
185}
186
187static int
188gpioiic_getsda(device_t dev)
189{
190 struct gpioiic_softc *sc = device_get_softc(dev);
191 unsigned int val;
192
193 GPIOBUS_LOCK_BUS(sc->sc_busdev);
194 GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, SDA_PIN,
195 GPIO_PIN_INPUT);
196 GPIOBUS_PIN_GET(sc->sc_busdev, sc->sc_dev, SDA_PIN, &val);
197 GPIOBUS_UNLOCK_BUS(sc->sc_busdev);
198
199 return ((int)val);
200}
201
202static int
203gpioiic_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
204{
205 struct gpioiic_softc *sc = device_get_softc(dev);
206
207 GPIOBUS_LOCK_BUS(sc->sc_busdev);
208 GPIOBUS_ACQUIRE_BUS(sc->sc_busdev, sc->sc_dev);
209
210 gpioiic_reset_bus(sc->sc_dev);
211
212 GPIOBUS_RELEASE_BUS(sc->sc_busdev, sc->sc_dev);
213 GPIOBUS_UNLOCK_BUS(sc->sc_busdev);
214
215 return (IIC_ENOADDR);
216}
217
218static devclass_t gpioiic_devclass;
219
220static device_method_t gpioiic_methods[] = {
221 /* Device interface */
222 DEVMETHOD(device_probe, gpioiic_probe),
223 DEVMETHOD(device_attach, gpioiic_attach),
224 DEVMETHOD(device_detach, bus_generic_detach),
225
226 /* iicbb interface */
227 DEVMETHOD(iicbb_callback, gpioiic_callback),
228 DEVMETHOD(iicbb_setsda, gpioiic_setsda),
229 DEVMETHOD(iicbb_setscl, gpioiic_setscl),
230 DEVMETHOD(iicbb_getsda, gpioiic_getsda),
231 DEVMETHOD(iicbb_getscl, gpioiic_getscl),
232 DEVMETHOD(iicbb_reset, gpioiic_reset),
233
234 { 0, 0 }
235};
236
237static driver_t gpioiic_driver = {
238 "gpioiic",
239 gpioiic_methods,
240 sizeof(struct gpioiic_softc),
241};
242
243DRIVER_MODULE(gpioiic, gpiobus, gpioiic_driver, gpioiic_devclass, 0, 0);
244DRIVER_MODULE(iicbb, gpioiic, iicbb_driver, iicbb_devclass, 0, 0);
245MODULE_DEPEND(gpioiic, iicbb, IICBB_MINVER, IICBB_PREFVER, IICBB_MAXVER);
246MODULE_DEPEND(gpioiic, gpiobus, 1, 1, 1);