]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/iicbus/twsi/a10_twsi.c
MFV r299425:
[FreeBSD/FreeBSD.git] / sys / dev / iicbus / twsi / a10_twsi.c
1 /*-
2  * Copyright (c) 2016 Emmanuel Vadot <manu@bidouilliste.com>
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 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 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
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/bus.h>
33 #include <sys/kernel.h>
34 #include <sys/module.h>
35 #include <sys/resource.h>
36
37 #include <machine/bus.h>
38 #include <machine/resource.h>
39
40 #include <sys/rman.h>
41
42 #include <sys/lock.h>
43 #include <sys/mutex.h>
44
45 #include <dev/iicbus/iiconf.h>
46 #include <dev/iicbus/iicbus.h>
47 #include <dev/iicbus/twsi/twsi.h>
48 #include <dev/ofw/ofw_bus.h>
49 #include <dev/ofw/ofw_bus_subr.h>
50
51 #include <dev/extres/clk/clk.h>
52 #include <dev/extres/hwreset/hwreset.h>
53
54 #include "iicbus_if.h"
55
56 #define TWI_ADDR        0x0
57 #define TWI_XADDR       0x4
58 #define TWI_DATA        0x8
59 #define TWI_CNTR        0xC
60 #define TWI_STAT        0x10
61 #define TWI_CCR         0x14
62 #define TWI_SRST        0x18
63 #define TWI_EFR         0x1C
64 #define TWI_LCR         0x20
65
66 static struct ofw_compat_data compat_data[] = {
67         {"allwinner,sun4i-a10-i2c", 1},
68         {"allwinner,sun6i-a31-i2c", 1},
69         {NULL, 0},
70 };
71
72 static int
73 a10_twsi_probe(device_t dev)
74 {
75
76         if (!ofw_bus_status_okay(dev))
77                 return (ENXIO);
78
79         if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
80                 return (ENXIO);
81
82         device_set_desc(dev, "Allwinner Integrated I2C Bus Controller");
83         return (BUS_PROBE_DEFAULT);
84 }
85
86 static int
87 a10_twsi_attach(device_t dev)
88 {
89         struct twsi_softc *sc;
90         clk_t clk;
91         hwreset_t rst;
92         int error;
93
94         sc = device_get_softc(dev);
95
96         /* De-assert reset */
97         if (hwreset_get_by_ofw_idx(dev, 0, &rst) == 0) {
98                 error = hwreset_deassert(rst);
99                 if (error != 0) {
100                         device_printf(dev, "could not de-assert reset\n");
101                         return (error);
102                 }
103         }
104
105         /* Activate clock */
106         error = clk_get_by_ofw_index(dev, 0, &clk);
107         if (error != 0) {
108                 device_printf(dev, "could not find clock\n");
109                 return (error);
110         }
111         error = clk_enable(clk);
112         if (error != 0) {
113                 device_printf(dev, "could not enable clock\n");
114                 return (error);
115         }
116
117         sc->reg_data = TWI_DATA;
118         sc->reg_slave_addr = TWI_ADDR;
119         sc->reg_slave_ext_addr = TWI_XADDR;
120         sc->reg_control = TWI_CNTR;
121         sc->reg_status = TWI_STAT;
122         sc->reg_baud_rate = TWI_CCR;
123         sc->reg_soft_reset = TWI_SRST;
124
125         /* Setup baud rate params */
126         sc->baud_rate[IIC_SLOW].param = TWSI_BAUD_RATE_PARAM(11, 2);
127         sc->baud_rate[IIC_FAST].param = TWSI_BAUD_RATE_PARAM(11, 2);
128         sc->baud_rate[IIC_FASTEST].param = TWSI_BAUD_RATE_PARAM(2, 2);
129
130         return (twsi_attach(dev));
131 }
132
133 static phandle_t
134 a10_twsi_get_node(device_t bus, device_t dev)
135 {
136         return (ofw_bus_get_node(bus));
137 }
138
139 static device_method_t a10_twsi_methods[] = {
140         /* device interface */
141         DEVMETHOD(device_probe,         a10_twsi_probe),
142         DEVMETHOD(device_attach,        a10_twsi_attach),
143
144         /* OFW methods */
145         DEVMETHOD(ofw_bus_get_node,     a10_twsi_get_node),
146
147         { 0, 0 }
148 };
149
150 DEFINE_CLASS_1(iichb, a10_twsi_driver, a10_twsi_methods,
151     sizeof(struct twsi_softc), twsi_driver);
152
153 static devclass_t a10_twsi_devclass;
154
155 DRIVER_MODULE(a10_twsi, simplebus, a10_twsi_driver, a10_twsi_devclass, 0, 0);
156 DRIVER_MODULE(iicbus, a10_twsi, iicbus_driver, iicbus_devclass, 0, 0);
157 MODULE_DEPEND(a10_twsi, iicbus, 1, 1, 1);