Cleanup some of the newbus infrastructure.
[dragonfly.git] / sys / dev / misc / lpbb / lpbb.c
... / ...
CommitLineData
1/*-
2 * Copyright (c) 1998 Nicolas Souchu, Marc Bouget
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: src/sys/dev/ppbus/lpbb.c,v 1.11.2.1 2000/05/24 00:20:57 n_hibma Exp $
27 * $DragonFly: src/sys/dev/misc/lpbb/lpbb.c,v 1.4 2005/10/28 03:25:45 dillon Exp $
28 *
29 */
30
31/*
32 * I2C Bit-Banging over parallel port
33 *
34 * See the Official Philips interface description in lpbb(4)
35 */
36
37#include <sys/param.h>
38#include <sys/kernel.h>
39#include <sys/systm.h>
40#include <sys/module.h>
41#include <sys/bus.h>
42#include <sys/uio.h>
43
44#include <machine/clock.h>
45
46#include <bus/ppbus/ppbconf.h>
47#include "ppbus_if.h"
48#include <bus/ppbus/ppbio.h>
49
50#include <bus/iicbus/iiconf.h>
51#include <bus/iicbus/iicbus.h>
52
53#include "iicbb_if.h"
54
55static int lpbb_detect(device_t dev);
56
57static int
58lpbb_probe(device_t dev)
59{
60
61 /* Perhaps call this during identify instead? */
62 if (!lpbb_detect(dev))
63 return (ENXIO);
64
65 device_set_desc(dev, "Parallel I2C bit-banging interface");
66
67 return (0);
68}
69
70static int
71lpbb_attach(device_t dev)
72{
73 device_t bitbang, iicbus;
74
75 /* add generic bit-banging code */
76 bitbang = device_add_child(dev, "iicbb", -1);
77
78 /* add the iicbus to the tree */
79 iicbus = iicbus_alloc_bus(bitbang);
80
81 device_probe_and_attach(bitbang);
82
83 /* XXX should be in iicbb_attach! */
84 device_probe_and_attach(iicbus);
85
86 return (0);
87}
88
89static int
90lpbb_callback(device_t dev, int index, caddr_t *data)
91{
92 device_t ppbus = device_get_parent(dev);
93 int error = 0;
94 int how;
95
96 switch (index) {
97 case IIC_REQUEST_BUS:
98 /* request the ppbus */
99 how = *(int *)data;
100 error = ppb_request_bus(ppbus, dev, how);
101 break;
102
103 case IIC_RELEASE_BUS:
104 /* release the ppbus */
105 error = ppb_release_bus(ppbus, dev);
106 break;
107
108 default:
109 error = EINVAL;
110 }
111
112 return (error);
113}
114
115#define SDA_out 0x80
116#define SCL_out 0x08
117#define SDA_in 0x80
118#define SCL_in 0x08
119#define ALIM 0x20
120#define I2CKEY 0x50
121
122static int getSDA(device_t ppbus)
123{
124 if((ppb_rstr(ppbus)&SDA_in)==SDA_in)
125 return 1;
126 else
127 return 0;
128}
129
130static void setSDA(device_t ppbus, char val)
131{
132 if(val==0)
133 ppb_wdtr(ppbus, (u_char)SDA_out);
134 else
135 ppb_wdtr(ppbus, (u_char)~SDA_out);
136}
137
138static void setSCL(device_t ppbus, unsigned char val)
139{
140 if(val==0)
141 ppb_wctr(ppbus, (u_char)(ppb_rctr(ppbus)&~SCL_out));
142 else
143 ppb_wctr(ppbus, (u_char)(ppb_rctr(ppbus)|SCL_out));
144}
145
146static int lpbb_detect(device_t dev)
147{
148 device_t ppbus = device_get_parent(dev);
149
150 if (ppb_request_bus(ppbus, dev, PPB_DONTWAIT)) {
151 device_printf(dev, "can't allocate ppbus\n");
152 return (0);
153 }
154
155 /* reset bus */
156 setSDA(ppbus, 1);
157 setSCL(ppbus, 1);
158
159 if ((ppb_rstr(ppbus) & I2CKEY) ||
160 ((ppb_rstr(ppbus) & ALIM) != ALIM)) {
161
162 ppb_release_bus(ppbus, dev);
163 return (0);
164 }
165
166 ppb_release_bus(ppbus, dev);
167
168 return (1);
169}
170
171static int
172lpbb_reset(device_t dev, u_char speed, u_char addr, u_char * oldaddr)
173{
174 device_t ppbus = device_get_parent(dev);
175
176 /* reset bus */
177 setSDA(ppbus, 1);
178 setSCL(ppbus, 1);
179
180 return (IIC_ENOADDR);
181}
182
183static void
184lpbb_setlines(device_t dev, int ctrl, int data)
185{
186 device_t ppbus = device_get_parent(dev);
187
188 setSCL(ppbus, ctrl);
189 setSDA(ppbus, data);
190}
191
192static int
193lpbb_getdataline(device_t dev)
194{
195 device_t ppbus = device_get_parent(dev);
196
197 return (getSDA(ppbus));
198}
199
200/*
201 * Because lpbb is a static device that always exists under any attached
202 * ppbus device, and not scanned by the ppbus device, we need an identify
203 * function to install the device.
204 */
205static devclass_t lpbb_devclass;
206
207static device_method_t lpbb_methods[] = {
208 /* device interface */
209 DEVMETHOD(device_identify, bus_generic_identify),
210 DEVMETHOD(device_probe, lpbb_probe),
211 DEVMETHOD(device_attach, lpbb_attach),
212
213 /* bus interface */
214 DEVMETHOD(bus_print_child, bus_generic_print_child),
215
216 /* iicbb interface */
217 DEVMETHOD(iicbb_callback, lpbb_callback),
218 DEVMETHOD(iicbb_setlines, lpbb_setlines),
219 DEVMETHOD(iicbb_getdataline, lpbb_getdataline),
220 DEVMETHOD(iicbb_reset, lpbb_reset),
221
222 { 0, 0 }
223};
224
225static driver_t lpbb_driver = {
226 "lpbb",
227 lpbb_methods,
228 1,
229};
230
231DRIVER_MODULE(lpbb, ppbus, lpbb_driver, lpbb_devclass, 0, 0);