Date: Thu, 20 Dec 2012 18:30:34 +0000 (UTC) From: Aleksandr Rybalko <ray@FreeBSD.org> To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r244502 - projects/efika_mx/sys/arm/freescale/imx Message-ID: <201212201830.qBKIUYq5099003@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: ray Date: Thu Dec 20 18:30:34 2012 New Revision: 244502 URL: http://svnweb.freebsd.org/changeset/base/244502 Log: Almost new driver. Not so much things left of old powerpc/mpc85xx/i2c.c driver. Sponsored by: FreeBSD Foundation Modified: projects/efika_mx/sys/arm/freescale/imx/i2c.c Modified: projects/efika_mx/sys/arm/freescale/imx/i2c.c ============================================================================== --- projects/efika_mx/sys/arm/freescale/imx/i2c.c Thu Dec 20 18:16:00 2012 (r244501) +++ projects/efika_mx/sys/arm/freescale/imx/i2c.c Thu Dec 20 18:30:34 2012 (r244502) @@ -1,7 +1,11 @@ /*- * Copyright (C) 2008-2009 Semihalf, Michal Hajduk + * Copyright (c) 2012 The FreeBSD Foundation * All rights reserved. * + * Portions of this software were developed by Oleksandr Rybalko + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -54,26 +58,28 @@ __FBSDID("$FreeBSD$"); #define I2C_STATUS_REG 0x0C /* I2C status register */ #define I2C_DATA_REG 0x10 /* I2C data register */ #define I2C_DFSRR_REG 0x14 /* I2C Digital Filter Sampling rate */ -#define I2C_ENABLE 0x80 /* Module enable - interrupt disable */ -#define I2CSR_RXAK 0x01 /* Received acknowledge */ -#define I2CSR_MCF (1<<7) /* Data transfer */ -#define I2CSR_MASS (1<<6) /* Addressed as a slave */ -#define I2CSR_MBB (1<<5) /* Bus busy */ -#define I2CSR_MAL (1<<4) /* Arbitration lost */ -#define I2CSR_SRW (1<<2) /* Slave read/write */ -#define I2CSR_MIF (1<<1) /* Module interrupt */ -#define I2CCR_MEN (1<<7) /* Module enable */ -#define I2CCR_MSTA (1<<5) /* Master/slave mode */ -#define I2CCR_MTX (1<<4) /* Transmit/receive mode */ -#define I2CCR_TXAK (1<<3) /* Transfer acknowledge */ -#define I2CCR_RSTA (1<<2) /* Repeated START */ + +#define I2CCR_MEN (1 << 7) /* Module enable */ +#define I2CCR_MSTA (1 << 5) /* Master/slave mode */ +#define I2CCR_MTX (1 << 4) /* Transmit/receive mode */ +#define I2CCR_TXAK (1 << 3) /* Transfer acknowledge */ +#define I2CCR_RSTA (1 << 2) /* Repeated START */ + +#define I2CSR_MCF (1 << 7) /* Data transfer */ +#define I2CSR_MASS (1 << 6) /* Addressed as a slave */ +#define I2CSR_MBB (1 << 5) /* Bus busy */ +#define I2CSR_MAL (1 << 4) /* Arbitration lost */ +#define I2CSR_SRW (1 << 2) /* Slave read/write */ +#define I2CSR_MIF (1 << 1) /* Module interrupt */ +#define I2CSR_RXAK (1 << 0) /* Received acknowledge */ #define I2C_BAUD_RATE_FAST 0x31 #define I2C_BAUD_RATE_DEF 0x3F #define I2C_DFSSR_DIV 0x10 #ifdef DEBUG -#define debugf(fmt, args...) do { printf("%s(): ", __func__); printf(fmt,##args); } while (0) +#define debugf(fmt, args...) do { printf("%s(): ", __func__); \ + printf(fmt,##args); } while (0) #else #define debugf(fmt, args...) #endif @@ -83,8 +89,6 @@ struct i2c_softc { device_t iicbus; struct resource *res; struct mtx mutex; - int flags; -#define FSL_IMX_I2C (1 << 0) /* To distinguish MPC and i.MX SoCs */ int rid; bus_space_handle_t bsh; bus_space_tag_t bst; @@ -93,12 +97,12 @@ struct i2c_softc { static int i2c_probe(device_t); static int i2c_attach(device_t); -static int i2c_repeated_start(device_t dev, u_char slave, int timeout); -static int i2c_start(device_t dev, u_char slave, int timeout); -static int i2c_stop(device_t dev); -static int i2c_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr); -static int i2c_read(device_t dev, char *buf, int len, int *read, int last, int delay); -static int i2c_write(device_t dev, const char *buf, int len, int *sent, int timeout); +static int i2c_repeated_start(device_t, u_char, int); +static int i2c_start(device_t, u_char, int); +static int i2c_stop(device_t); +static int i2c_reset(device_t, u_char, u_char, u_char *); +static int i2c_read(device_t, char *, int, int *, int, int); +static int i2c_write(device_t, const char *, int, int *, int); static device_method_t i2c_methods[] = { DEVMETHOD(device_probe, i2c_probe), @@ -150,38 +154,54 @@ i2c_flag_set(struct i2c_softc *sc, bus_s i2c_write_reg(sc, off, status); } +/* Wait for transfer interrupt flag */ static int -i2c_do_wait(device_t dev, struct i2c_softc *sc, int write, int start) +wait_for_iif(struct i2c_softc *sc) { - int err; - uint8_t status; + int retry; - status = i2c_read_reg(sc, I2C_STATUS_REG); - if (status & I2CSR_MIF) { - if (write && start && (status & I2CSR_RXAK)) { - debugf("no ack %s", start ? - "after sending slave address" : ""); - err = IIC_ENOACK; - goto error; - } - if (status & I2CSR_MAL) { - debugf("arbitration lost"); - err = IIC_EBUSERR; - goto error; - } - if (!write && !(status & I2CSR_MCF)) { - debugf("transfer unfinished"); - err = IIC_EBUSERR; - goto error; - } + retry = 1000; + while (retry --) { + if (i2c_read_reg(sc, I2C_STATUS_REG) & I2CSR_MIF) + return (IIC_NOERR); + DELAY(10); } - return (IIC_NOERR); + return (IIC_ETIMEOUT); +} -error: - i2c_write_reg(sc, I2C_STATUS_REG, 0x0); - i2c_write_reg(sc, I2C_CONTROL_REG, I2CCR_MEN | I2CCR_TXAK); - return (err); +/* Wait for free bus */ +static int +wait_for_nibb(struct i2c_softc *sc) +{ + int retry; + + retry = 1000; + while (retry --) { + if ((i2c_read_reg(sc, I2C_STATUS_REG) & I2CSR_MBB) == 0) + return (IIC_NOERR); + DELAY(10); + } + + return (IIC_ETIMEOUT); +} + +/* Wait for transfer complete+interrupt flag */ +static int +wait_for_icf(struct i2c_softc *sc) +{ + int retry; + + retry = 1000; + while (retry --) { + + if ((i2c_read_reg(sc, I2C_STATUS_REG) & + (I2CSR_MCF|I2CSR_MIF)) == (I2CSR_MCF|I2CSR_MIF)) + return (IIC_NOERR); + DELAY(10); + } + + return (IIC_ETIMEOUT); } static int @@ -189,16 +209,10 @@ i2c_probe(device_t dev) { struct i2c_softc *sc; - sc = device_get_softc(dev); - - if (ofw_bus_is_compatible(dev, "fsl-i2c")) - /* compatible */; - else if (ofw_bus_is_compatible(dev, "fsl,imx-i2c")) - /* compatible, i.MX SoC */ - sc->flags |= FSL_IMX_I2C; - else + if (!ofw_bus_is_compatible(dev, "fsl,imx-i2c")) return (ENXIO); + sc = device_get_softc(dev); sc->rid = 0; sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->rid, @@ -212,7 +226,7 @@ i2c_probe(device_t dev) sc->bsh = rman_get_bushandle(sc->res); /* Enable I2C */ - i2c_write_reg(sc, I2C_CONTROL_REG, I2C_ENABLE); + i2c_write_reg(sc, I2C_CONTROL_REG, I2CCR_MEN); bus_release_resource(dev, SYS_RES_MEMORY, sc->rid, sc->res); device_set_desc(dev, "I2C bus controller"); @@ -223,8 +237,8 @@ static int i2c_attach(device_t dev) { struct i2c_softc *sc; - sc = device_get_softc(dev); + sc = device_get_softc(dev); sc->dev = dev; sc->rid = 0; @@ -251,22 +265,37 @@ i2c_attach(device_t dev) bus_generic_attach(dev); return (IIC_NOERR); } + static int i2c_repeated_start(device_t dev, u_char slave, int timeout) { struct i2c_softc *sc; int error; - + sc = device_get_softc(dev); mtx_lock(&sc->mutex); + + i2c_write_reg(sc, I2C_ADDR_REG, slave); + if ((i2c_read_reg(sc, I2C_STATUS_REG) & I2CSR_MBB) == 0) { + mtx_unlock(&sc->mutex); + return (IIC_EBUSBSY); + } + /* Set repeated start condition */ - i2c_flag_set(sc, I2C_CONTROL_REG ,I2CCR_RSTA); + DELAY(10); + i2c_flag_set(sc, I2C_CONTROL_REG, I2CCR_RSTA); + DELAY(10); + /* Clear status */ + i2c_write_reg(sc, I2C_STATUS_REG, 0x0); /* Write target address - LSB is R/W bit */ i2c_write_reg(sc, I2C_DATA_REG, slave); - DELAY(1250); - error = i2c_do_wait(dev, sc, 1, 1); + error = wait_for_iif(sc); + + /* Clear status */ + i2c_write_reg(sc, I2C_STATUS_REG, 0x0); + mtx_unlock(&sc->mutex); if (error) @@ -279,29 +308,29 @@ static int i2c_start(device_t dev, u_char slave, int timeout) { struct i2c_softc *sc; - uint8_t status; int error; sc = device_get_softc(dev); - DELAY(1000); mtx_lock(&sc->mutex); - status = i2c_read_reg(sc, I2C_STATUS_REG); - /* Check if bus is idle or busy */ - if (status & I2CSR_MBB) { - debugf("bus busy"); + i2c_write_reg(sc, I2C_ADDR_REG, slave); + if (i2c_read_reg(sc, I2C_STATUS_REG) & I2CSR_MBB) { mtx_unlock(&sc->mutex); - i2c_stop(dev); return (IIC_EBUSBSY); } /* Set start condition */ - i2c_write_reg(sc, I2C_CONTROL_REG, I2CCR_MEN | I2CCR_MSTA | I2CCR_MTX); + i2c_write_reg(sc, I2C_CONTROL_REG, + I2CCR_MEN | I2CCR_MSTA | I2CCR_TXAK); + DELAY(100); + i2c_write_reg(sc, I2C_CONTROL_REG, + I2CCR_MEN | I2CCR_MSTA | I2CCR_MTX | I2CCR_TXAK); + /* Clear status */ + i2c_write_reg(sc, I2C_STATUS_REG, 0x0); /* Write target address - LSB is R/W bit */ i2c_write_reg(sc, I2C_DATA_REG, slave); - DELAY(1250); - error = i2c_do_wait(dev, sc, 1, 1); + error = wait_for_iif(sc); mtx_unlock(&sc->mutex); if (error) @@ -310,6 +339,7 @@ i2c_start(device_t dev, u_char slave, in return (IIC_NOERR); } + static int i2c_stop(device_t dev) { @@ -318,7 +348,15 @@ i2c_stop(device_t dev) sc = device_get_softc(dev); mtx_lock(&sc->mutex); i2c_write_reg(sc, I2C_CONTROL_REG, I2CCR_MEN | I2CCR_TXAK); - DELAY(1000); + DELAY(100); + /* Reset controller if bus still busy after STOP */ + if (wait_for_nibb(sc) == IIC_ETIMEOUT) { + i2c_write_reg(sc, I2C_CONTROL_REG, 0); + DELAY(1000); + i2c_write_reg(sc, I2C_CONTROL_REG, I2CCR_MEN | I2CCR_TXAK); + + i2c_write_reg(sc, I2C_STATUS_REG, 0x0); + } mtx_unlock(&sc->mutex); return (IIC_NOERR); @@ -348,11 +386,11 @@ i2c_reset(device_t dev, u_char speed, u_ i2c_write_reg(sc, I2C_CONTROL_REG, 0x0); i2c_write_reg(sc, I2C_STATUS_REG, 0x0); DELAY(1000); - i2c_write_reg(sc, I2C_FDR_REG, baud_rate); - if (!(sc->flags & FSL_IMX_I2C)) - i2c_write_reg(sc, I2C_DFSRR_REG, I2C_DFSSR_DIV); - i2c_write_reg(sc, I2C_CONTROL_REG, I2C_ENABLE); + + i2c_write_reg(sc, I2C_FDR_REG, 20); + i2c_write_reg(sc, I2C_CONTROL_REG, I2CCR_MEN); DELAY(1000); + i2c_write_reg(sc, I2C_STATUS_REG, 0x0); mtx_unlock(&sc->mutex); return (IIC_NOERR); @@ -362,12 +400,13 @@ static int i2c_read(device_t dev, char *buf, int len, int *read, int last, int delay) { struct i2c_softc *sc; - int error; + int error, reg; sc = device_get_softc(dev); *read = 0; mtx_lock(&sc->mutex); + if (len) { if (len == 1) i2c_write_reg(sc, I2C_CONTROL_REG, I2CCR_MEN | @@ -383,25 +422,27 @@ i2c_read(device_t dev, char *buf, int le } while (*read < len) { - DELAY(1000); - error = i2c_do_wait(dev, sc, 0, 0); + error = wait_for_icf(sc); if (error) { mtx_unlock(&sc->mutex); return (error); } + i2c_write_reg(sc, I2C_STATUS_REG, 0x0); if ((*read == len - 2) && last) { + /* NO ACK on last byte */ i2c_write_reg(sc, I2C_CONTROL_REG, I2CCR_MEN | I2CCR_MSTA | I2CCR_TXAK); } if ((*read == len - 1) && last) { - i2c_write_reg(sc, I2C_CONTROL_REG, I2CCR_MEN | + /* Transfer done, remove master bit */ + i2c_write_reg(sc, I2C_CONTROL_REG, I2CCR_MEN | I2CCR_TXAK); } - *buf++ = i2c_read_reg(sc, I2C_DATA_REG); + reg = i2c_read_reg(sc, I2C_DATA_REG); + *buf++ = reg; (*read)++; - DELAY(1250); } mtx_unlock(&sc->mutex); @@ -419,10 +460,10 @@ i2c_write(device_t dev, const char *buf, mtx_lock(&sc->mutex); while (*sent < len) { + i2c_write_reg(sc, I2C_STATUS_REG, 0x0); i2c_write_reg(sc, I2C_DATA_REG, *buf++); - DELAY(1250); - error = i2c_do_wait(dev, sc, 1, 0); + error = wait_for_iif(sc); if (error) { mtx_unlock(&sc->mutex); return (error);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201212201830.qBKIUYq5099003>