pcf.c revision 181303
138781Snsouch/*- 238781Snsouch * Copyright (c) 1998 Nicolas Souchu, Marc Bouget 3129704Sjoerg * Copyright (c) 2004 Joerg Wunsch 438781Snsouch * All rights reserved. 538781Snsouch * 638781Snsouch * Redistribution and use in source and binary forms, with or without 738781Snsouch * modification, are permitted provided that the following conditions 838781Snsouch * are met: 938781Snsouch * 1. Redistributions of source code must retain the above copyright 1038781Snsouch * notice, this list of conditions and the following disclaimer. 1138781Snsouch * 2. Redistributions in binary form must reproduce the above copyright 1238781Snsouch * notice, this list of conditions and the following disclaimer in the 1338781Snsouch * documentation and/or other materials provided with the distribution. 1438781Snsouch * 1538781Snsouch * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1638781Snsouch * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1738781Snsouch * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1838781Snsouch * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1938781Snsouch * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2038781Snsouch * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2138781Snsouch * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2238781Snsouch * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2338781Snsouch * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2438781Snsouch * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2538781Snsouch * SUCH DAMAGE. 2638781Snsouch */ 27115703Sobrien 28115703Sobrien#include <sys/cdefs.h> 29115703Sobrien__FBSDID("$FreeBSD: head/sys/dev/pcf/pcf.c 181303 2008-08-04 20:46:15Z jhb $"); 30115703Sobrien 3138781Snsouch#include <sys/param.h> 32181303Sjhb#include <sys/bus.h> 33181303Sjhb#include <sys/lock.h> 3438781Snsouch#include <sys/kernel.h> 3538781Snsouch#include <sys/module.h> 36181303Sjhb#include <sys/mutex.h> 37181303Sjhb#include <sys/systm.h> 3838781Snsouch 3955939Snsouch#include <machine/bus.h> 4055939Snsouch#include <machine/resource.h> 41129704Sjoerg 4255939Snsouch#include <sys/rman.h> 4338781Snsouch 4438781Snsouch#include <dev/iicbus/iiconf.h> 45129704Sjoerg#include <dev/pcf/pcfvar.h> 4638781Snsouch#include "iicbus_if.h" 4738781Snsouch 48129704Sjoerg/* Not so official debugging option. */ 49129704Sjoerg/* #define PCFDEBUG */ 5055939Snsouch 51129704Sjoergstatic int pcf_wait_byte(struct pcf_softc *pcf); 52129704Sjoergstatic int pcf_noack(struct pcf_softc *pcf, int timeout); 53181303Sjhbstatic void pcf_stop_locked(struct pcf_softc *pcf); 5438781Snsouch 5538781Snsouch/* 5638781Snsouch * Polling mode for master operations wait for a new 57181303Sjhb * byte incoming or outgoing 5838781Snsouch */ 59181303Sjhbstatic int 60129704Sjoergpcf_wait_byte(struct pcf_softc *sc) 6138781Snsouch{ 6238781Snsouch int counter = TIMEOUT; 6338781Snsouch 64181303Sjhb PCF_ASSERT_LOCKED(sc); 6538781Snsouch while (counter--) { 6638781Snsouch 67129704Sjoerg if ((pcf_get_S1(sc) & PIN) == 0) 6838781Snsouch return (0); 6938781Snsouch } 7038781Snsouch 71129893Snsouch#ifdef PCFDEBUG 72129893Snsouch printf("pcf: timeout!\n"); 73129893Snsouch#endif 74129893Snsouch 7538781Snsouch return (IIC_ETIMEOUT); 7638781Snsouch} 7738781Snsouch 78181303Sjhbstatic void 79181303Sjhbpcf_stop_locked(struct pcf_softc *sc) 8038781Snsouch{ 8138781Snsouch 82181303Sjhb PCF_ASSERT_LOCKED(sc); 83129704Sjoerg#ifdef PCFDEBUG 84129704Sjoerg device_printf(dev, " >> stop\n"); 85129704Sjoerg#endif 8640784Snsouch /* 8740784Snsouch * Send STOP condition iff the START condition was previously sent. 88108533Sschweikh * STOP is sent only once even if an iicbus_stop() is called after 89129704Sjoerg * an iicbus_read()... see pcf_read(): the PCF needs to send the stop 9040784Snsouch * before the last char is read. 9140784Snsouch */ 92129704Sjoerg if (sc->pcf_started) { 9340784Snsouch /* set stop condition and enable IT */ 94129704Sjoerg pcf_set_S1(sc, PIN|ESO|ENI|STO|ACK); 9538781Snsouch 96129704Sjoerg sc->pcf_started = 0; 9740784Snsouch } 9838781Snsouch} 9938781Snsouch 100181303Sjhbstatic int 101129704Sjoergpcf_noack(struct pcf_softc *sc, int timeout) 10238781Snsouch{ 10340784Snsouch int noack; 10440784Snsouch int k = timeout/10; 10540784Snsouch 106181303Sjhb PCF_ASSERT_LOCKED(sc); 10740784Snsouch do { 108129704Sjoerg noack = pcf_get_S1(sc) & LRB; 10940784Snsouch if (!noack) 11040784Snsouch break; 11140784Snsouch DELAY(10); /* XXX wait 10 us */ 11240784Snsouch } while (k--); 11340784Snsouch 11440784Snsouch return (noack); 11540784Snsouch} 11640784Snsouch 117129704Sjoergint 118129704Sjoergpcf_repeated_start(device_t dev, u_char slave, int timeout) 11940784Snsouch{ 120129704Sjoerg struct pcf_softc *sc = DEVTOSOFTC(dev); 12138781Snsouch int error = 0; 12238781Snsouch 123181303Sjhb PCF_LOCK(sc); 124129704Sjoerg#ifdef PCFDEBUG 125129704Sjoerg device_printf(dev, " >> repeated start for slave %#x\n", 126129704Sjoerg (unsigned)slave); 127129704Sjoerg#endif 12838781Snsouch /* repeated start */ 129129704Sjoerg pcf_set_S1(sc, ESO|STA|STO|ACK); 13038781Snsouch 13138781Snsouch /* set slave address to PCF. Last bit (LSB) must be set correctly 13238781Snsouch * according to transfer direction */ 133129704Sjoerg pcf_set_S0(sc, slave); 13438781Snsouch 13538781Snsouch /* wait for address sent, polling */ 136129704Sjoerg if ((error = pcf_wait_byte(sc))) 13738781Snsouch goto error; 13838781Snsouch 13940784Snsouch /* check for ack */ 140129704Sjoerg if (pcf_noack(sc, timeout)) { 14138781Snsouch error = IIC_ENOACK; 142129893Snsouch#ifdef PCFDEBUG 143129893Snsouch printf("pcf: no ack on repeated_start!\n"); 144129893Snsouch#endif 14538781Snsouch goto error; 14638781Snsouch } 14738781Snsouch 148181303Sjhb PCF_UNLOCK(sc); 14938781Snsouch return (0); 15038781Snsouch 15138781Snsoucherror: 152181303Sjhb pcf_stop_locked(sc); 153181303Sjhb PCF_UNLOCK(sc); 15438781Snsouch return (error); 15538781Snsouch} 15638781Snsouch 157129704Sjoergint 158129704Sjoergpcf_start(device_t dev, u_char slave, int timeout) 15938781Snsouch{ 160129704Sjoerg struct pcf_softc *sc = DEVTOSOFTC(dev); 16138781Snsouch int error = 0; 16238781Snsouch 163181303Sjhb PCF_LOCK(sc); 164129704Sjoerg#ifdef PCFDEBUG 165129704Sjoerg device_printf(dev, " >> start for slave %#x\n", (unsigned)slave); 166129704Sjoerg#endif 167129893Snsouch if ((pcf_get_S1(sc) & nBB) == 0) { 168129893Snsouch#ifdef PCFDEBUG 169129893Snsouch printf("pcf: busy!\n"); 170129893Snsouch#endif 171181303Sjhb PCF_UNLOCK(sc); 17238781Snsouch return (IIC_EBUSBSY); 173129893Snsouch } 17438781Snsouch 17538781Snsouch /* set slave address to PCF. Last bit (LSB) must be set correctly 17638781Snsouch * according to transfer direction */ 177129704Sjoerg pcf_set_S0(sc, slave); 17838781Snsouch 17938781Snsouch /* START only */ 180129704Sjoerg pcf_set_S1(sc, PIN|ESO|STA|ACK); 18138781Snsouch 182129704Sjoerg sc->pcf_started = 1; 18340784Snsouch 18438781Snsouch /* wait for address sent, polling */ 185129704Sjoerg if ((error = pcf_wait_byte(sc))) 18638781Snsouch goto error; 18738781Snsouch 18840784Snsouch /* check for ACK */ 189129704Sjoerg if (pcf_noack(sc, timeout)) { 19038781Snsouch error = IIC_ENOACK; 191129893Snsouch#ifdef PCFDEBUG 192129893Snsouch printf("pcf: no ack on start!\n"); 193129893Snsouch#endif 19438781Snsouch goto error; 19538781Snsouch } 19638781Snsouch 197181303Sjhb PCF_UNLOCK(sc); 19838781Snsouch return (0); 19938781Snsouch 20038781Snsoucherror: 201181303Sjhb pcf_stop_locked(sc); 202181303Sjhb PCF_UNLOCK(sc); 20338781Snsouch return (error); 20438781Snsouch} 20538781Snsouch 206181303Sjhbint 207181303Sjhbpcf_stop(device_t dev) 208181303Sjhb{ 209181303Sjhb struct pcf_softc *sc = DEVTOSOFTC(dev); 210181303Sjhb 211181303Sjhb#ifdef PCFDEBUG 212181303Sjhb device_printf(dev, " >> stop\n"); 213181303Sjhb#endif 214181303Sjhb PCF_LOCK(sc); 215181303Sjhb pcf_stop_locked(sc); 216181303Sjhb PCF_UNLOCK(sc); 217181303Sjhb 218181303Sjhb return (0); 219181303Sjhb} 220181303Sjhb 221129704Sjoergvoid 222129704Sjoergpcf_intr(void *arg) 22338781Snsouch{ 224129893Snsouch struct pcf_softc *sc = arg; 22538781Snsouch char data, status, addr; 22638781Snsouch char error = 0; 22738781Snsouch 228181303Sjhb PCF_LOCK(sc); 229129704Sjoerg status = pcf_get_S1(sc); 23038781Snsouch 23138781Snsouch if (status & PIN) { 232129893Snsouch printf("pcf: spurious interrupt, status=0x%x\n", 233129893Snsouch status & 0xff); 23438781Snsouch 23538781Snsouch goto error; 236129704Sjoerg } 23738781Snsouch 23838781Snsouch if (status & LAB) 239129893Snsouch printf("pcf: bus arbitration lost!\n"); 24038781Snsouch 24138781Snsouch if (status & BER) { 24238781Snsouch error = IIC_EBUSERR; 243129704Sjoerg iicbus_intr(sc->iicbus, INTR_ERROR, &error); 24438781Snsouch 24538781Snsouch goto error; 24638781Snsouch } 24738781Snsouch 24838781Snsouch do { 249129704Sjoerg status = pcf_get_S1(sc); 25038781Snsouch 251129704Sjoerg switch(sc->pcf_slave_mode) { 25238781Snsouch 25338781Snsouch case SLAVE_TRANSMITTER: 25438781Snsouch if (status & LRB) { 25538781Snsouch /* ack interrupt line */ 256129704Sjoerg dummy_write(sc); 25738781Snsouch 25838781Snsouch /* no ack, don't send anymore */ 259129704Sjoerg sc->pcf_slave_mode = SLAVE_RECEIVER; 26038781Snsouch 261129704Sjoerg iicbus_intr(sc->iicbus, INTR_NOACK, NULL); 26238781Snsouch break; 26338781Snsouch } 26438781Snsouch 26538781Snsouch /* get data from upper code */ 266129704Sjoerg iicbus_intr(sc->iicbus, INTR_TRANSMIT, &data); 26738781Snsouch 268129704Sjoerg pcf_set_S0(sc, data); 269129704Sjoerg break; 270129704Sjoerg 27138781Snsouch case SLAVE_RECEIVER: 27238781Snsouch if (status & AAS) { 273129704Sjoerg addr = pcf_get_S0(sc); 27438781Snsouch 27538781Snsouch if (status & AD0) 276129704Sjoerg iicbus_intr(sc->iicbus, INTR_GENERAL, &addr); 27738781Snsouch else 278129704Sjoerg iicbus_intr(sc->iicbus, INTR_START, &addr); 27938781Snsouch 28038781Snsouch if (addr & LSB) { 281129704Sjoerg sc->pcf_slave_mode = SLAVE_TRANSMITTER; 28238781Snsouch 28338781Snsouch /* get the first char from upper code */ 284129704Sjoerg iicbus_intr(sc->iicbus, INTR_TRANSMIT, &data); 28538781Snsouch 28638781Snsouch /* send first data byte */ 287129704Sjoerg pcf_set_S0(sc, data); 28838781Snsouch } 28938781Snsouch 29038781Snsouch break; 29138781Snsouch } 29238781Snsouch 29338781Snsouch /* stop condition received? */ 29438781Snsouch if (status & STS) { 29538781Snsouch /* ack interrupt line */ 296129704Sjoerg dummy_read(sc); 29738781Snsouch 29838781Snsouch /* emulate intr stop condition */ 299129704Sjoerg iicbus_intr(sc->iicbus, INTR_STOP, NULL); 30038781Snsouch 30138781Snsouch } else { 30238781Snsouch /* get data, ack interrupt line */ 303129704Sjoerg data = pcf_get_S0(sc); 30438781Snsouch 30538781Snsouch /* deliver the character */ 306129704Sjoerg iicbus_intr(sc->iicbus, INTR_RECEIVE, &data); 30738781Snsouch } 30838781Snsouch break; 30938781Snsouch 31038781Snsouch default: 31187599Sobrien panic("%s: unknown slave mode (%d)!", __func__, 312129704Sjoerg sc->pcf_slave_mode); 31338781Snsouch } 31438781Snsouch 315129704Sjoerg } while ((pcf_get_S1(sc) & PIN) == 0); 316181303Sjhb PCF_UNLOCK(sc); 31738781Snsouch 31838781Snsouch return; 31938781Snsouch 32038781Snsoucherror: 32138781Snsouch /* unknown event on bus...reset PCF */ 322129704Sjoerg pcf_set_S1(sc, PIN|ESO|ENI|ACK); 32338781Snsouch 324129704Sjoerg sc->pcf_slave_mode = SLAVE_RECEIVER; 325181303Sjhb PCF_UNLOCK(sc); 32638781Snsouch 32738781Snsouch return; 32838781Snsouch} 32938781Snsouch 330129704Sjoergint 331129704Sjoergpcf_rst_card(device_t dev, u_char speed, u_char addr, u_char *oldaddr) 33238781Snsouch{ 333129704Sjoerg struct pcf_softc *sc = DEVTOSOFTC(dev); 33438781Snsouch 335181303Sjhb PCF_LOCK(sc); 33640784Snsouch if (oldaddr) 337129704Sjoerg *oldaddr = sc->pcf_addr; 33840784Snsouch 33938781Snsouch /* retrieve own address from bus level */ 34040784Snsouch if (!addr) 341129704Sjoerg sc->pcf_addr = PCF_DEFAULT_ADDR; 34240784Snsouch else 343129704Sjoerg sc->pcf_addr = addr; 34438781Snsouch 345129704Sjoerg pcf_set_S1(sc, PIN); /* initialize S1 */ 346129704Sjoerg 34738781Snsouch /* own address S'O<>0 */ 348129704Sjoerg pcf_set_S0(sc, sc->pcf_addr >> 1); 34938781Snsouch 35038781Snsouch /* select clock register */ 351129704Sjoerg pcf_set_S1(sc, PIN|ES1); 35238781Snsouch 35338781Snsouch /* select bus speed : 18=90kb, 19=45kb, 1A=11kb, 1B=1.5kb */ 35438781Snsouch switch (speed) { 35538781Snsouch case IIC_SLOW: 356129704Sjoerg pcf_set_S0(sc, 0x1b); /* XXX Sun uses 0x1f */ 35738781Snsouch break; 35838781Snsouch 35938781Snsouch case IIC_FAST: 360129704Sjoerg pcf_set_S0(sc, 0x19); /* XXX Sun: 0x1d */ 36138781Snsouch break; 36238781Snsouch 36338781Snsouch case IIC_UNKNOWN: 36438781Snsouch case IIC_FASTEST: 36538781Snsouch default: 366129704Sjoerg pcf_set_S0(sc, 0x18); /* XXX Sun: 0x1c */ 36738781Snsouch break; 36838781Snsouch } 36938781Snsouch 37038781Snsouch /* set bus on, ack=yes, INT=yes */ 371129704Sjoerg pcf_set_S1(sc, PIN|ESO|ENI|ACK); 37238781Snsouch 373129704Sjoerg sc->pcf_slave_mode = SLAVE_RECEIVER; 374181303Sjhb PCF_UNLOCK(sc); 37538781Snsouch 37638781Snsouch return (0); 37738781Snsouch} 37838781Snsouch 379129704Sjoergint 380129704Sjoergpcf_write(device_t dev, char *buf, int len, int *sent, int timeout /* us */) 38138781Snsouch{ 382129704Sjoerg struct pcf_softc *sc = DEVTOSOFTC(dev); 38338781Snsouch int bytes, error = 0; 38438781Snsouch 38538781Snsouch#ifdef PCFDEBUG 386129704Sjoerg device_printf(dev, " >> writing %d bytes: %#x%s\n", len, 387129704Sjoerg (unsigned)buf[0], len > 1? "...": ""); 38838781Snsouch#endif 38938781Snsouch 39038781Snsouch bytes = 0; 391181303Sjhb PCF_LOCK(sc); 39238781Snsouch while (len) { 39338781Snsouch 394129704Sjoerg pcf_set_S0(sc, *buf++); 39538781Snsouch 39640784Snsouch /* wait for the byte to be send */ 397129704Sjoerg if ((error = pcf_wait_byte(sc))) 39838781Snsouch goto error; 39938781Snsouch 40040784Snsouch /* check if ack received */ 401129704Sjoerg if (pcf_noack(sc, timeout)) { 40238781Snsouch error = IIC_ENOACK; 40338781Snsouch goto error; 40438781Snsouch } 40538781Snsouch 40638781Snsouch len --; 40738781Snsouch bytes ++; 40838781Snsouch } 40938781Snsouch 41038781Snsoucherror: 41138781Snsouch *sent = bytes; 412181303Sjhb PCF_UNLOCK(sc); 41338781Snsouch 41438781Snsouch#ifdef PCFDEBUG 415129704Sjoerg device_printf(dev, " >> %d bytes written (%d)\n", bytes, error); 41638781Snsouch#endif 41738781Snsouch 41838781Snsouch return (error); 41938781Snsouch} 42038781Snsouch 421129704Sjoergint 422129704Sjoergpcf_read(device_t dev, char *buf, int len, int *read, int last, 423129704Sjoerg int delay /* us */) 42438781Snsouch{ 425129704Sjoerg struct pcf_softc *sc = DEVTOSOFTC(dev); 42638781Snsouch int bytes, error = 0; 427129704Sjoerg#ifdef PCFDEBUG 428129704Sjoerg char *obuf = buf; 42938781Snsouch 430129704Sjoerg device_printf(dev, " << reading %d bytes\n", len); 43138781Snsouch#endif 43238781Snsouch 433181303Sjhb PCF_LOCK(sc); 43438781Snsouch /* trig the bus to get the first data byte in S0 */ 43538781Snsouch if (len) { 43640784Snsouch if (len == 1 && last) 43738781Snsouch /* just one byte to read */ 438129704Sjoerg pcf_set_S1(sc, ESO); /* no ack */ 43938781Snsouch 440129704Sjoerg dummy_read(sc); 44138781Snsouch } 44238781Snsouch 44338781Snsouch bytes = 0; 44438781Snsouch while (len) { 44538781Snsouch 44640784Snsouch /* XXX delay needed here */ 44740784Snsouch 44840784Snsouch /* wait for trigged byte */ 449129704Sjoerg if ((error = pcf_wait_byte(sc))) { 450181303Sjhb pcf_stop_locked(sc); 45138781Snsouch goto error; 45238781Snsouch } 45338781Snsouch 45440784Snsouch if (len == 1 && last) 45540784Snsouch /* ok, last data byte already in S0, no I2C activity 456129704Sjoerg * on next pcf_get_S0() */ 457181303Sjhb pcf_stop_locked(sc); 45838781Snsouch 45940784Snsouch else if (len == 2 && last) 46040784Snsouch /* next trigged byte with no ack */ 461129704Sjoerg pcf_set_S1(sc, ESO); 46238781Snsouch 46340784Snsouch /* receive byte, trig next byte */ 464129704Sjoerg *buf++ = pcf_get_S0(sc); 46538781Snsouch 46638781Snsouch len --; 46738781Snsouch bytes ++; 46838781Snsouch }; 46938781Snsouch 47038781Snsoucherror: 47138781Snsouch *read = bytes; 472181303Sjhb PCF_UNLOCK(sc); 47338781Snsouch 47438781Snsouch#ifdef PCFDEBUG 475129704Sjoerg device_printf(dev, " << %d bytes read (%d): %#x%s\n", bytes, error, 476129704Sjoerg (unsigned)obuf[0], bytes > 1? "...": ""); 47738781Snsouch#endif 47838781Snsouch 47938781Snsouch return (error); 48038781Snsouch} 481