From 8f2e2072ac6dcba5df34464ee0d9847b5b902362 Mon Sep 17 00:00:00 2001 From: Patrick Wildt Date: Fri, 30 Mar 2018 20:02:29 +0000 Subject: Move imxiic(4) to sys/dev/fdt. --- sys/arch/armv7/imx/files.imx | 6 +- sys/arch/armv7/imx/imxiic.c | 432 ----------------------------------------- sys/arch/armv7/imx/imxiicvar.h | 44 ----- sys/dev/fdt/files.fdt | 6 +- sys/dev/fdt/imxiic.c | 432 +++++++++++++++++++++++++++++++++++++++++ sys/dev/fdt/imxiicvar.h | 44 +++++ 6 files changed, 482 insertions(+), 482 deletions(-) delete mode 100644 sys/arch/armv7/imx/imxiic.c delete mode 100644 sys/arch/armv7/imx/imxiicvar.h create mode 100644 sys/dev/fdt/imxiic.c create mode 100644 sys/dev/fdt/imxiicvar.h (limited to 'sys') diff --git a/sys/arch/armv7/imx/files.imx b/sys/arch/armv7/imx/files.imx index cb86c895b60..f6b02eb653d 100644 --- a/sys/arch/armv7/imx/files.imx +++ b/sys/arch/armv7/imx/files.imx @@ -1,4 +1,4 @@ -# $OpenBSD: files.imx,v 1.25 2018/03/30 19:50:55 patrick Exp $ +# $OpenBSD: files.imx,v 1.26 2018/03/30 20:02:28 patrick Exp $ device imxccm attach imxccm at fdt @@ -16,10 +16,6 @@ device imxanatop attach imxanatop at fdt file arch/armv7/imx/imxanatop.c imxanatop -device imxiic: i2cbus -attach imxiic at fdt -file arch/armv7/imx/imxiic.c imxiic - device fec: ether, ifnet, mii, ifmedia attach fec at fdt file arch/armv7/imx/if_fec.c fec diff --git a/sys/arch/armv7/imx/imxiic.c b/sys/arch/armv7/imx/imxiic.c deleted file mode 100644 index 79a7af8c81d..00000000000 --- a/sys/arch/armv7/imx/imxiic.c +++ /dev/null @@ -1,432 +0,0 @@ -/* $OpenBSD: imxiic.c,v 1.14 2017/12/30 13:34:56 kettenis Exp $ */ -/* - * Copyright (c) 2013 Patrick Wildt - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include -#include - -#include -#include - -#include - -#include -#include -#include -#include - -/* registers */ -#define I2C_IADR 0x00 -#define I2C_IFDR 0x04 -#define I2C_I2CR 0x08 -#define I2C_I2SR 0x0C -#define I2C_I2DR 0x10 - -#define I2C_I2CR_RSTA (1 << 2) -#define I2C_I2CR_TXAK (1 << 3) -#define I2C_I2CR_MTX (1 << 4) -#define I2C_I2CR_MSTA (1 << 5) -#define I2C_I2CR_IIEN (1 << 6) -#define I2C_I2CR_IEN (1 << 7) -#define I2C_I2SR_RXAK (1 << 0) -#define I2C_I2SR_IIF (1 << 1) -#define I2C_I2SR_IBB (1 << 5) - -struct imxiic_softc { - struct device sc_dev; - bus_space_tag_t sc_iot; - bus_space_handle_t sc_ioh; - bus_size_t sc_ios; - void *sc_ih; - int sc_node; - - struct rwlock sc_buslock; - struct i2c_controller i2c_tag; - - uint16_t frequency; - uint16_t intr_status; - uint16_t stopped; -}; - -int imxiic_match(struct device *, void *, void *); -void imxiic_attach(struct device *, struct device *, void *); -int imxiic_detach(struct device *, int); -void imxiic_setspeed(struct imxiic_softc *, u_int); -int imxiic_intr(void *); -int imxiic_wait_intr(struct imxiic_softc *, int, int); -int imxiic_wait_state(struct imxiic_softc *, uint32_t, uint32_t); -int imxiic_read(struct imxiic_softc *, int, void *, int); -int imxiic_write(struct imxiic_softc *, int, const void *, int, - const void *, int); - -int imxiic_i2c_acquire_bus(void *, int); -void imxiic_i2c_release_bus(void *, int); -int imxiic_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t, - void *, size_t, int); - -#define HREAD2(sc, reg) \ - (bus_space_read_2((sc)->sc_iot, (sc)->sc_ioh, (reg))) -#define HWRITE2(sc, reg, val) \ - bus_space_write_2((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) -#define HSET2(sc, reg, bits) \ - HWRITE2((sc), (reg), HREAD2((sc), (reg)) | (bits)) -#define HCLR2(sc, reg, bits) \ - HWRITE2((sc), (reg), HREAD2((sc), (reg)) & ~(bits)) - -void imxiic_scan(struct device *, struct i2cbus_attach_args *, void *); - -struct cfattach imxiic_ca = { - sizeof(struct imxiic_softc), imxiic_match, imxiic_attach, - imxiic_detach -}; - -struct cfdriver imxiic_cd = { - NULL, "imxiic", DV_DULL -}; - -int -imxiic_match(struct device *parent, void *match, void *aux) -{ - struct fdt_attach_args *faa = aux; - - return OF_is_compatible(faa->fa_node, "fsl,imx21-i2c"); -} - -void -imxiic_attach(struct device *parent, struct device *self, void *aux) -{ - struct imxiic_softc *sc = (struct imxiic_softc *)self; - struct fdt_attach_args *faa = aux; - - if (faa->fa_nreg < 1) - return; - - sc->sc_iot = faa->fa_iot; - sc->sc_ios = faa->fa_reg[0].size; - sc->sc_node = faa->fa_node; - if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, - faa->fa_reg[0].size, 0, &sc->sc_ioh)) - panic("imxiic_attach: bus_space_map failed!"); - -#if 0 - sc->sc_ih = arm_intr_establish_fdt(faa->fa_node, IPL_BIO, - imxiic_intr, sc, sc->sc_dev.dv_xname); -#endif - - printf("\n"); - - /* set iomux pins */ - pinctrl_byname(faa->fa_node, "default"); - - /* set speed to 100kHz */ - imxiic_setspeed(sc, 100); - - /* reset */ - HWRITE2(sc, I2C_I2CR, 0); - HWRITE2(sc, I2C_I2SR, 0); - - sc->stopped = 1; - rw_init(&sc->sc_buslock, sc->sc_dev.dv_xname); - - struct i2cbus_attach_args iba; - - sc->i2c_tag.ic_cookie = sc; - sc->i2c_tag.ic_acquire_bus = imxiic_i2c_acquire_bus; - sc->i2c_tag.ic_release_bus = imxiic_i2c_release_bus; - sc->i2c_tag.ic_exec = imxiic_i2c_exec; - - bzero(&iba, sizeof iba); - iba.iba_name = "iic"; - iba.iba_tag = &sc->i2c_tag; - iba.iba_bus_scan = imxiic_scan; - iba.iba_bus_scan_arg = &sc->sc_node; - config_found(&sc->sc_dev, &iba, iicbus_print); -} - -void -imxiic_setspeed(struct imxiic_softc *sc, u_int speed) -{ - if (!sc->frequency) { - uint32_t i2c_clk_rate; - uint32_t div; - int i; - - i2c_clk_rate = clock_get_frequency(sc->sc_node, NULL) / 1000; - div = (i2c_clk_rate + speed - 1) / speed; - if (div < imxiic_clk_div[0][0]) - i = 0; - else if (div > imxiic_clk_div[49][0]) - i = 49; - else - for (i = 0; imxiic_clk_div[i][0] < div; i++); - - sc->frequency = imxiic_clk_div[i][1]; - } - - HWRITE2(sc, I2C_IFDR, sc->frequency); -} - -#if 0 -int -imxiic_intr(void *arg) -{ - struct imxiic_softc *sc = arg; - u_int16_t status; - - status = HREAD2(sc, I2C_I2SR); - - if (ISSET(status, I2C_I2SR_IIF)) { - /* acknowledge the interrupts */ - HWRITE2(sc, I2C_I2SR, - HREAD2(sc, I2C_I2SR) & ~I2C_I2SR_IIF); - - sc->intr_status |= status; - wakeup(&sc->intr_status); - } - - return (0); -} - -int -imxiic_wait_intr(struct imxiic_softc *sc, int mask, int timo) -{ - int status; - int s; - - s = splbio(); - - status = sc->intr_status & mask; - while (status == 0) { - if (tsleep(&sc->intr_status, PWAIT, "hcintr", timo) - == EWOULDBLOCK) { - break; - } - status = sc->intr_status & mask; - } - status = sc->intr_status & mask; - sc->intr_status &= ~status; - - splx(s); - return status; -} -#endif - -int -imxiic_wait_state(struct imxiic_softc *sc, uint32_t mask, uint32_t value) -{ - uint32_t state; - int timeout; - state = HREAD2(sc, I2C_I2SR); - for (timeout = 1000; timeout > 0; timeout--) { - if (((state = HREAD2(sc, I2C_I2SR)) & mask) == value) - return 0; - delay(10); - } - return ETIMEDOUT; -} - -int -imxiic_read(struct imxiic_softc *sc, int addr, void *data, int len) -{ - int i; - - HWRITE2(sc, I2C_I2DR, (addr << 1) | 1); - - if (imxiic_wait_state(sc, I2C_I2SR_IIF, I2C_I2SR_IIF)) - return (EIO); - HCLR2(sc, I2C_I2SR, I2C_I2SR_IIF); - if (HREAD2(sc, I2C_I2SR) & I2C_I2SR_RXAK) - return (EIO); - - HCLR2(sc, I2C_I2CR, I2C_I2CR_MTX); - if (len - 1) - HCLR2(sc, I2C_I2CR, I2C_I2CR_TXAK); - - /* dummy read */ - HREAD2(sc, I2C_I2DR); - - for (i = 0; i < len; i++) { - if (imxiic_wait_state(sc, I2C_I2SR_IIF, I2C_I2SR_IIF)) - return (EIO); - HCLR2(sc, I2C_I2SR, I2C_I2SR_IIF); - - if (i == (len - 1)) { - HCLR2(sc, I2C_I2CR, I2C_I2CR_MSTA | I2C_I2CR_MTX); - imxiic_wait_state(sc, I2C_I2SR_IBB, 0); - sc->stopped = 1; - } else if (i == (len - 2)) { - HSET2(sc, I2C_I2CR, I2C_I2CR_TXAK); - } - ((uint8_t*)data)[i] = HREAD2(sc, I2C_I2DR); - } - - return 0; -} - -int -imxiic_write(struct imxiic_softc *sc, int addr, const void *cmd, int cmdlen, - const void *data, int len) -{ - int i; - - HWRITE2(sc, I2C_I2DR, addr << 1); - - if (imxiic_wait_state(sc, I2C_I2SR_IIF, I2C_I2SR_IIF)) - return (EIO); - HCLR2(sc, I2C_I2SR, I2C_I2SR_IIF); - if (HREAD2(sc, I2C_I2SR) & I2C_I2SR_RXAK) - return (EIO); - - for (i = 0; i < cmdlen; i++) { - HWRITE2(sc, I2C_I2DR, ((uint8_t*)cmd)[i]); - if (imxiic_wait_state(sc, I2C_I2SR_IIF, I2C_I2SR_IIF)) - return (EIO); - HCLR2(sc, I2C_I2SR, I2C_I2SR_IIF); - if (HREAD2(sc, I2C_I2SR) & I2C_I2SR_RXAK) - return (EIO); - } - - for (i = 0; i < len; i++) { - HWRITE2(sc, I2C_I2DR, ((uint8_t*)data)[i]); - if (imxiic_wait_state(sc, I2C_I2SR_IIF, I2C_I2SR_IIF)) - return (EIO); - HCLR2(sc, I2C_I2SR, I2C_I2SR_IIF); - if (HREAD2(sc, I2C_I2SR) & I2C_I2SR_RXAK) - return (EIO); - } - return 0; -} - -int -imxiic_i2c_acquire_bus(void *cookie, int flags) -{ - struct imxiic_softc *sc = cookie; - - rw_enter(&sc->sc_buslock, RW_WRITE); - - /* clock gating */ - clock_enable(sc->sc_node, NULL); - - /* set speed to 100kHz */ - imxiic_setspeed(sc, 100); - - /* enable the controller */ - HWRITE2(sc, I2C_I2SR, 0); - HWRITE2(sc, I2C_I2CR, I2C_I2CR_IEN); - - /* wait for it to be stable */ - delay(50); - - return 0; -} - -void -imxiic_i2c_release_bus(void *cookie, int flags) -{ - struct imxiic_softc *sc = cookie; - - HWRITE2(sc, I2C_I2CR, 0); - - rw_exit(&sc->sc_buslock); -} - -int -imxiic_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, - const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags) -{ - struct imxiic_softc *sc = cookie; - int ret = 0; - - if (!I2C_OP_STOP_P(op)) - return EINVAL; - if (I2C_OP_READ_P(op) && cmdlen > 0) - return EINVAL; - - /* start transaction */ - HSET2(sc, I2C_I2CR, I2C_I2CR_MSTA); - - if (imxiic_wait_state(sc, I2C_I2SR_IBB, I2C_I2SR_IBB)) { - ret = EIO; - goto fail; - } - - sc->stopped = 0; - - HSET2(sc, I2C_I2CR, I2C_I2CR_IIEN | I2C_I2CR_MTX | I2C_I2CR_TXAK); - - if (I2C_OP_READ_P(op)) { - ret = imxiic_read(sc, addr, buf, len); - } else { - ret = imxiic_write(sc, addr, cmdbuf, cmdlen, buf, len); - } - -fail: - if (!sc->stopped) { - HCLR2(sc, I2C_I2CR, I2C_I2CR_MSTA | I2C_I2CR_MTX); - imxiic_wait_state(sc, I2C_I2SR_IBB, 0); - sc->stopped = 1; - } - - return ret; -} - -int -imxiic_detach(struct device *self, int flags) -{ - struct imxiic_softc *sc = (struct imxiic_softc *)self; - - HWRITE2(sc, I2C_IADR, 0); - HWRITE2(sc, I2C_IFDR, 0); - HWRITE2(sc, I2C_I2CR, 0); - HWRITE2(sc, I2C_I2SR, 0); - - bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios); - return 0; -} - -void -imxiic_scan(struct device *self, struct i2cbus_attach_args *iba, void *aux) -{ - int iba_node = *(int *)aux; - extern int iic_print(void *, const char *); - struct i2c_attach_args ia; - char name[32]; - uint32_t reg[1]; - int node; - - for (node = OF_child(iba_node); node; node = OF_peer(node)) { - memset(name, 0, sizeof(name)); - memset(reg, 0, sizeof(reg)); - - if (OF_getprop(node, "compatible", name, sizeof(name)) == -1) - continue; - if (name[0] == '\0') - continue; - - if (OF_getprop(node, "reg", ®, sizeof(reg)) != sizeof(reg)) - continue; - - memset(&ia, 0, sizeof(ia)); - ia.ia_tag = iba->iba_tag; - ia.ia_addr = bemtoh32(®[0]); - ia.ia_name = name; - ia.ia_cookie = &node; - - config_found(self, &ia, iic_print); - } -} diff --git a/sys/arch/armv7/imx/imxiicvar.h b/sys/arch/armv7/imx/imxiicvar.h deleted file mode 100644 index cd703366bfa..00000000000 --- a/sys/arch/armv7/imx/imxiicvar.h +++ /dev/null @@ -1,44 +0,0 @@ -/* $OpenBSD: imxiicvar.h,v 1.1 2013/09/06 20:45:54 patrick Exp $ */ -/* - * Copyright (c) 2013 Patrick Wildt - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IMXIICVAR_H -#define IMXIICVAR_H - -#include -#include -#include -#include - -#include - -static uint16_t imxiic_clk_div[50][2] = { - { 22, 0x20 }, { 24, 0x21 }, { 26, 0x22 }, { 28, 0x23 }, - { 30, 0x00 }, { 32, 0x24 }, { 36, 0x25 }, { 40, 0x26 }, - { 42, 0x03 }, { 44, 0x27 }, { 48, 0x28 }, { 52, 0x05 }, - { 56, 0x29 }, { 60, 0x06 }, { 64, 0x2A }, { 72, 0x2B }, - { 80, 0x2C }, { 88, 0x09 }, { 96, 0x2D }, { 104, 0x0A }, - { 112, 0x2E }, { 128, 0x2F }, { 144, 0x0C }, { 160, 0x30 }, - { 192, 0x31 }, { 224, 0x32 }, { 240, 0x0F }, { 256, 0x33 }, - { 288, 0x10 }, { 320, 0x34 }, { 384, 0x35 }, { 448, 0x36 }, - { 480, 0x13 }, { 512, 0x37 }, { 576, 0x14 }, { 640, 0x38 }, - { 768, 0x39 }, { 896, 0x3A }, { 960, 0x17 }, { 1024, 0x3B }, - { 1152, 0x18 }, { 1280, 0x3C }, { 1536, 0x3D }, { 1792, 0x3E }, - { 1920, 0x1B }, { 2048, 0x3F }, { 2304, 0x1C }, { 2560, 0x1D }, - { 3072, 0x1E }, { 3840, 0x1F } -}; - -#endif diff --git a/sys/dev/fdt/files.fdt b/sys/dev/fdt/files.fdt index b7c6504a9fd..32644969204 100644 --- a/sys/dev/fdt/files.fdt +++ b/sys/dev/fdt/files.fdt @@ -1,4 +1,4 @@ -# $OpenBSD: files.fdt,v 1.49 2018/03/30 19:50:55 patrick Exp $ +# $OpenBSD: files.fdt,v 1.50 2018/03/30 20:02:28 patrick Exp $ # # Config file and device description for machine-independent FDT code. # Included by ports that need it. @@ -197,3 +197,7 @@ file dev/fdt/imxgpio.c imxgpio device imxesdhc: sdmmcbus attach imxesdhc at fdt file dev/fdt/imxesdhc.c imxesdhc + +device imxiic: i2cbus +attach imxiic at fdt +file dev/fdt/imxiic.c imxiic diff --git a/sys/dev/fdt/imxiic.c b/sys/dev/fdt/imxiic.c new file mode 100644 index 00000000000..e2dd4528775 --- /dev/null +++ b/sys/dev/fdt/imxiic.c @@ -0,0 +1,432 @@ +/* $OpenBSD: imxiic.c,v 1.1 2018/03/30 20:02:28 patrick Exp $ */ +/* + * Copyright (c) 2013 Patrick Wildt + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include + +/* registers */ +#define I2C_IADR 0x00 +#define I2C_IFDR 0x04 +#define I2C_I2CR 0x08 +#define I2C_I2SR 0x0C +#define I2C_I2DR 0x10 + +#define I2C_I2CR_RSTA (1 << 2) +#define I2C_I2CR_TXAK (1 << 3) +#define I2C_I2CR_MTX (1 << 4) +#define I2C_I2CR_MSTA (1 << 5) +#define I2C_I2CR_IIEN (1 << 6) +#define I2C_I2CR_IEN (1 << 7) +#define I2C_I2SR_RXAK (1 << 0) +#define I2C_I2SR_IIF (1 << 1) +#define I2C_I2SR_IBB (1 << 5) + +struct imxiic_softc { + struct device sc_dev; + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; + bus_size_t sc_ios; + void *sc_ih; + int sc_node; + + struct rwlock sc_buslock; + struct i2c_controller i2c_tag; + + uint16_t frequency; + uint16_t intr_status; + uint16_t stopped; +}; + +int imxiic_match(struct device *, void *, void *); +void imxiic_attach(struct device *, struct device *, void *); +int imxiic_detach(struct device *, int); +void imxiic_setspeed(struct imxiic_softc *, u_int); +int imxiic_intr(void *); +int imxiic_wait_intr(struct imxiic_softc *, int, int); +int imxiic_wait_state(struct imxiic_softc *, uint32_t, uint32_t); +int imxiic_read(struct imxiic_softc *, int, void *, int); +int imxiic_write(struct imxiic_softc *, int, const void *, int, + const void *, int); + +int imxiic_i2c_acquire_bus(void *, int); +void imxiic_i2c_release_bus(void *, int); +int imxiic_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t, + void *, size_t, int); + +#define HREAD2(sc, reg) \ + (bus_space_read_2((sc)->sc_iot, (sc)->sc_ioh, (reg))) +#define HWRITE2(sc, reg, val) \ + bus_space_write_2((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) +#define HSET2(sc, reg, bits) \ + HWRITE2((sc), (reg), HREAD2((sc), (reg)) | (bits)) +#define HCLR2(sc, reg, bits) \ + HWRITE2((sc), (reg), HREAD2((sc), (reg)) & ~(bits)) + +void imxiic_scan(struct device *, struct i2cbus_attach_args *, void *); + +struct cfattach imxiic_ca = { + sizeof(struct imxiic_softc), imxiic_match, imxiic_attach, + imxiic_detach +}; + +struct cfdriver imxiic_cd = { + NULL, "imxiic", DV_DULL +}; + +int +imxiic_match(struct device *parent, void *match, void *aux) +{ + struct fdt_attach_args *faa = aux; + + return OF_is_compatible(faa->fa_node, "fsl,imx21-i2c"); +} + +void +imxiic_attach(struct device *parent, struct device *self, void *aux) +{ + struct imxiic_softc *sc = (struct imxiic_softc *)self; + struct fdt_attach_args *faa = aux; + + if (faa->fa_nreg < 1) + return; + + sc->sc_iot = faa->fa_iot; + sc->sc_ios = faa->fa_reg[0].size; + sc->sc_node = faa->fa_node; + if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, + faa->fa_reg[0].size, 0, &sc->sc_ioh)) + panic("imxiic_attach: bus_space_map failed!"); + +#if 0 + sc->sc_ih = arm_intr_establish_fdt(faa->fa_node, IPL_BIO, + imxiic_intr, sc, sc->sc_dev.dv_xname); +#endif + + printf("\n"); + + /* set iomux pins */ + pinctrl_byname(faa->fa_node, "default"); + + /* set speed to 100kHz */ + imxiic_setspeed(sc, 100); + + /* reset */ + HWRITE2(sc, I2C_I2CR, 0); + HWRITE2(sc, I2C_I2SR, 0); + + sc->stopped = 1; + rw_init(&sc->sc_buslock, sc->sc_dev.dv_xname); + + struct i2cbus_attach_args iba; + + sc->i2c_tag.ic_cookie = sc; + sc->i2c_tag.ic_acquire_bus = imxiic_i2c_acquire_bus; + sc->i2c_tag.ic_release_bus = imxiic_i2c_release_bus; + sc->i2c_tag.ic_exec = imxiic_i2c_exec; + + bzero(&iba, sizeof iba); + iba.iba_name = "iic"; + iba.iba_tag = &sc->i2c_tag; + iba.iba_bus_scan = imxiic_scan; + iba.iba_bus_scan_arg = &sc->sc_node; + config_found(&sc->sc_dev, &iba, iicbus_print); +} + +void +imxiic_setspeed(struct imxiic_softc *sc, u_int speed) +{ + if (!sc->frequency) { + uint32_t i2c_clk_rate; + uint32_t div; + int i; + + i2c_clk_rate = clock_get_frequency(sc->sc_node, NULL) / 1000; + div = (i2c_clk_rate + speed - 1) / speed; + if (div < imxiic_clk_div[0][0]) + i = 0; + else if (div > imxiic_clk_div[49][0]) + i = 49; + else + for (i = 0; imxiic_clk_div[i][0] < div; i++); + + sc->frequency = imxiic_clk_div[i][1]; + } + + HWRITE2(sc, I2C_IFDR, sc->frequency); +} + +#if 0 +int +imxiic_intr(void *arg) +{ + struct imxiic_softc *sc = arg; + u_int16_t status; + + status = HREAD2(sc, I2C_I2SR); + + if (ISSET(status, I2C_I2SR_IIF)) { + /* acknowledge the interrupts */ + HWRITE2(sc, I2C_I2SR, + HREAD2(sc, I2C_I2SR) & ~I2C_I2SR_IIF); + + sc->intr_status |= status; + wakeup(&sc->intr_status); + } + + return (0); +} + +int +imxiic_wait_intr(struct imxiic_softc *sc, int mask, int timo) +{ + int status; + int s; + + s = splbio(); + + status = sc->intr_status & mask; + while (status == 0) { + if (tsleep(&sc->intr_status, PWAIT, "hcintr", timo) + == EWOULDBLOCK) { + break; + } + status = sc->intr_status & mask; + } + status = sc->intr_status & mask; + sc->intr_status &= ~status; + + splx(s); + return status; +} +#endif + +int +imxiic_wait_state(struct imxiic_softc *sc, uint32_t mask, uint32_t value) +{ + uint32_t state; + int timeout; + state = HREAD2(sc, I2C_I2SR); + for (timeout = 1000; timeout > 0; timeout--) { + if (((state = HREAD2(sc, I2C_I2SR)) & mask) == value) + return 0; + delay(10); + } + return ETIMEDOUT; +} + +int +imxiic_read(struct imxiic_softc *sc, int addr, void *data, int len) +{ + int i; + + HWRITE2(sc, I2C_I2DR, (addr << 1) | 1); + + if (imxiic_wait_state(sc, I2C_I2SR_IIF, I2C_I2SR_IIF)) + return (EIO); + HCLR2(sc, I2C_I2SR, I2C_I2SR_IIF); + if (HREAD2(sc, I2C_I2SR) & I2C_I2SR_RXAK) + return (EIO); + + HCLR2(sc, I2C_I2CR, I2C_I2CR_MTX); + if (len - 1) + HCLR2(sc, I2C_I2CR, I2C_I2CR_TXAK); + + /* dummy read */ + HREAD2(sc, I2C_I2DR); + + for (i = 0; i < len; i++) { + if (imxiic_wait_state(sc, I2C_I2SR_IIF, I2C_I2SR_IIF)) + return (EIO); + HCLR2(sc, I2C_I2SR, I2C_I2SR_IIF); + + if (i == (len - 1)) { + HCLR2(sc, I2C_I2CR, I2C_I2CR_MSTA | I2C_I2CR_MTX); + imxiic_wait_state(sc, I2C_I2SR_IBB, 0); + sc->stopped = 1; + } else if (i == (len - 2)) { + HSET2(sc, I2C_I2CR, I2C_I2CR_TXAK); + } + ((uint8_t*)data)[i] = HREAD2(sc, I2C_I2DR); + } + + return 0; +} + +int +imxiic_write(struct imxiic_softc *sc, int addr, const void *cmd, int cmdlen, + const void *data, int len) +{ + int i; + + HWRITE2(sc, I2C_I2DR, addr << 1); + + if (imxiic_wait_state(sc, I2C_I2SR_IIF, I2C_I2SR_IIF)) + return (EIO); + HCLR2(sc, I2C_I2SR, I2C_I2SR_IIF); + if (HREAD2(sc, I2C_I2SR) & I2C_I2SR_RXAK) + return (EIO); + + for (i = 0; i < cmdlen; i++) { + HWRITE2(sc, I2C_I2DR, ((uint8_t*)cmd)[i]); + if (imxiic_wait_state(sc, I2C_I2SR_IIF, I2C_I2SR_IIF)) + return (EIO); + HCLR2(sc, I2C_I2SR, I2C_I2SR_IIF); + if (HREAD2(sc, I2C_I2SR) & I2C_I2SR_RXAK) + return (EIO); + } + + for (i = 0; i < len; i++) { + HWRITE2(sc, I2C_I2DR, ((uint8_t*)data)[i]); + if (imxiic_wait_state(sc, I2C_I2SR_IIF, I2C_I2SR_IIF)) + return (EIO); + HCLR2(sc, I2C_I2SR, I2C_I2SR_IIF); + if (HREAD2(sc, I2C_I2SR) & I2C_I2SR_RXAK) + return (EIO); + } + return 0; +} + +int +imxiic_i2c_acquire_bus(void *cookie, int flags) +{ + struct imxiic_softc *sc = cookie; + + rw_enter(&sc->sc_buslock, RW_WRITE); + + /* clock gating */ + clock_enable(sc->sc_node, NULL); + + /* set speed to 100kHz */ + imxiic_setspeed(sc, 100); + + /* enable the controller */ + HWRITE2(sc, I2C_I2SR, 0); + HWRITE2(sc, I2C_I2CR, I2C_I2CR_IEN); + + /* wait for it to be stable */ + delay(50); + + return 0; +} + +void +imxiic_i2c_release_bus(void *cookie, int flags) +{ + struct imxiic_softc *sc = cookie; + + HWRITE2(sc, I2C_I2CR, 0); + + rw_exit(&sc->sc_buslock); +} + +int +imxiic_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, + const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags) +{ + struct imxiic_softc *sc = cookie; + int ret = 0; + + if (!I2C_OP_STOP_P(op)) + return EINVAL; + if (I2C_OP_READ_P(op) && cmdlen > 0) + return EINVAL; + + /* start transaction */ + HSET2(sc, I2C_I2CR, I2C_I2CR_MSTA); + + if (imxiic_wait_state(sc, I2C_I2SR_IBB, I2C_I2SR_IBB)) { + ret = EIO; + goto fail; + } + + sc->stopped = 0; + + HSET2(sc, I2C_I2CR, I2C_I2CR_IIEN | I2C_I2CR_MTX | I2C_I2CR_TXAK); + + if (I2C_OP_READ_P(op)) { + ret = imxiic_read(sc, addr, buf, len); + } else { + ret = imxiic_write(sc, addr, cmdbuf, cmdlen, buf, len); + } + +fail: + if (!sc->stopped) { + HCLR2(sc, I2C_I2CR, I2C_I2CR_MSTA | I2C_I2CR_MTX); + imxiic_wait_state(sc, I2C_I2SR_IBB, 0); + sc->stopped = 1; + } + + return ret; +} + +int +imxiic_detach(struct device *self, int flags) +{ + struct imxiic_softc *sc = (struct imxiic_softc *)self; + + HWRITE2(sc, I2C_IADR, 0); + HWRITE2(sc, I2C_IFDR, 0); + HWRITE2(sc, I2C_I2CR, 0); + HWRITE2(sc, I2C_I2SR, 0); + + bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios); + return 0; +} + +void +imxiic_scan(struct device *self, struct i2cbus_attach_args *iba, void *aux) +{ + int iba_node = *(int *)aux; + extern int iic_print(void *, const char *); + struct i2c_attach_args ia; + char name[32]; + uint32_t reg[1]; + int node; + + for (node = OF_child(iba_node); node; node = OF_peer(node)) { + memset(name, 0, sizeof(name)); + memset(reg, 0, sizeof(reg)); + + if (OF_getprop(node, "compatible", name, sizeof(name)) == -1) + continue; + if (name[0] == '\0') + continue; + + if (OF_getprop(node, "reg", ®, sizeof(reg)) != sizeof(reg)) + continue; + + memset(&ia, 0, sizeof(ia)); + ia.ia_tag = iba->iba_tag; + ia.ia_addr = bemtoh32(®[0]); + ia.ia_name = name; + ia.ia_cookie = &node; + + config_found(self, &ia, iic_print); + } +} diff --git a/sys/dev/fdt/imxiicvar.h b/sys/dev/fdt/imxiicvar.h new file mode 100644 index 00000000000..56824cac385 --- /dev/null +++ b/sys/dev/fdt/imxiicvar.h @@ -0,0 +1,44 @@ +/* $OpenBSD: imxiicvar.h,v 1.1 2018/03/30 20:02:28 patrick Exp $ */ +/* + * Copyright (c) 2013 Patrick Wildt + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IMXIICVAR_H +#define IMXIICVAR_H + +#include +#include +#include +#include + +#include + +static uint16_t imxiic_clk_div[50][2] = { + { 22, 0x20 }, { 24, 0x21 }, { 26, 0x22 }, { 28, 0x23 }, + { 30, 0x00 }, { 32, 0x24 }, { 36, 0x25 }, { 40, 0x26 }, + { 42, 0x03 }, { 44, 0x27 }, { 48, 0x28 }, { 52, 0x05 }, + { 56, 0x29 }, { 60, 0x06 }, { 64, 0x2A }, { 72, 0x2B }, + { 80, 0x2C }, { 88, 0x09 }, { 96, 0x2D }, { 104, 0x0A }, + { 112, 0x2E }, { 128, 0x2F }, { 144, 0x0C }, { 160, 0x30 }, + { 192, 0x31 }, { 224, 0x32 }, { 240, 0x0F }, { 256, 0x33 }, + { 288, 0x10 }, { 320, 0x34 }, { 384, 0x35 }, { 448, 0x36 }, + { 480, 0x13 }, { 512, 0x37 }, { 576, 0x14 }, { 640, 0x38 }, + { 768, 0x39 }, { 896, 0x3A }, { 960, 0x17 }, { 1024, 0x3B }, + { 1152, 0x18 }, { 1280, 0x3C }, { 1536, 0x3D }, { 1792, 0x3E }, + { 1920, 0x1B }, { 2048, 0x3F }, { 2304, 0x1C }, { 2560, 0x1D }, + { 3072, 0x1E }, { 3840, 0x1F } +}; + +#endif -- cgit v1.2.3