1 /* $NetBSD: ausmbus_psc.c,v 1.8 2007/10/17 19:55:35 garbled Exp $ */
4 * Copyright (c) 2006 Shigeyuki Fukushima.
7 * Written by Shigeyuki Fukushima.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above
15 * copyright notice, this list of conditions and the following
16 * disclaimer in the documentation and/or other materials provided
17 * with the distribution.
18 * 3. The name of the author may not be used to endorse or promote
19 * products derived from this software without specific prior
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
23 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
26 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
28 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 #include <sys/cdefs.h>
36 __KERNEL_RCSID(0, "$NetBSD: ausmbus_psc.c,v 1.8 2007/10/17 19:55:35 garbled Exp $");
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/device.h>
43 #include <sys/errno.h>
45 #include <machine/bus.h>
46 #include <machine/cpu.h>
48 #include <mips/alchemy/dev/aupscreg.h>
49 #include <mips/alchemy/dev/aupscvar.h>
50 #include <mips/alchemy/dev/ausmbus_pscreg.h>
52 #include <dev/i2c/i2cvar.h>
53 #include <dev/i2c/i2c_bitbang.h>
55 struct ausmbus_softc
{
58 /* protocol comoon fields */
59 struct aupsc_controller sc_ctrl
;
61 /* protocol specific fields */
62 struct i2c_controller sc_i2c
;
63 i2c_addr_t sc_smbus_slave_addr
;
67 #define ausmbus_reg_read(sc, reg) \
68 bus_space_read_4(sc->sc_ctrl.psc_bust, sc->sc_ctrl.psc_bush, reg)
69 #define ausmbus_reg_write(sc, reg, val) \
70 bus_space_write_4(sc->sc_ctrl.psc_bust, sc->sc_ctrl.psc_bush, reg, \
74 static int ausmbus_match(struct device
*, struct cfdata
*, void *);
75 static void ausmbus_attach(struct device
*, struct device
*, void *);
77 CFATTACH_DECL(ausmbus
, sizeof(struct ausmbus_softc
),
78 ausmbus_match
, ausmbus_attach
, NULL
, NULL
);
80 /* fuctions for i2c_controller */
81 static int ausmbus_acquire_bus(void *, int);
82 static void ausmbus_release_bus(void *, int);
83 static int ausmbus_exec(void *cookie
, i2c_op_t op
, i2c_addr_t addr
,
84 const void *cmd
, size_t cmdlen
, void *vbuf
,
85 size_t buflen
, int flags
);
87 /* subroutine functions for i2c_controller */
88 static int ausmbus_quick_write(struct ausmbus_softc
*);
89 static int ausmbus_quick_read(struct ausmbus_softc
*);
90 static int ausmbus_receive_1(struct ausmbus_softc
*, uint8_t *);
91 static int ausmbus_read_1(struct ausmbus_softc
*, uint8_t, uint8_t *);
92 static int ausmbus_read_2(struct ausmbus_softc
*, uint8_t, uint16_t *);
93 static int ausmbus_send_1(struct ausmbus_softc
*, uint8_t);
94 static int ausmbus_write_1(struct ausmbus_softc
*, uint8_t, uint8_t);
95 static int ausmbus_write_2(struct ausmbus_softc
*, uint8_t, uint16_t);
96 static int ausmbus_wait_mastertx(struct ausmbus_softc
*sc
);
97 static int ausmbus_wait_masterrx(struct ausmbus_softc
*sc
);
98 static int ausmbus_initiate_xfer(void *, i2c_addr_t
, int);
99 static int ausmbus_read_byte(void *arg
, uint8_t *vp
, int flags
);
100 static int ausmbus_write_byte(void *arg
, uint8_t v
, int flags
);
104 ausmbus_match(struct device
*parent
, struct cfdata
*cf
, void *aux
)
106 struct aupsc_attach_args
*aa
= (struct aupsc_attach_args
*)aux
;
108 if (strcmp(aa
->aupsc_name
, cf
->cf_name
) != 0)
115 ausmbus_attach(struct device
*parent
, struct device
*self
, void *aux
)
117 struct ausmbus_softc
*sc
= (struct ausmbus_softc
*)self
;
118 struct aupsc_attach_args
*aa
= (struct aupsc_attach_args
*)aux
;
119 struct i2cbus_attach_args iba
;
121 aprint_normal(": Alchemy PSC SMBus protocol\n");
124 sc
->sc_ctrl
= aa
->aupsc_ctrl
;
126 /* Initialize i2c_controller for SMBus */
127 sc
->sc_i2c
.ic_cookie
= sc
;
128 sc
->sc_i2c
.ic_acquire_bus
= ausmbus_acquire_bus
;
129 sc
->sc_i2c
.ic_release_bus
= ausmbus_release_bus
;
130 sc
->sc_i2c
.ic_send_start
= NULL
;
131 sc
->sc_i2c
.ic_send_stop
= NULL
;
132 sc
->sc_i2c
.ic_initiate_xfer
= NULL
;
133 sc
->sc_i2c
.ic_read_byte
= NULL
;
134 sc
->sc_i2c
.ic_write_byte
= NULL
;
135 sc
->sc_i2c
.ic_exec
= ausmbus_exec
;
136 sc
->sc_smbus_timeout
= 10;
138 iba
.iba_tag
= &sc
->sc_i2c
;
139 (void) config_found_ia(&sc
->sc_dev
, "i2cbus", &iba
, iicbus_print
);
143 ausmbus_acquire_bus(void *arg
, int flags
)
145 struct ausmbus_softc
*sc
= arg
;
148 /* Select SMBus Protocol & Enable PSC */
149 sc
->sc_ctrl
.psc_enable(sc
, AUPSC_SEL_SMBUS
);
150 v
= ausmbus_reg_read(sc
, AUPSC_SMBSTAT
);
151 if ((v
& SMBUS_STAT_SR
) == 0) {
152 /* PSC is not ready */
156 /* Setup SMBus Configuration register */
157 v
= SMBUS_CFG_DD
; /* Disable DMA */
158 v
|= SMBUS_CFG_RT_SET(SMBUS_CFG_RT_FIFO8
); /* Rx FIFO 8data */
159 v
|= SMBUS_CFG_TT_SET(SMBUS_CFG_TT_FIFO8
); /* Tx FIFO 8data */
160 v
|= SMBUS_CFG_DIV_SET(SMBUS_CFG_DIV8
); /* pscn_mainclk/8 */
161 v
&= ~SMBUS_CFG_SFM
; /* Standard Mode */
162 ausmbus_reg_write(sc
, AUPSC_SMBCFG
, v
);
164 /* Setup SMBus Protocol Timing register */
165 v
= SMBUS_TMR_TH_SET(SMBUS_TMR_STD_TH
)
166 | SMBUS_TMR_PS_SET(SMBUS_TMR_STD_PS
)
167 | SMBUS_TMR_PU_SET(SMBUS_TMR_STD_PU
)
168 | SMBUS_TMR_SH_SET(SMBUS_TMR_STD_SH
)
169 | SMBUS_TMR_SU_SET(SMBUS_TMR_STD_SU
)
170 | SMBUS_TMR_CL_SET(SMBUS_TMR_STD_CL
)
171 | SMBUS_TMR_CH_SET(SMBUS_TMR_STD_CH
);
172 ausmbus_reg_write(sc
, AUPSC_SMBTMR
, v
);
174 /* Setup SMBus Mask register */
175 v
= SMBUS_MSK_ALLMASK
;
176 ausmbus_reg_write(sc
, AUPSC_SMBMSK
, v
);
179 v
= ausmbus_reg_read(sc
, AUPSC_SMBCFG
);
181 ausmbus_reg_write(sc
, AUPSC_SMBCFG
, v
);
182 v
= ausmbus_reg_read(sc
, AUPSC_SMBSTAT
);
183 if ((v
& SMBUS_STAT_SR
) == 0) {
184 /* SMBus is not ready */
188 #ifdef AUSMBUS_PSC_DEBUG
189 aprint_normal("AuSMBus enabled.\n");
190 aprint_normal("AuSMBus smbconfig: 0x%08x\n",
191 ausmbus_reg_read(sc
, AUPSC_SMBCFG
));
192 aprint_normal("AuSMBus smbstatus: 0x%08x\n",
193 ausmbus_reg_read(sc
, AUPSC_SMBSTAT
));
194 aprint_normal("AuSMBus smbtmr : 0x%08x\n",
195 ausmbus_reg_read(sc
, AUPSC_SMBTMR
));
196 aprint_normal("AuSMBus smbmask : 0x%08x\n",
197 ausmbus_reg_read(sc
, AUPSC_SMBMSK
));
204 ausmbus_release_bus(void *arg
, int flags
)
206 struct ausmbus_softc
*sc
= arg
;
208 ausmbus_reg_write(sc
, AUPSC_SMBCFG
, 0);
209 sc
->sc_ctrl
.psc_disable(sc
);
215 ausmbus_exec(void *cookie
, i2c_op_t op
, i2c_addr_t addr
, const void *vcmd
,
216 size_t cmdlen
, void *vbuf
, size_t buflen
, int flags
)
218 struct ausmbus_softc
*sc
= (struct ausmbus_softc
*)cookie
;
219 const uint8_t *cmd
= vcmd
;
221 sc
->sc_smbus_slave_addr
= addr
;
224 if ((I2C_OP_READ_P(op
)) && (cmdlen
== 0) && (buflen
== 1)) {
225 return ausmbus_receive_1(sc
, (uint8_t *)vbuf
);
229 if ((I2C_OP_READ_P(op
)) && (cmdlen
== 1) && (buflen
== 1)) {
230 return ausmbus_read_1(sc
, *cmd
, (uint8_t *)vbuf
);
234 if ((I2C_OP_READ_P(op
)) && (cmdlen
== 1) && (buflen
== 2)) {
235 return ausmbus_read_2(sc
, *cmd
, (uint16_t *)vbuf
);
239 if ((I2C_OP_READ_P(op
)) && (cmdlen
== 0) && (buflen
== 0)) {
240 return ausmbus_quick_read(sc
);
244 if ((I2C_OP_WRITE_P(op
)) && (cmdlen
== 0) && (buflen
== 1)) {
245 return ausmbus_send_1(sc
, *((uint8_t *)vbuf
));
249 if ((I2C_OP_WRITE_P(op
)) && (cmdlen
== 1) && (buflen
== 1)) {
250 return ausmbus_write_1(sc
, *cmd
, *((uint8_t *)vbuf
));
254 if ((I2C_OP_WRITE_P(op
)) && (cmdlen
== 1) && (buflen
== 2)) {
255 return ausmbus_write_2(sc
, *cmd
, *((uint16_t *)vbuf
));
259 if ((I2C_OP_WRITE_P(op
)) && (cmdlen
== 0) && (buflen
== 0)) {
260 return ausmbus_quick_write(sc
);
264 * XXX: TODO Please Support other protocols defined in SMBus 2.0
267 * - Clock write-block read process cal
268 * - SMBus host notify protocol
270 * - Read quick and write quick have not been tested!
277 ausmbus_receive_1(struct ausmbus_softc
*sc
, uint8_t *vp
)
281 error
= ausmbus_initiate_xfer(sc
, sc
->sc_smbus_slave_addr
, I2C_F_READ
);
285 error
= ausmbus_read_byte(sc
, vp
, I2C_F_STOP
);
294 ausmbus_read_1(struct ausmbus_softc
*sc
, uint8_t cmd
, uint8_t *vp
)
298 error
= ausmbus_initiate_xfer(sc
, sc
->sc_smbus_slave_addr
, I2C_F_WRITE
);
303 error
= ausmbus_write_byte(sc
, cmd
, I2C_F_READ
);
308 error
= ausmbus_initiate_xfer(sc
, sc
->sc_smbus_slave_addr
, I2C_F_READ
);
313 error
= ausmbus_read_byte(sc
, vp
, I2C_F_STOP
);
322 ausmbus_read_2(struct ausmbus_softc
*sc
, uint8_t cmd
, uint16_t *vp
)
327 error
= ausmbus_initiate_xfer(sc
, sc
->sc_smbus_slave_addr
, I2C_F_WRITE
);
332 error
= ausmbus_write_byte(sc
, cmd
, I2C_F_READ
);
337 error
= ausmbus_initiate_xfer(sc
, sc
->sc_smbus_slave_addr
, I2C_F_READ
);
342 error
= ausmbus_read_byte(sc
, &low
, 0);
347 error
= ausmbus_read_byte(sc
, &high
, I2C_F_STOP
);
352 *vp
= (high
<< 8) | low
;
358 ausmbus_send_1(struct ausmbus_softc
*sc
, uint8_t val
)
362 error
= ausmbus_initiate_xfer(sc
, sc
->sc_smbus_slave_addr
, I2C_F_WRITE
);
367 error
= ausmbus_write_byte(sc
, val
, I2C_F_STOP
);
376 ausmbus_write_1(struct ausmbus_softc
*sc
, uint8_t cmd
, uint8_t val
)
380 error
= ausmbus_initiate_xfer(sc
, sc
->sc_smbus_slave_addr
, I2C_F_WRITE
);
385 error
= ausmbus_write_byte(sc
, cmd
, 0);
390 error
= ausmbus_write_byte(sc
, val
, I2C_F_STOP
);
399 ausmbus_write_2(struct ausmbus_softc
*sc
, uint8_t cmd
, uint16_t val
)
404 high
= (val
>> 8) & 0xff;
407 error
= ausmbus_initiate_xfer(sc
, sc
->sc_smbus_slave_addr
, I2C_F_WRITE
);
412 error
= ausmbus_write_byte(sc
, cmd
, 0);
417 error
= ausmbus_write_byte(sc
, low
, 0);
422 error
= ausmbus_write_byte(sc
, high
, I2C_F_STOP
);
431 * XXX The quick_write() and quick_read() routines have not been tested!
434 ausmbus_quick_write(struct ausmbus_softc
*sc
)
436 return ausmbus_initiate_xfer(sc
, sc
->sc_smbus_slave_addr
,
437 I2C_F_STOP
| I2C_F_WRITE
);
441 ausmbus_quick_read(struct ausmbus_softc
*sc
)
443 return ausmbus_initiate_xfer(sc
, sc
->sc_smbus_slave_addr
,
444 I2C_F_STOP
| I2C_F_READ
);
448 ausmbus_wait_mastertx(struct ausmbus_softc
*sc
)
454 timeout
= sc
->sc_smbus_timeout
;
457 v
= ausmbus_reg_read(sc
, AUPSC_SMBEVNT
);
458 #ifdef AUSMBUS_PSC_DEBUG
459 aprint_normal("AuSMBus: ausmbus_wait_mastertx(): psc_smbevnt=0x%08x\n", v
);
461 if ((v
& SMBUS_EVNT_TU
) != 0)
463 if ((v
& SMBUS_EVNT_MD
) != 0)
465 if ((v
& (SMBUS_EVNT_DN
| SMBUS_EVNT_AN
| SMBUS_EVNT_AL
))
472 } while (timeout
> 0);
475 ausmbus_reg_write(sc
, AUPSC_SMBEVNT
,
476 SMBUS_EVNT_DN
| SMBUS_EVNT_AN
| SMBUS_EVNT_AL
);
477 #ifdef AUSMBUS_PSC_DEBUG
478 aprint_normal("AuSMBus: ausmbus_wait_mastertx(): Tx error\n");
483 /* Reset Event TU (Tx Underflow) */
484 ausmbus_reg_write(sc
, AUPSC_SMBEVNT
, SMBUS_EVNT_TU
| SMBUS_EVNT_MD
);
486 #ifdef AUSMBUS_PSC_DEBUG
487 v
= ausmbus_reg_read(sc
, AUPSC_SMBEVNT
);
488 aprint_normal("AuSMBus: ausmbus_wait_mastertx(): psc_smbevnt=0x%08x (reset)\n", v
);
494 ausmbus_wait_masterrx(struct ausmbus_softc
*sc
)
498 timeout
= sc
->sc_smbus_timeout
;
500 if (ausmbus_wait_mastertx(sc
) != 0)
504 v
= ausmbus_reg_read(sc
, AUPSC_SMBSTAT
);
505 #ifdef AUSMBUS_PSC_DEBUG
506 aprint_normal("AuSMBus: ausmbus_wait_masterrx(): psc_smbstat=0x%08x\n", v
);
508 if ((v
& SMBUS_STAT_RE
) == 0)
512 } while (timeout
> 0);
518 ausmbus_initiate_xfer(void *arg
, i2c_addr_t addr
, int flags
)
520 struct ausmbus_softc
*sc
= arg
;
523 /* Tx/Rx Slave Address */
524 v
= (addr
<< 1) & SMBUS_TXRX_ADDRDATA
;
525 if ((flags
& I2C_F_READ
) != 0)
527 if ((flags
& I2C_F_STOP
) != 0)
529 ausmbus_reg_write(sc
, AUPSC_SMBTXRX
, v
);
532 ausmbus_reg_write(sc
, AUPSC_SMBPCR
, SMBUS_PCR_MS
);
534 if (ausmbus_wait_mastertx(sc
) != 0)
541 ausmbus_read_byte(void *arg
, uint8_t *vp
, int flags
)
543 struct ausmbus_softc
*sc
= arg
;
546 if ((flags
& I2C_F_STOP
) != 0) {
547 ausmbus_reg_write(sc
, AUPSC_SMBTXRX
, SMBUS_TXRX_STP
);
549 ausmbus_reg_write(sc
, AUPSC_SMBTXRX
, 0);
552 if (ausmbus_wait_masterrx(sc
) != 0)
555 v
= ausmbus_reg_read(sc
, AUPSC_SMBTXRX
);
556 *vp
= v
& SMBUS_TXRX_ADDRDATA
;
562 ausmbus_write_byte(void *arg
, uint8_t v
, int flags
)
564 struct ausmbus_softc
*sc
= arg
;
566 if ((flags
& I2C_F_STOP
) != 0) {
567 ausmbus_reg_write(sc
, AUPSC_SMBTXRX
, (v
| SMBUS_TXRX_STP
));
568 } else if ((flags
& I2C_F_READ
) != 0) {
569 ausmbus_reg_write(sc
, AUPSC_SMBTXRX
, (v
| SMBUS_TXRX_RSR
));
571 ausmbus_reg_write(sc
, AUPSC_SMBTXRX
, v
);
574 if (ausmbus_wait_mastertx(sc
) != 0)