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: releng/11.0/sys/dev/pcf/pcf.c 297793 2016-04-10 23:07:00Z pfg $"); 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 44181332Sjhb#include <dev/iicbus/iicbus.h> 4538781Snsouch#include <dev/iicbus/iiconf.h> 46129704Sjoerg#include <dev/pcf/pcfvar.h> 4738781Snsouch#include "iicbus_if.h" 4838781Snsouch 49129704Sjoerg/* Not so official debugging option. */ 50129704Sjoerg/* #define PCFDEBUG */ 5155939Snsouch 52129704Sjoergstatic int pcf_wait_byte(struct pcf_softc *pcf); 53129704Sjoergstatic int pcf_noack(struct pcf_softc *pcf, int timeout); 54181303Sjhbstatic void pcf_stop_locked(struct pcf_softc *pcf); 5538781Snsouch 5638781Snsouch/* 5738781Snsouch * Polling mode for master operations wait for a new 58181303Sjhb * byte incoming or outgoing 5938781Snsouch */ 60181303Sjhbstatic int 61129704Sjoergpcf_wait_byte(struct pcf_softc *sc) 6238781Snsouch{ 6338781Snsouch int counter = TIMEOUT; 6438781Snsouch 65181303Sjhb PCF_ASSERT_LOCKED(sc); 6638781Snsouch while (counter--) { 6738781Snsouch 68129704Sjoerg if ((pcf_get_S1(sc) & PIN) == 0) 6938781Snsouch return (0); 7038781Snsouch } 7138781Snsouch 72129893Snsouch#ifdef PCFDEBUG 73129893Snsouch printf("pcf: timeout!\n"); 74129893Snsouch#endif 75129893Snsouch 7638781Snsouch return (IIC_ETIMEOUT); 7738781Snsouch} 7838781Snsouch 79181303Sjhbstatic void 80181303Sjhbpcf_stop_locked(struct pcf_softc *sc) 8138781Snsouch{ 8238781Snsouch 83181303Sjhb PCF_ASSERT_LOCKED(sc); 84129704Sjoerg#ifdef PCFDEBUG 85129704Sjoerg device_printf(dev, " >> stop\n"); 86129704Sjoerg#endif 8740784Snsouch /* 8840784Snsouch * Send STOP condition iff the START condition was previously sent. 89108533Sschweikh * STOP is sent only once even if an iicbus_stop() is called after 90129704Sjoerg * an iicbus_read()... see pcf_read(): the PCF needs to send the stop 9140784Snsouch * before the last char is read. 9240784Snsouch */ 93129704Sjoerg if (sc->pcf_started) { 9440784Snsouch /* set stop condition and enable IT */ 95129704Sjoerg pcf_set_S1(sc, PIN|ESO|ENI|STO|ACK); 9638781Snsouch 97129704Sjoerg sc->pcf_started = 0; 9840784Snsouch } 9938781Snsouch} 10038781Snsouch 101181303Sjhbstatic int 102129704Sjoergpcf_noack(struct pcf_softc *sc, int timeout) 10338781Snsouch{ 10440784Snsouch int noack; 10540784Snsouch int k = timeout/10; 10640784Snsouch 107181303Sjhb PCF_ASSERT_LOCKED(sc); 10840784Snsouch do { 109129704Sjoerg noack = pcf_get_S1(sc) & LRB; 11040784Snsouch if (!noack) 11140784Snsouch break; 11240784Snsouch DELAY(10); /* XXX wait 10 us */ 11340784Snsouch } while (k--); 11440784Snsouch 11540784Snsouch return (noack); 11640784Snsouch} 11740784Snsouch 118129704Sjoergint 119129704Sjoergpcf_repeated_start(device_t dev, u_char slave, int timeout) 12040784Snsouch{ 121129704Sjoerg struct pcf_softc *sc = DEVTOSOFTC(dev); 12238781Snsouch int error = 0; 12338781Snsouch 124181303Sjhb PCF_LOCK(sc); 125129704Sjoerg#ifdef PCFDEBUG 126129704Sjoerg device_printf(dev, " >> repeated start for slave %#x\n", 127129704Sjoerg (unsigned)slave); 128129704Sjoerg#endif 12938781Snsouch /* repeated start */ 130129704Sjoerg pcf_set_S1(sc, ESO|STA|STO|ACK); 13138781Snsouch 13238781Snsouch /* set slave address to PCF. Last bit (LSB) must be set correctly 13338781Snsouch * according to transfer direction */ 134129704Sjoerg pcf_set_S0(sc, slave); 13538781Snsouch 13638781Snsouch /* wait for address sent, polling */ 137129704Sjoerg if ((error = pcf_wait_byte(sc))) 13838781Snsouch goto error; 13938781Snsouch 14040784Snsouch /* check for ack */ 141129704Sjoerg if (pcf_noack(sc, timeout)) { 14238781Snsouch error = IIC_ENOACK; 143129893Snsouch#ifdef PCFDEBUG 144129893Snsouch printf("pcf: no ack on repeated_start!\n"); 145129893Snsouch#endif 14638781Snsouch goto error; 14738781Snsouch } 14838781Snsouch 149181303Sjhb PCF_UNLOCK(sc); 15038781Snsouch return (0); 15138781Snsouch 15238781Snsoucherror: 153181303Sjhb pcf_stop_locked(sc); 154181303Sjhb PCF_UNLOCK(sc); 15538781Snsouch return (error); 15638781Snsouch} 15738781Snsouch 158129704Sjoergint 159129704Sjoergpcf_start(device_t dev, u_char slave, int timeout) 16038781Snsouch{ 161129704Sjoerg struct pcf_softc *sc = DEVTOSOFTC(dev); 16238781Snsouch int error = 0; 16338781Snsouch 164181303Sjhb PCF_LOCK(sc); 165129704Sjoerg#ifdef PCFDEBUG 166129704Sjoerg device_printf(dev, " >> start for slave %#x\n", (unsigned)slave); 167129704Sjoerg#endif 168129893Snsouch if ((pcf_get_S1(sc) & nBB) == 0) { 169129893Snsouch#ifdef PCFDEBUG 170129893Snsouch printf("pcf: busy!\n"); 171129893Snsouch#endif 172181303Sjhb PCF_UNLOCK(sc); 173289093Sian return (IIC_EBUSERR); 174129893Snsouch } 17538781Snsouch 17638781Snsouch /* set slave address to PCF. Last bit (LSB) must be set correctly 17738781Snsouch * according to transfer direction */ 178129704Sjoerg pcf_set_S0(sc, slave); 17938781Snsouch 18038781Snsouch /* START only */ 181129704Sjoerg pcf_set_S1(sc, PIN|ESO|STA|ACK); 18238781Snsouch 183129704Sjoerg sc->pcf_started = 1; 18440784Snsouch 18538781Snsouch /* wait for address sent, polling */ 186129704Sjoerg if ((error = pcf_wait_byte(sc))) 18738781Snsouch goto error; 18838781Snsouch 18940784Snsouch /* check for ACK */ 190129704Sjoerg if (pcf_noack(sc, timeout)) { 19138781Snsouch error = IIC_ENOACK; 192129893Snsouch#ifdef PCFDEBUG 193129893Snsouch printf("pcf: no ack on start!\n"); 194129893Snsouch#endif 19538781Snsouch goto error; 19638781Snsouch } 19738781Snsouch 198181303Sjhb PCF_UNLOCK(sc); 19938781Snsouch return (0); 20038781Snsouch 20138781Snsoucherror: 202181303Sjhb pcf_stop_locked(sc); 203181303Sjhb PCF_UNLOCK(sc); 20438781Snsouch return (error); 20538781Snsouch} 20638781Snsouch 207181303Sjhbint 208181303Sjhbpcf_stop(device_t dev) 209181303Sjhb{ 210181303Sjhb struct pcf_softc *sc = DEVTOSOFTC(dev); 211181303Sjhb 212181303Sjhb#ifdef PCFDEBUG 213181303Sjhb device_printf(dev, " >> stop\n"); 214181303Sjhb#endif 215181303Sjhb PCF_LOCK(sc); 216181303Sjhb pcf_stop_locked(sc); 217181303Sjhb PCF_UNLOCK(sc); 218181303Sjhb 219181303Sjhb return (0); 220181303Sjhb} 221181303Sjhb 222129704Sjoergvoid 223129704Sjoergpcf_intr(void *arg) 22438781Snsouch{ 225129893Snsouch struct pcf_softc *sc = arg; 22638781Snsouch char data, status, addr; 22738781Snsouch char error = 0; 22838781Snsouch 229181303Sjhb PCF_LOCK(sc); 230129704Sjoerg status = pcf_get_S1(sc); 23138781Snsouch 23238781Snsouch if (status & PIN) { 233129893Snsouch printf("pcf: spurious interrupt, status=0x%x\n", 234129893Snsouch status & 0xff); 23538781Snsouch 23638781Snsouch goto error; 237129704Sjoerg } 23838781Snsouch 23938781Snsouch if (status & LAB) 240129893Snsouch printf("pcf: bus arbitration lost!\n"); 24138781Snsouch 24238781Snsouch if (status & BER) { 24338781Snsouch error = IIC_EBUSERR; 244129704Sjoerg iicbus_intr(sc->iicbus, INTR_ERROR, &error); 24538781Snsouch 24638781Snsouch goto error; 24738781Snsouch } 24838781Snsouch 24938781Snsouch do { 250129704Sjoerg status = pcf_get_S1(sc); 25138781Snsouch 252129704Sjoerg switch(sc->pcf_slave_mode) { 25338781Snsouch 25438781Snsouch case SLAVE_TRANSMITTER: 25538781Snsouch if (status & LRB) { 25638781Snsouch /* ack interrupt line */ 257129704Sjoerg dummy_write(sc); 25838781Snsouch 25938781Snsouch /* no ack, don't send anymore */ 260129704Sjoerg sc->pcf_slave_mode = SLAVE_RECEIVER; 26138781Snsouch 262129704Sjoerg iicbus_intr(sc->iicbus, INTR_NOACK, NULL); 26338781Snsouch break; 26438781Snsouch } 26538781Snsouch 26638781Snsouch /* get data from upper code */ 267129704Sjoerg iicbus_intr(sc->iicbus, INTR_TRANSMIT, &data); 26838781Snsouch 269129704Sjoerg pcf_set_S0(sc, data); 270129704Sjoerg break; 271129704Sjoerg 27238781Snsouch case SLAVE_RECEIVER: 27338781Snsouch if (status & AAS) { 274129704Sjoerg addr = pcf_get_S0(sc); 27538781Snsouch 27638781Snsouch if (status & AD0) 277129704Sjoerg iicbus_intr(sc->iicbus, INTR_GENERAL, &addr); 27838781Snsouch else 279129704Sjoerg iicbus_intr(sc->iicbus, INTR_START, &addr); 28038781Snsouch 28138781Snsouch if (addr & LSB) { 282129704Sjoerg sc->pcf_slave_mode = SLAVE_TRANSMITTER; 28338781Snsouch 28438781Snsouch /* get the first char from upper code */ 285129704Sjoerg iicbus_intr(sc->iicbus, INTR_TRANSMIT, &data); 28638781Snsouch 28738781Snsouch /* send first data byte */ 288129704Sjoerg pcf_set_S0(sc, data); 28938781Snsouch } 29038781Snsouch 29138781Snsouch break; 29238781Snsouch } 29338781Snsouch 29438781Snsouch /* stop condition received? */ 29538781Snsouch if (status & STS) { 29638781Snsouch /* ack interrupt line */ 297129704Sjoerg dummy_read(sc); 29838781Snsouch 29938781Snsouch /* emulate intr stop condition */ 300129704Sjoerg iicbus_intr(sc->iicbus, INTR_STOP, NULL); 30138781Snsouch 30238781Snsouch } else { 30338781Snsouch /* get data, ack interrupt line */ 304129704Sjoerg data = pcf_get_S0(sc); 30538781Snsouch 30638781Snsouch /* deliver the character */ 307129704Sjoerg iicbus_intr(sc->iicbus, INTR_RECEIVE, &data); 30838781Snsouch } 30938781Snsouch break; 31038781Snsouch 31138781Snsouch default: 31287599Sobrien panic("%s: unknown slave mode (%d)!", __func__, 313129704Sjoerg sc->pcf_slave_mode); 31438781Snsouch } 31538781Snsouch 316129704Sjoerg } while ((pcf_get_S1(sc) & PIN) == 0); 317181303Sjhb PCF_UNLOCK(sc); 31838781Snsouch 31938781Snsouch return; 32038781Snsouch 32138781Snsoucherror: 32238781Snsouch /* unknown event on bus...reset PCF */ 323129704Sjoerg pcf_set_S1(sc, PIN|ESO|ENI|ACK); 32438781Snsouch 325129704Sjoerg sc->pcf_slave_mode = SLAVE_RECEIVER; 326181303Sjhb PCF_UNLOCK(sc); 32738781Snsouch 32838781Snsouch return; 32938781Snsouch} 33038781Snsouch 331129704Sjoergint 332129704Sjoergpcf_rst_card(device_t dev, u_char speed, u_char addr, u_char *oldaddr) 33338781Snsouch{ 334129704Sjoerg struct pcf_softc *sc = DEVTOSOFTC(dev); 33538781Snsouch 336181303Sjhb PCF_LOCK(sc); 33740784Snsouch if (oldaddr) 338129704Sjoerg *oldaddr = sc->pcf_addr; 33940784Snsouch 34038781Snsouch /* retrieve own address from bus level */ 34140784Snsouch if (!addr) 342129704Sjoerg sc->pcf_addr = PCF_DEFAULT_ADDR; 34340784Snsouch else 344129704Sjoerg sc->pcf_addr = addr; 34538781Snsouch 346129704Sjoerg pcf_set_S1(sc, PIN); /* initialize S1 */ 347129704Sjoerg 34838781Snsouch /* own address S'O<>0 */ 349129704Sjoerg pcf_set_S0(sc, sc->pcf_addr >> 1); 35038781Snsouch 35138781Snsouch /* select clock register */ 352129704Sjoerg pcf_set_S1(sc, PIN|ES1); 35338781Snsouch 35438781Snsouch /* select bus speed : 18=90kb, 19=45kb, 1A=11kb, 1B=1.5kb */ 35538781Snsouch switch (speed) { 35638781Snsouch case IIC_SLOW: 357129704Sjoerg pcf_set_S0(sc, 0x1b); /* XXX Sun uses 0x1f */ 35838781Snsouch break; 35938781Snsouch 36038781Snsouch case IIC_FAST: 361129704Sjoerg pcf_set_S0(sc, 0x19); /* XXX Sun: 0x1d */ 36238781Snsouch break; 36338781Snsouch 36438781Snsouch case IIC_UNKNOWN: 36538781Snsouch case IIC_FASTEST: 36638781Snsouch default: 367129704Sjoerg pcf_set_S0(sc, 0x18); /* XXX Sun: 0x1c */ 36838781Snsouch break; 36938781Snsouch } 37038781Snsouch 37138781Snsouch /* set bus on, ack=yes, INT=yes */ 372129704Sjoerg pcf_set_S1(sc, PIN|ESO|ENI|ACK); 37338781Snsouch 374129704Sjoerg sc->pcf_slave_mode = SLAVE_RECEIVER; 375181303Sjhb PCF_UNLOCK(sc); 37638781Snsouch 37738781Snsouch return (0); 37838781Snsouch} 37938781Snsouch 380129704Sjoergint 381194026Savgpcf_write(device_t dev, const char *buf, int len, int *sent, int timeout /* us */) 38238781Snsouch{ 383129704Sjoerg struct pcf_softc *sc = DEVTOSOFTC(dev); 38438781Snsouch int bytes, error = 0; 38538781Snsouch 38638781Snsouch#ifdef PCFDEBUG 387129704Sjoerg device_printf(dev, " >> writing %d bytes: %#x%s\n", len, 388129704Sjoerg (unsigned)buf[0], len > 1? "...": ""); 38938781Snsouch#endif 39038781Snsouch 39138781Snsouch bytes = 0; 392181303Sjhb PCF_LOCK(sc); 39338781Snsouch while (len) { 39438781Snsouch 395129704Sjoerg pcf_set_S0(sc, *buf++); 39638781Snsouch 39740784Snsouch /* wait for the byte to be send */ 398129704Sjoerg if ((error = pcf_wait_byte(sc))) 39938781Snsouch goto error; 40038781Snsouch 40140784Snsouch /* check if ack received */ 402129704Sjoerg if (pcf_noack(sc, timeout)) { 40338781Snsouch error = IIC_ENOACK; 40438781Snsouch goto error; 40538781Snsouch } 40638781Snsouch 40738781Snsouch len --; 40838781Snsouch bytes ++; 40938781Snsouch } 41038781Snsouch 41138781Snsoucherror: 41238781Snsouch *sent = bytes; 413181303Sjhb PCF_UNLOCK(sc); 41438781Snsouch 41538781Snsouch#ifdef PCFDEBUG 416129704Sjoerg device_printf(dev, " >> %d bytes written (%d)\n", bytes, error); 41738781Snsouch#endif 41838781Snsouch 41938781Snsouch return (error); 42038781Snsouch} 42138781Snsouch 422129704Sjoergint 423129704Sjoergpcf_read(device_t dev, char *buf, int len, int *read, int last, 424129704Sjoerg int delay /* us */) 42538781Snsouch{ 426129704Sjoerg struct pcf_softc *sc = DEVTOSOFTC(dev); 42738781Snsouch int bytes, error = 0; 428129704Sjoerg#ifdef PCFDEBUG 429129704Sjoerg char *obuf = buf; 43038781Snsouch 431129704Sjoerg device_printf(dev, " << reading %d bytes\n", len); 43238781Snsouch#endif 43338781Snsouch 434181303Sjhb PCF_LOCK(sc); 43538781Snsouch /* trig the bus to get the first data byte in S0 */ 43638781Snsouch if (len) { 43740784Snsouch if (len == 1 && last) 43838781Snsouch /* just one byte to read */ 439129704Sjoerg pcf_set_S1(sc, ESO); /* no ack */ 44038781Snsouch 441129704Sjoerg dummy_read(sc); 44238781Snsouch } 44338781Snsouch 44438781Snsouch bytes = 0; 44538781Snsouch while (len) { 44638781Snsouch 44740784Snsouch /* XXX delay needed here */ 44840784Snsouch 44940784Snsouch /* wait for trigged byte */ 450129704Sjoerg if ((error = pcf_wait_byte(sc))) { 451181303Sjhb pcf_stop_locked(sc); 45238781Snsouch goto error; 45338781Snsouch } 45438781Snsouch 45540784Snsouch if (len == 1 && last) 45640784Snsouch /* ok, last data byte already in S0, no I2C activity 457129704Sjoerg * on next pcf_get_S0() */ 458181303Sjhb pcf_stop_locked(sc); 45938781Snsouch 46040784Snsouch else if (len == 2 && last) 46140784Snsouch /* next trigged byte with no ack */ 462129704Sjoerg pcf_set_S1(sc, ESO); 46338781Snsouch 46440784Snsouch /* receive byte, trig next byte */ 465129704Sjoerg *buf++ = pcf_get_S0(sc); 46638781Snsouch 46738781Snsouch len --; 46838781Snsouch bytes ++; 469297793Spfg } 47038781Snsouch 47138781Snsoucherror: 47238781Snsouch *read = bytes; 473181303Sjhb PCF_UNLOCK(sc); 47438781Snsouch 47538781Snsouch#ifdef PCFDEBUG 476129704Sjoerg device_printf(dev, " << %d bytes read (%d): %#x%s\n", bytes, error, 477129704Sjoerg (unsigned)obuf[0], bytes > 1? "...": ""); 47838781Snsouch#endif 47938781Snsouch 48038781Snsouch return (error); 48138781Snsouch} 482181332Sjhb 483181332SjhbDRIVER_MODULE(iicbus, pcf, iicbus_driver, iicbus_devclass, 0, 0); 484181332SjhbMODULE_DEPEND(pcf, iicbus, PCF_MINVER, PCF_PREFVER, PCF_MAXVER); 485181332SjhbMODULE_VERSION(pcf, PCF_MODVER); 486