Index: head/sys/arm/allwinner/a10_clk.c =================================================================== --- head/sys/arm/allwinner/a10_clk.c (revision 295625) +++ head/sys/arm/allwinner/a10_clk.c (revision 295626) @@ -1,444 +1,467 @@ /*- * Copyright (c) 2013 Ganbold Tsagaankhuu * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* Simple clock driver for Allwinner A10 */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include "a10_clk.h" struct a10_ccm_softc { struct resource *res; bus_space_tag_t bst; bus_space_handle_t bsh; int pll6_enabled; }; static struct a10_ccm_softc *a10_ccm_sc = NULL; #define ccm_read_4(sc, reg) \ bus_space_read_4((sc)->bst, (sc)->bsh, (reg)) #define ccm_write_4(sc, reg, val) \ bus_space_write_4((sc)->bst, (sc)->bsh, (reg), (val)) static int a10_ccm_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_is_compatible(dev, "allwinner,sun4i-ccm")) { device_set_desc(dev, "Allwinner Clock Control Module"); return(BUS_PROBE_DEFAULT); } return (ENXIO); } static int a10_ccm_attach(device_t dev) { struct a10_ccm_softc *sc = device_get_softc(dev); int rid = 0; if (a10_ccm_sc) return (ENXIO); sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (!sc->res) { device_printf(dev, "could not allocate resource\n"); return (ENXIO); } sc->bst = rman_get_bustag(sc->res); sc->bsh = rman_get_bushandle(sc->res); a10_ccm_sc = sc; return (0); } static device_method_t a10_ccm_methods[] = { DEVMETHOD(device_probe, a10_ccm_probe), DEVMETHOD(device_attach, a10_ccm_attach), { 0, 0 } }; static driver_t a10_ccm_driver = { "a10_ccm", a10_ccm_methods, sizeof(struct a10_ccm_softc), }; static devclass_t a10_ccm_devclass; EARLY_DRIVER_MODULE(a10_ccm, simplebus, a10_ccm_driver, a10_ccm_devclass, 0, 0, BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE); int a10_clk_usb_activate(void) { struct a10_ccm_softc *sc = a10_ccm_sc; uint32_t reg_value; if (sc == NULL) return (ENXIO); /* Gating AHB clock for USB */ reg_value = ccm_read_4(sc, CCM_AHB_GATING0); reg_value |= CCM_AHB_GATING_USB0; /* AHB clock gate usb0 */ reg_value |= CCM_AHB_GATING_EHCI0; /* AHB clock gate ehci0 */ reg_value |= CCM_AHB_GATING_EHCI1; /* AHB clock gate ehci1 */ ccm_write_4(sc, CCM_AHB_GATING0, reg_value); /* Enable clock for USB */ reg_value = ccm_read_4(sc, CCM_USB_CLK); reg_value |= CCM_USB_PHY; /* USBPHY */ reg_value |= CCM_USB0_RESET; /* disable reset for USB0 */ reg_value |= CCM_USB1_RESET; /* disable reset for USB1 */ reg_value |= CCM_USB2_RESET; /* disable reset for USB2 */ ccm_write_4(sc, CCM_USB_CLK, reg_value); return (0); } int a10_clk_usb_deactivate(void) { struct a10_ccm_softc *sc = a10_ccm_sc; uint32_t reg_value; if (sc == NULL) return (ENXIO); /* Disable clock for USB */ reg_value = ccm_read_4(sc, CCM_USB_CLK); reg_value &= ~CCM_USB_PHY; /* USBPHY */ reg_value &= ~CCM_USB0_RESET; /* reset for USB0 */ reg_value &= ~CCM_USB1_RESET; /* reset for USB1 */ reg_value &= ~CCM_USB2_RESET; /* reset for USB2 */ ccm_write_4(sc, CCM_USB_CLK, reg_value); /* Disable gating AHB clock for USB */ reg_value = ccm_read_4(sc, CCM_AHB_GATING0); reg_value &= ~CCM_AHB_GATING_USB0; /* disable AHB clock gate usb0 */ reg_value &= ~CCM_AHB_GATING_EHCI0; /* disable AHB clock gate ehci0 */ reg_value &= ~CCM_AHB_GATING_EHCI1; /* disable AHB clock gate ehci1 */ ccm_write_4(sc, CCM_AHB_GATING0, reg_value); return (0); } int a10_clk_emac_activate(void) { struct a10_ccm_softc *sc = a10_ccm_sc; uint32_t reg_value; if (sc == NULL) return (ENXIO); /* Gating AHB clock for EMAC */ reg_value = ccm_read_4(sc, CCM_AHB_GATING0); reg_value |= CCM_AHB_GATING_EMAC; ccm_write_4(sc, CCM_AHB_GATING0, reg_value); return (0); } int a10_clk_gmac_activate(phandle_t node) { char *phy_type; struct a10_ccm_softc *sc; uint32_t reg_value; sc = a10_ccm_sc; if (sc == NULL) return (ENXIO); /* Gating AHB clock for GMAC */ reg_value = ccm_read_4(sc, CCM_AHB_GATING1); reg_value |= CCM_AHB_GATING_GMAC; ccm_write_4(sc, CCM_AHB_GATING1, reg_value); /* Set GMAC mode. */ reg_value = CCM_GMAC_CLK_MII; if (OF_getprop_alloc(node, "phy-mode", 1, (void **)&phy_type) > 0) { if (strcasecmp(phy_type, "rgmii") == 0) reg_value = CCM_GMAC_CLK_RGMII | CCM_GMAC_MODE_RGMII; else if (strcasecmp(phy_type, "rgmii-bpi") == 0) { reg_value = CCM_GMAC_CLK_RGMII | CCM_GMAC_MODE_RGMII; reg_value |= (3 << CCM_GMAC_CLK_DELAY_SHIFT); } free(phy_type, M_OFWPROP); } ccm_write_4(sc, CCM_GMAC_CLK, reg_value); return (0); } static void a10_clk_pll6_enable(void) { struct a10_ccm_softc *sc; uint32_t reg_value; /* * SATA needs PLL6 to be a 100MHz clock. * The SATA output frequency is 24MHz * n * k / m / 6. * To get to 100MHz, k & m must be equal and n must be 25. * For other uses the output frequency is 24MHz * n * k / 2. */ sc = a10_ccm_sc; if (sc->pll6_enabled) return; reg_value = ccm_read_4(sc, CCM_PLL6_CFG); reg_value &= ~CCM_PLL_CFG_BYPASS; reg_value &= ~(CCM_PLL_CFG_FACTOR_K | CCM_PLL_CFG_FACTOR_M | CCM_PLL_CFG_FACTOR_N); reg_value |= (25 << CCM_PLL_CFG_FACTOR_N_SHIFT); reg_value |= CCM_PLL6_CFG_SATA_CLKEN; reg_value |= CCM_PLL_CFG_ENABLE; ccm_write_4(sc, CCM_PLL6_CFG, reg_value); sc->pll6_enabled = 1; } static unsigned int a10_clk_pll6_get_rate(void) { struct a10_ccm_softc *sc; uint32_t k, n, reg_value; sc = a10_ccm_sc; reg_value = ccm_read_4(sc, CCM_PLL6_CFG); n = ((reg_value & CCM_PLL_CFG_FACTOR_N) >> CCM_PLL_CFG_FACTOR_N_SHIFT); k = ((reg_value & CCM_PLL_CFG_FACTOR_K) >> CCM_PLL_CFG_FACTOR_K_SHIFT) + 1; return ((CCM_CLK_REF_FREQ * n * k) / 2); } static int a10_clk_pll2_set_rate(unsigned int freq) { struct a10_ccm_softc *sc; uint32_t reg_value; unsigned int prediv, postdiv, n; sc = a10_ccm_sc; if (sc == NULL) return (ENXIO); reg_value = ccm_read_4(sc, CCM_PLL2_CFG); reg_value &= ~(CCM_PLL2_CFG_PREDIV | CCM_PLL2_CFG_POSTDIV | CCM_PLL_CFG_FACTOR_N); /* * Audio Codec needs PLL2 to be either 24576000 Hz or 22579200 Hz * * PLL2 output frequency is 24MHz * n / prediv / postdiv. * To get as close as possible to the desired rate, we use a * pre-divider of 21 and a post-divider of 4. With these values, * a multiplier of 86 or 79 gets us close to the target rates. */ prediv = 21; postdiv = 4; switch (freq) { case 24576000: n = 86; reg_value |= CCM_PLL_CFG_ENABLE; break; case 22579200: n = 79; reg_value |= CCM_PLL_CFG_ENABLE; break; case 0: n = 1; reg_value &= ~CCM_PLL_CFG_ENABLE; break; default: return (EINVAL); } reg_value |= (prediv << CCM_PLL2_CFG_PREDIV_SHIFT); reg_value |= (postdiv << CCM_PLL2_CFG_POSTDIV_SHIFT); reg_value |= (n << CCM_PLL_CFG_FACTOR_N_SHIFT); ccm_write_4(sc, CCM_PLL2_CFG, reg_value); return (0); } int a10_clk_ahci_activate(void) { struct a10_ccm_softc *sc; uint32_t reg_value; sc = a10_ccm_sc; if (sc == NULL) return (ENXIO); a10_clk_pll6_enable(); /* Gating AHB clock for SATA */ reg_value = ccm_read_4(sc, CCM_AHB_GATING0); reg_value |= CCM_AHB_GATING_SATA; ccm_write_4(sc, CCM_AHB_GATING0, reg_value); DELAY(1000); ccm_write_4(sc, CCM_SATA_CLK, CCM_PLL_CFG_ENABLE); return (0); } int a10_clk_mmc_activate(int devid) { struct a10_ccm_softc *sc; uint32_t reg_value; sc = a10_ccm_sc; if (sc == NULL) return (ENXIO); a10_clk_pll6_enable(); /* Gating AHB clock for SD/MMC */ reg_value = ccm_read_4(sc, CCM_AHB_GATING0); reg_value |= CCM_AHB_GATING_SDMMC0 << devid; ccm_write_4(sc, CCM_AHB_GATING0, reg_value); return (0); } int a10_clk_mmc_cfg(int devid, int freq) { struct a10_ccm_softc *sc; uint32_t clksrc, m, n, ophase, phase, reg_value; unsigned int pll_freq; sc = a10_ccm_sc; if (sc == NULL) return (ENXIO); freq /= 1000; if (freq <= 400) { pll_freq = CCM_CLK_REF_FREQ / 1000; clksrc = CCM_SD_CLK_SRC_SEL_OSC24M; ophase = 0; phase = 0; n = 2; } else if (freq <= 25000) { pll_freq = a10_clk_pll6_get_rate() / 1000; clksrc = CCM_SD_CLK_SRC_SEL_PLL6; ophase = 0; phase = 5; n = 2; } else if (freq <= 50000) { pll_freq = a10_clk_pll6_get_rate() / 1000; clksrc = CCM_SD_CLK_SRC_SEL_PLL6; ophase = 3; phase = 5; n = 0; } else return (EINVAL); m = ((pll_freq / (1 << n)) / (freq)) - 1; reg_value = ccm_read_4(sc, CCM_MMC0_SCLK_CFG + (devid * 4)); reg_value &= ~CCM_SD_CLK_SRC_SEL; reg_value |= (clksrc << CCM_SD_CLK_SRC_SEL_SHIFT); reg_value &= ~CCM_SD_CLK_PHASE_CTR; reg_value |= (phase << CCM_SD_CLK_PHASE_CTR_SHIFT); reg_value &= ~CCM_SD_CLK_DIV_RATIO_N; reg_value |= (n << CCM_SD_CLK_DIV_RATIO_N_SHIFT); reg_value &= ~CCM_SD_CLK_OPHASE_CTR; reg_value |= (ophase << CCM_SD_CLK_OPHASE_CTR_SHIFT); reg_value &= ~CCM_SD_CLK_DIV_RATIO_M; reg_value |= m; reg_value |= CCM_PLL_CFG_ENABLE; ccm_write_4(sc, CCM_MMC0_SCLK_CFG + (devid * 4), reg_value); return (0); } int +a10_clk_i2c_activate(int devid) +{ + struct a10_ccm_softc *sc; + uint32_t reg_value; + + sc = a10_ccm_sc; + if (sc == NULL) + return (ENXIO); + + a10_clk_pll6_enable(); + + /* Gating APB clock for I2C/TWI */ + reg_value = ccm_read_4(sc, CCM_APB1_GATING); + if (devid == 4) + reg_value |= CCM_APB1_GATING_TWI << 15; + else + reg_value |= CCM_APB1_GATING_TWI << devid; + ccm_write_4(sc, CCM_APB1_GATING, reg_value); + + return (0); +} + +int a10_clk_dmac_activate(void) { struct a10_ccm_softc *sc; uint32_t reg_value; sc = a10_ccm_sc; if (sc == NULL) return (ENXIO); /* Gating AHB clock for DMA controller */ reg_value = ccm_read_4(sc, CCM_AHB_GATING0); reg_value |= CCM_AHB_GATING_DMA; ccm_write_4(sc, CCM_AHB_GATING0, reg_value); return (0); } int a10_clk_codec_activate(unsigned int freq) { struct a10_ccm_softc *sc; uint32_t reg_value; sc = a10_ccm_sc; if (sc == NULL) return (ENXIO); a10_clk_pll2_set_rate(freq); /* Gating APB clock for ADDA */ reg_value = ccm_read_4(sc, CCM_APB0_GATING); reg_value |= CCM_APB0_GATING_ADDA; ccm_write_4(sc, CCM_APB0_GATING, reg_value); /* Enable audio codec clock */ reg_value = ccm_read_4(sc, CCM_AUDIO_CODEC_CLK); reg_value |= CCM_AUDIO_CODEC_ENABLE; ccm_write_4(sc, CCM_AUDIO_CODEC_CLK, reg_value); return (0); } Index: head/sys/arm/allwinner/a10_clk.h =================================================================== --- head/sys/arm/allwinner/a10_clk.h (revision 295625) +++ head/sys/arm/allwinner/a10_clk.h (revision 295626) @@ -1,172 +1,176 @@ /*- * Copyright (c) 2013 Ganbold Tsagaankhuu * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _A10_CLK_H_ #define _A10_CLK_H_ #define CCM_PLL1_CFG 0x0000 #define CCM_PLL1_TUN 0x0004 #define CCM_PLL2_CFG 0x0008 #define CCM_PLL2_TUN 0x000c #define CCM_PLL3_CFG 0x0010 #define CCM_PLL3_TUN 0x0014 #define CCM_PLL4_CFG 0x0018 #define CCM_PLL4_TUN 0x001c #define CCM_PLL5_CFG 0x0020 #define CCM_PLL5_TUN 0x0024 #define CCM_PLL6_CFG 0x0028 #define CCM_PLL6_TUN 0x002c #define CCM_PLL7_CFG 0x0030 #define CCM_PLL7_TUN 0x0034 #define CCM_PLL1_TUN2 0x0038 #define CCM_PLL5_TUN2 0x003c #define CCM_PLL_LOCK_DBG 0x004c #define CCM_OSC24M_CFG 0x0050 #define CCM_CPU_AHB_APB0_CFG 0x0054 #define CCM_APB1_CLK_DIV 0x0058 #define CCM_AXI_GATING 0x005c #define CCM_AHB_GATING0 0x0060 #define CCM_AHB_GATING1 0x0064 #define CCM_APB0_GATING 0x0068 #define CCM_APB1_GATING 0x006c #define CCM_NAND_SCLK_CFG 0x0080 #define CCM_MS_SCLK_CFG 0x0084 #define CCM_MMC0_SCLK_CFG 0x0088 #define CCM_MMC1_SCLK_CFG 0x008c #define CCM_MMC2_SCLK_CFG 0x0090 #define CCM_MMC3_SCLK_CFG 0x0094 #define CCM_TS_CLK 0x0098 #define CCM_SS_CLK 0x009c #define CCM_SPI0_CLK 0x00a0 #define CCM_SPI1_CLK 0x00a4 #define CCM_SPI2_CLK 0x00a8 #define CCM_PATA_CLK 0x00ac #define CCM_IR0_CLK 0x00b0 #define CCM_IR1_CLK 0x00b4 #define CCM_IIS_CLK 0x00b8 #define CCM_AC97_CLK 0x00bc #define CCM_SPDIF_CLK 0x00c0 #define CCM_KEYPAD_CLK 0x00c4 #define CCM_SATA_CLK 0x00c8 #define CCM_USB_CLK 0x00cc #define CCM_GPS_CLK 0x00d0 #define CCM_SPI3_CLK 0x00d4 #define CCM_DRAM_CLK 0x0100 #define CCM_BE0_SCLK 0x0104 #define CCM_BE1_SCLK 0x0108 #define CCM_FE0_CLK 0x010c #define CCM_FE1_CLK 0x0110 #define CCM_MP_CLK 0x0114 #define CCM_LCD0_CH0_CLK 0x0118 #define CCM_LCD1_CH0_CLK 0x011c #define CCM_CSI_ISP_CLK 0x0120 #define CCM_TVD_CLK 0x0128 #define CCM_LCD0_CH1_CLK 0x012c #define CCM_LCD1_CH1_CLK 0x0130 #define CCM_CS0_CLK 0x0134 #define CCM_CS1_CLK 0x0138 #define CCM_VE_CLK 0x013c #define CCM_AUDIO_CODEC_CLK 0x0140 #define CCM_AVS_CLK 0x0144 #define CCM_ACE_CLK 0x0148 #define CCM_LVDS_CLK 0x014c #define CCM_HDMI_CLK 0x0150 #define CCM_MALI400_CLK 0x0154 #define CCM_GMAC_CLK 0x0164 #define CCM_GMAC_CLK_DELAY_SHIFT 10 #define CCM_GMAC_CLK_MODE_MASK 0x7 #define CCM_GMAC_MODE_RGMII (1 << 2) #define CCM_GMAC_CLK_MII 0x0 #define CCM_GMAC_CLK_EXT_RGMII 0x1 #define CCM_GMAC_CLK_RGMII 0x2 /* APB0_GATING */ #define CCM_APB0_GATING_ADDA (1 << 0) /* AHB_GATING_REG0 */ #define CCM_AHB_GATING_USB0 (1 << 0) #define CCM_AHB_GATING_EHCI0 (1 << 1) #define CCM_AHB_GATING_EHCI1 (1 << 3) #define CCM_AHB_GATING_DMA (1 << 6) #define CCM_AHB_GATING_SDMMC0 (1 << 8) #define CCM_AHB_GATING_EMAC (1 << 17) #define CCM_AHB_GATING_SATA (1 << 25) /* AHB_GATING_REG1 */ #define CCM_AHB_GATING_GMAC (1 << 17) +/* APB1_GATING_REG */ +#define CCM_APB1_GATING_TWI (1 << 0) + #define CCM_USB_PHY (1 << 8) #define CCM_USB0_RESET (1 << 0) #define CCM_USB1_RESET (1 << 1) #define CCM_USB2_RESET (1 << 2) #define CCM_PLL_CFG_ENABLE (1U << 31) #define CCM_PLL_CFG_BYPASS (1U << 30) #define CCM_PLL_CFG_PLL5 (1U << 25) #define CCM_PLL_CFG_PLL6 (1U << 24) #define CCM_PLL_CFG_FACTOR_N 0x1f00 #define CCM_PLL_CFG_FACTOR_N_SHIFT 8 #define CCM_PLL_CFG_FACTOR_K 0x30 #define CCM_PLL_CFG_FACTOR_K_SHIFT 4 #define CCM_PLL_CFG_FACTOR_M 0x3 #define CCM_PLL2_CFG_POSTDIV 0x3c000000 #define CCM_PLL2_CFG_POSTDIV_SHIFT 26 #define CCM_PLL2_CFG_PREDIV 0x1f #define CCM_PLL2_CFG_PREDIV_SHIFT 0 #define CCM_PLL6_CFG_SATA_CLKEN (1U << 14) #define CCM_SD_CLK_SRC_SEL 0x3000000 #define CCM_SD_CLK_SRC_SEL_SHIFT 24 #define CCM_SD_CLK_SRC_SEL_OSC24M 0 #define CCM_SD_CLK_SRC_SEL_PLL6 1 #define CCM_SD_CLK_PHASE_CTR 0x700000 #define CCM_SD_CLK_PHASE_CTR_SHIFT 20 #define CCM_SD_CLK_DIV_RATIO_N 0x30000 #define CCM_SD_CLK_DIV_RATIO_N_SHIFT 16 #define CCM_SD_CLK_OPHASE_CTR 0x700 #define CCM_SD_CLK_OPHASE_CTR_SHIFT 8 #define CCM_SD_CLK_DIV_RATIO_M 0xf #define CCM_AUDIO_CODEC_ENABLE (1U << 31) #define CCM_CLK_REF_FREQ 24000000U int a10_clk_usb_activate(void); int a10_clk_usb_deactivate(void); int a10_clk_emac_activate(void); int a10_clk_gmac_activate(phandle_t); int a10_clk_ahci_activate(void); int a10_clk_mmc_activate(int); int a10_clk_mmc_cfg(int, int); +int a10_clk_i2c_activate(int); int a10_clk_dmac_activate(void); int a10_clk_codec_activate(unsigned int); #endif /* _A10_CLK_H_ */ Index: head/sys/arm/allwinner/files.allwinner =================================================================== --- head/sys/arm/allwinner/files.allwinner (revision 295625) +++ head/sys/arm/allwinner/files.allwinner (revision 295626) @@ -1,15 +1,16 @@ # $FreeBSD$ kern/kern_clocksource.c standard arm/allwinner/a10_ahci.c optional ahci arm/allwinner/a10_clk.c standard arm/allwinner/a10_common.c standard arm/allwinner/a10_ehci.c optional ehci arm/allwinner/a10_gpio.c optional gpio arm/allwinner/a10_mmc.c optional mmc arm/allwinner/a10_sramc.c standard arm/allwinner/a10_wdog.c standard arm/allwinner/a20/a20_cpu_cfg.c standard arm/allwinner/allwinner_machdep.c standard arm/allwinner/if_emac.c optional emac +dev/iicbus/twsi/a10_twsi.c optional twsi #arm/allwinner/console.c standard Index: head/sys/arm/conf/A10 =================================================================== --- head/sys/arm/conf/A10 (revision 295625) +++ head/sys/arm/conf/A10 (revision 295626) @@ -1,105 +1,106 @@ # # A10 -- Custom configuration for the AllWinner A10 SoC # # For more information on this file, please read the config(5) manual page, # and/or the handbook section on Kernel Configuration Files: # # http://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html # # The handbook is also available locally in /usr/share/doc/handbook # if you've installed the doc distribution, otherwise always see the # FreeBSD World Wide Web server (http://www.FreeBSD.org/) for the # latest information. # # An exhaustive list of options and more detailed explanations of the # device lines is also present in the ../../conf/NOTES and NOTES files. # If you are in doubt as to the purpose or necessity of a line, check first # in NOTES. # # $FreeBSD$ ident A10 include "std.armv6" include "../allwinner/std.a10" options HZ=100 options SCHED_4BSD # 4BSD scheduler options PLATFORM # Debugging for use in -current makeoptions DEBUG=-g # Build kernel with gdb(1) debug symbols options ALT_BREAK_TO_DEBUGGER #options VERBOSE_SYSINIT # Enable verbose sysinit messages options KDB # Enable kernel debugger support # For minimum debugger support (stable branch) use: #options KDB_TRACE # Print a stack trace for a panic # For full debugger support use this instead: options DDB # Enable the kernel debugger options INVARIANTS # Enable calls of extra sanity checking options INVARIANT_SUPPORT # Extra sanity checks of internal structures, required by INVARIANTS options WITNESS # Enable checks to detect deadlocks and cycles options WITNESS_SKIPSPIN # Don't run witness on spinlocks for speed #options DIAGNOSTIC # NFS root from boopt/dhcp #options BOOTP #options BOOTP_NFSROOT #options BOOTP_COMPAT #options BOOTP_NFSV3 #options BOOTP_WIRED_TO=emac0 # MMC/SD/SDIO Card slot support device mmc # mmc/sd bus device mmcsd # mmc/sd flash cards # ATA controllers device ahci # AHCI-compatible SATA controllers #device ata # Legacy ATA/SATA controllers # Console and misc device uart device uart_ns8250 device pty device snp device md device random # Entropy device # I2C support -#device iicbus -#device iic +device iicbus +device iic +device twsi # GPIO device gpio device gpioled device scbus # SCSI bus (required for ATA/SCSI) device da # Direct Access (disks) device pass # Passthrough device (direct ATA/SCSI access) # USB support options USB_HOST_ALIGN=64 # Align usb buffers to cache line size. device usb options USB_DEBUG #options USB_REQ_DEBUG #options USB_VERBOSE #device uhci #device ohci device ehci device umass # Ethernet device loop device ether device mii device bpf device emac # USB ethernet support, requires miibus device miibus # Flattened Device Tree options FDT # Configure using FDT/DTB data makeoptions MODULES_EXTRA=dtb/allwinner Index: head/sys/arm/conf/A20 =================================================================== --- head/sys/arm/conf/A20 (revision 295625) +++ head/sys/arm/conf/A20 (revision 295626) @@ -1,115 +1,116 @@ # # A20 -- Custom configuration for the Allwinner A20 ARM SoC # # For more information on this file, please read the config(5) manual page, # and/or the handbook section on Kernel Configuration Files: # # http://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html # # The handbook is also available locally in /usr/share/doc/handbook # if you've installed the doc distribution, otherwise always see the # FreeBSD World Wide Web server (http://www.FreeBSD.org/) for the # latest information. # # An exhaustive list of options and more detailed explanations of the # device lines is also present in the ../../conf/NOTES and NOTES files. # If you are in doubt as to the purpose or necessity of a line, check first # in NOTES. # # $FreeBSD$ ident A20 include "std.armv6" include "../allwinner/a20/std.a20" options ARM_INTRNG options HZ=100 options SCHED_ULE # ULE scheduler options SMP # Enable multiple cores options PLATFORM # Debugging for use in -current makeoptions DEBUG=-g # Build kernel with gdb(1) debug symbols options ALT_BREAK_TO_DEBUGGER #options VERBOSE_SYSINIT # Enable verbose sysinit messages options KDB # Enable kernel debugger support # For minimum debugger support (stable branch) use: #options KDB_TRACE # Print a stack trace for a panic # For full debugger support use this instead: options DDB # Enable the kernel debugger options INVARIANTS # Enable calls of extra sanity checking options INVARIANT_SUPPORT # Extra sanity checks of internal structures, required by INVARIANTS options WITNESS # Enable checks to detect deadlocks and cycles options WITNESS_SKIPSPIN # Don't run witness on spinlocks for speed #options DIAGNOSTIC # NFS root from boopt/dhcp #options BOOTP #options BOOTP_NFSROOT #options BOOTP_COMPAT #options BOOTP_NFSV3 #options BOOTP_WIRED_TO=dwc0 # Interrupt controller device gic # ARM Generic Timer device generic_timer # MMC/SD/SDIO Card slot support device mmc # mmc/sd bus device mmcsd # mmc/sd flash cards # ATA controllers device ahci # AHCI-compatible SATA controllers #device ata # Legacy ATA/SATA controllers # Console and misc device uart device uart_ns8250 device pty device snp device md device random # Entropy device # I2C support -#device iicbus -#device iic +device iicbus +device iic +device twsi # GPIO device gpio device gpioled device scbus # SCSI bus (required for ATA/SCSI) device da # Direct Access (disks) device pass # Passthrough device (direct ATA/SCSI access) # USB support options USB_HOST_ALIGN=64 # Align usb buffers to cache line size. device usb options USB_DEBUG #options USB_REQ_DEBUG #options USB_VERBOSE #device uhci #device ohci device ehci device umass # Ethernet device loop device ether device mii device bpf #device emac # 10/100 integrated EMAC controller device dwc # 10/100/1000 integrated GMAC controller # USB ethernet support, requires miibus device miibus # Flattened Device Tree options FDT # Configure using FDT/DTB data makeoptions MODULES_EXTRA=dtb/allwinner Index: head/sys/arm/mv/files.mv =================================================================== --- head/sys/arm/mv/files.mv (revision 295625) +++ head/sys/arm/mv/files.mv (revision 295626) @@ -1,30 +1,31 @@ # $FreeBSD$ # # The Marvell CPU cores # - Compliant with V5TE architecture # - Super scalar dual issue CPU # - Big/Little Endian # - MMU/MPU # - L1 Cache: Supports streaming and write allocate # - Variable pipeline stages # - Out-of-order execution # - Branch Prediction # - JTAG/ICE # - Vector Floating Point (VFP) unit # arm/mv/gpio.c optional gpio arm/mv/mv_common.c standard arm/mv/mv_localbus.c standard arm/mv/mv_machdep.c standard arm/mv/mv_pci.c optional pci arm/mv/mv_ts.c standard arm/mv/timer.c standard dev/cesa/cesa.c optional cesa +dev/iicbus/twsi/mv_twsi.c optional twsi dev/mge/if_mge.c optional mge dev/nand/nfc_mv.c optional nand dev/mvs/mvs_soc.c optional mvs dev/uart/uart_dev_ns8250.c optional uart dev/usb/controller/ehci_mv.c optional ehci kern/kern_clocksource.c standard Index: head/sys/dev/iicbus/twsi/a10_twsi.c =================================================================== --- head/sys/dev/iicbus/twsi/a10_twsi.c (nonexistent) +++ head/sys/dev/iicbus/twsi/a10_twsi.c (revision 295626) @@ -0,0 +1,131 @@ +/*- + * Copyright (c) 2016 Emmanuel Vadot + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "iicbus_if.h" + +#define TWI_ADDR 0x0 +#define TWI_XADDR 0x4 +#define TWI_DATA 0x8 +#define TWI_CNTR 0xC +#define TWI_STAT 0x10 +#define TWI_CCR 0x14 +#define TWI_SRST 0x18 +#define TWI_EFR 0x1C +#define TWI_LCR 0x20 + +static int +a10_twsi_probe(device_t dev) +{ + struct twsi_softc *sc; + + sc = device_get_softc(dev); + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (!ofw_bus_is_compatible(dev, "allwinner,sun4i-a10-i2c")) + return (ENXIO); + + device_set_desc(dev, "Allwinner Integrated I2C Bus Controller"); + return (BUS_PROBE_DEFAULT); +} + +static int +a10_twsi_attach(device_t dev) +{ + struct twsi_softc *sc; + + sc = device_get_softc(dev); + + /* Activate clock */ + a10_clk_i2c_activate(device_get_unit(dev)); + + sc->reg_data = TWI_DATA; + sc->reg_slave_addr = TWI_ADDR; + sc->reg_slave_ext_addr = TWI_XADDR; + sc->reg_control = TWI_CNTR; + sc->reg_status = TWI_STAT; + sc->reg_baud_rate = TWI_CCR; + sc->reg_soft_reset = TWI_SRST; + + /* Setup baud rate params */ + sc->baud_rate[IIC_SLOW].param = TWSI_BAUD_RATE_PARAM(11, 2); + sc->baud_rate[IIC_FAST].param = TWSI_BAUD_RATE_PARAM(11, 2); + sc->baud_rate[IIC_FASTEST].param = TWSI_BAUD_RATE_PARAM(2, 2); + + return (twsi_attach(dev)); +} + +static phandle_t +a10_twsi_get_node(device_t bus, device_t dev) +{ + return (ofw_bus_get_node(bus)); +} + +static device_method_t a10_twsi_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, a10_twsi_probe), + DEVMETHOD(device_attach, a10_twsi_attach), + + /* OFW methods */ + DEVMETHOD(ofw_bus_get_node, a10_twsi_get_node), + + { 0, 0 } +}; + +DEFINE_CLASS_1(iichb, a10_twsi_driver, a10_twsi_methods, + sizeof(struct twsi_softc), twsi_driver); + +static devclass_t a10_twsi_devclass; + +DRIVER_MODULE(a10_twsi, simplebus, a10_twsi_driver, a10_twsi_devclass, 0, 0); +DRIVER_MODULE(iicbus, a10_twsi, iicbus_driver, iicbus_devclass, 0, 0); +MODULE_DEPEND(a10_twsi, iicbus, 1, 1, 1); Property changes on: head/sys/dev/iicbus/twsi/a10_twsi.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: head/sys/dev/iicbus/twsi/mv_twsi.c =================================================================== --- head/sys/dev/iicbus/twsi/mv_twsi.c (nonexistent) +++ head/sys/dev/iicbus/twsi/mv_twsi.c (revision 295626) @@ -0,0 +1,252 @@ +/*- + * Copyright (C) 2008 MARVELL INTERNATIONAL LTD. + * All rights reserved. + * + * Developed by Semihalf. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of MARVELL nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Driver for the TWSI (aka I2C, aka IIC) bus controller found on Marvell + * and Allwinner SoCs. Supports master operation only, and works in polling mode. + * + * Calls to DELAY() are needed per Application Note AN-179 "TWSI Software + * Guidelines for Discovery(TM), Horizon (TM) and Feroceon(TM) Devices". + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "iicbus_if.h" + +#define MV_TWSI_NAME "twsi" +#define IICBUS_DEVNAME "iicbus" + +#define TWSI_ADDR 0x00 +#define TWSI_DATA 0x04 +#define TWSI_CNTR 0x08 +#define TWSI_XADDR 0x10 +#define TWSI_STAT 0x0c +#define TWSI_BAUD_RATE 0x0c +#define TWSI_SRST 0x1c + +#define TWSI_BAUD_RATE_RAW(C,M,N) ((C)/((10*(M+1))<<(N+1))) +#define TWSI_BAUD_RATE_SLOW 50000 /* 50kHz */ +#define TWSI_BAUD_RATE_FAST 100000 /* 100kHz */ + +#define TWSI_DEBUG +#undef TWSI_DEBUG + +#ifdef TWSI_DEBUG +#define debugf(fmt, args...) do { printf("%s(): ", __func__); printf(fmt,##args); } while (0) +#else +#define debugf(fmt, args...) +#endif + +static int mv_twsi_probe(device_t); +static int mv_twsi_attach(device_t); + +static struct ofw_compat_data compat_data[] = { + { "mrvl,twsi", true }, + { "marvell,mv64xxx-i2c", true }, + { NULL, false } +}; + +static device_method_t mv_twsi_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, mv_twsi_probe), + DEVMETHOD(device_attach, mv_twsi_attach), + + { 0, 0 } +}; + +DEFINE_CLASS_1(twsi, mv_twsi_driver, mv_twsi_methods, + sizeof(struct twsi_softc), twsi_driver); + +static devclass_t mv_twsi_devclass; + +DRIVER_MODULE(twsi, simplebus, mv_twsi_driver, mv_twsi_devclass, 0, 0); +DRIVER_MODULE(iicbus, twsi, iicbus_driver, iicbus_devclass, 0, 0); +MODULE_DEPEND(twsi, iicbus, 1, 1, 1); + +static int +mv_twsi_probe(device_t dev) +{ + struct twsi_softc *sc; + + sc = device_get_softc(dev); + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) + return (ENXIO); + + sc->reg_data = TWSI_DATA; + sc->reg_slave_addr = TWSI_ADDR; + sc->reg_slave_ext_addr = TWSI_XADDR; + sc->reg_control = TWSI_CNTR; + sc->reg_status = TWSI_STAT; + sc->reg_baud_rate = TWSI_BAUD_RATE; + sc->reg_soft_reset = TWSI_SRST; + + device_set_desc(dev, "Marvell Integrated I2C Bus Controller"); + return (BUS_PROBE_DEFAULT); +} + +#define ABSSUB(a,b) (((a) > (b)) ? (a) - (b) : (b) - (a)) +static void +mv_twsi_cal_baud_rate(const uint32_t target, struct twsi_baud_rate *rate) +{ + uint32_t clk, cur, diff, diff0; + int m, n, m0, n0; + + /* Calculate baud rate. */ + m0 = n0 = 4; /* Default values on reset */ + diff0 = 0xffffffff; + clk = get_tclk(); + + for (n = 0; n < 8; n++) { + for (m = 0; m < 16; m++) { + cur = TWSI_BAUD_RATE_RAW(clk,m,n); + diff = ABSSUB(target, cur); + if (diff < diff0) { + m0 = m; + n0 = n; + diff0 = diff; + } + } + } + rate->raw = TWSI_BAUD_RATE_RAW(clk, m0, n0); + rate->param = TWSI_BAUD_RATE_PARAM(m0, n0); + rate->m = m0; + rate->n = n0; +} + +static int +mv_twsi_attach(device_t dev) +{ + struct twsi_softc *sc; + phandle_t child, iicbusnode; + device_t childdev; + struct iicbus_ivar *devi; + char dname[32]; /* 32 is taken from struct u_device */ + uint32_t paddr; + int len, error, ret; + + sc = device_get_softc(dev); + + mv_twsi_cal_baud_rate(TWSI_BAUD_RATE_SLOW, &sc->baud_rate[IIC_SLOW]); + mv_twsi_cal_baud_rate(TWSI_BAUD_RATE_FAST, &sc->baud_rate[IIC_FAST]); + if (bootverbose) + device_printf(dev, "calculated baud rates are:\n" + " %" PRIu32 " kHz (M=%d, N=%d) for slow,\n" + " %" PRIu32 " kHz (M=%d, N=%d) for fast.\n", + sc->baud_rate[IIC_SLOW].raw / 1000, + sc->baud_rate[IIC_SLOW].m, + sc->baud_rate[IIC_SLOW].n, + sc->baud_rate[IIC_FAST].raw / 1000, + sc->baud_rate[IIC_FAST].m, + sc->baud_rate[IIC_FAST].n); + + + ret = twsi_attach(dev); + if (ret != 0) + return (ret); + + iicbusnode = 0; + /* Find iicbus as the child devices in the device tree. */ + for (child = OF_child(ofw_bus_get_node(dev)); child != 0; + child = OF_peer(child)) { + len = OF_getproplen(child, "model"); + if (len <= 0 || len > sizeof(dname)) + continue; + error = OF_getprop(child, "model", &dname, len); + if (error == -1) + continue; + len = strlen(dname); + if (len == strlen(IICBUS_DEVNAME) && + strncasecmp(dname, IICBUS_DEVNAME, len) == 0) { + iicbusnode = child; + break; + } + } + if (iicbusnode == 0) + goto attach_end; + + /* Attach child devices onto iicbus. */ + for (child = OF_child(iicbusnode); child != 0; child = OF_peer(child)) { + /* Get slave address. */ + error = OF_getprop(child, "i2c-address", &paddr, sizeof(paddr)); + if (error == -1) + error = OF_getprop(child, "reg", &paddr, sizeof(paddr)); + if (error == -1) + continue; + + /* Get device driver name. */ + len = OF_getproplen(child, "model"); + if (len <= 0 || len > sizeof(dname)) + continue; + OF_getprop(child, "model", &dname, len); + + if (bootverbose) + device_printf(dev, "adding a device %s at %d.\n", + dname, fdt32_to_cpu(paddr)); + childdev = BUS_ADD_CHILD(sc->iicbus, 0, dname, -1); + devi = IICBUS_IVAR(childdev); + devi->addr = fdt32_to_cpu(paddr); + } + +attach_end: + bus_generic_attach(sc->iicbus); + + return (0); +} Property changes on: head/sys/dev/iicbus/twsi/mv_twsi.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/sys/dev/iicbus/twsi/twsi.c =================================================================== --- head/sys/dev/iicbus/twsi/twsi.c (revision 295625) +++ head/sys/dev/iicbus/twsi/twsi.c (revision 295626) @@ -1,644 +1,482 @@ /*- * Copyright (C) 2008 MARVELL INTERNATIONAL LTD. * All rights reserved. * * Developed by Semihalf. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of MARVELL nor the names of contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Driver for the TWSI (aka I2C, aka IIC) bus controller found on Marvell - * SoCs. Supports master operation only, and works in polling mode. + * and Allwinner SoCs. Supports master operation only, and works in polling mode. * * Calls to DELAY() are needed per Application Note AN-179 "TWSI Software * Guidelines for Discovery(TM), Horizon (TM) and Feroceon(TM) Devices". */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include "iicbus_if.h" -#define MV_TWSI_NAME "twsi" -#define IICBUS_DEVNAME "iicbus" +#define TWSI_CONTROL_ACK (1 << 2) +#define TWSI_CONTROL_IFLG (1 << 3) +#define TWSI_CONTROL_STOP (1 << 4) +#define TWSI_CONTROL_START (1 << 5) +#define TWSI_CONTROL_TWSIEN (1 << 6) +#define TWSI_CONTROL_INTEN (1 << 7) -#define TWSI_SLAVE_ADDR 0x00 -#define TWSI_EXT_SLAVE_ADDR 0x10 -#define TWSI_DATA 0x04 +#define TWSI_STATUS_START 0x08 +#define TWSI_STATUS_RPTD_START 0x10 +#define TWSI_STATUS_ADDR_W_ACK 0x18 +#define TWSI_STATUS_DATA_WR_ACK 0x28 +#define TWSI_STATUS_ADDR_R_ACK 0x40 +#define TWSI_STATUS_DATA_RD_ACK 0x50 +#define TWSI_STATUS_DATA_RD_NOACK 0x58 -#define TWSI_CONTROL 0x08 -#define TWSI_CONTROL_ACK (1 << 2) -#define TWSI_CONTROL_IFLG (1 << 3) -#define TWSI_CONTROL_STOP (1 << 4) -#define TWSI_CONTROL_START (1 << 5) -#define TWSI_CONTROL_TWSIEN (1 << 6) -#define TWSI_CONTROL_INTEN (1 << 7) - -#define TWSI_STATUS 0x0c -#define TWSI_STATUS_START 0x08 -#define TWSI_STATUS_RPTD_START 0x10 -#define TWSI_STATUS_ADDR_W_ACK 0x18 -#define TWSI_STATUS_DATA_WR_ACK 0x28 -#define TWSI_STATUS_ADDR_R_ACK 0x40 -#define TWSI_STATUS_DATA_RD_ACK 0x50 -#define TWSI_STATUS_DATA_RD_NOACK 0x58 - -#define TWSI_BAUD_RATE 0x0c -#define TWSI_BAUD_RATE_PARAM(M,N) ((((M) << 3) | ((N) & 0x7)) & 0x7f) -#define TWSI_BAUD_RATE_RAW(C,M,N) ((C)/((10*(M+1))<<(N+1))) -#define TWSI_BAUD_RATE_SLOW 50000 /* 50kHz */ -#define TWSI_BAUD_RATE_FAST 100000 /* 100kHz */ - -#define TWSI_SOFT_RESET 0x1c - -#define TWSI_DEBUG +#define TWSI_DEBUG #undef TWSI_DEBUG -#ifdef TWSI_DEBUG -#define debugf(fmt, args...) do { printf("%s(): ", __func__); printf(fmt,##args); } while (0) +#ifdef TWSI_DEBUG +#define debugf(fmt, args...) do { printf("%s(): ", __func__); printf(fmt,##args); } while (0) #else -#define debugf(fmt, args...) +#define debugf(fmt, args...) #endif -struct mv_twsi_softc { - device_t dev; - struct resource *res[1]; /* SYS_RES_MEMORY */ - struct mtx mutex; - device_t iicbus; -}; - -static struct mv_twsi_baud_rate { - uint32_t raw; - int param; - int m; - int n; -} baud_rate[IIC_FASTEST + 1]; - -static int mv_twsi_probe(device_t); -static int mv_twsi_attach(device_t); -static int mv_twsi_detach(device_t); - -static int mv_twsi_reset(device_t dev, u_char speed, u_char addr, - u_char *oldaddr); -static int mv_twsi_repeated_start(device_t dev, u_char slave, int timeout); -static int mv_twsi_start(device_t dev, u_char slave, int timeout); -static int mv_twsi_stop(device_t dev); -static int mv_twsi_read(device_t dev, char *buf, int len, int *read, int last, - int delay); -static int mv_twsi_write(device_t dev, const char *buf, int len, int *sent, - int timeout); - static struct resource_spec res_spec[] = { { SYS_RES_MEMORY, 0, RF_ACTIVE }, { -1, 0 } }; -static struct ofw_compat_data compat_data[] = { - { "mrvl,twsi", true }, - { "marvell,mv64xxx-i2c", true }, - { NULL, false } -}; - -static device_method_t mv_twsi_methods[] = { - /* device interface */ - DEVMETHOD(device_probe, mv_twsi_probe), - DEVMETHOD(device_attach, mv_twsi_attach), - DEVMETHOD(device_detach, mv_twsi_detach), - - /* iicbus interface */ - DEVMETHOD(iicbus_callback, iicbus_null_callback), - DEVMETHOD(iicbus_repeated_start, mv_twsi_repeated_start), - DEVMETHOD(iicbus_start, mv_twsi_start), - DEVMETHOD(iicbus_stop, mv_twsi_stop), - DEVMETHOD(iicbus_write, mv_twsi_write), - DEVMETHOD(iicbus_read, mv_twsi_read), - DEVMETHOD(iicbus_reset, mv_twsi_reset), - DEVMETHOD(iicbus_transfer, iicbus_transfer_gen), - { 0, 0 } -}; - -static devclass_t mv_twsi_devclass; - -static driver_t mv_twsi_driver = { - MV_TWSI_NAME, - mv_twsi_methods, - sizeof(struct mv_twsi_softc), -}; - -DRIVER_MODULE(twsi, simplebus, mv_twsi_driver, mv_twsi_devclass, 0, 0); -DRIVER_MODULE(iicbus, twsi, iicbus_driver, iicbus_devclass, 0, 0); -MODULE_DEPEND(twsi, iicbus, 1, 1, 1); - static __inline uint32_t -TWSI_READ(struct mv_twsi_softc *sc, bus_size_t off) +TWSI_READ(struct twsi_softc *sc, bus_size_t off) { return (bus_read_4(sc->res[0], off)); } static __inline void -TWSI_WRITE(struct mv_twsi_softc *sc, bus_size_t off, uint32_t val) +TWSI_WRITE(struct twsi_softc *sc, bus_size_t off, uint32_t val) { bus_write_4(sc->res[0], off, val); } static __inline void -twsi_control_clear(struct mv_twsi_softc *sc, uint32_t mask) +twsi_control_clear(struct twsi_softc *sc, uint32_t mask) { uint32_t val; - val = TWSI_READ(sc, TWSI_CONTROL); + val = TWSI_READ(sc, sc->reg_control); val &= ~mask; - TWSI_WRITE(sc, TWSI_CONTROL, val); + TWSI_WRITE(sc, sc->reg_control, val); } static __inline void -twsi_control_set(struct mv_twsi_softc *sc, uint32_t mask) +twsi_control_set(struct twsi_softc *sc, uint32_t mask) { uint32_t val; - val = TWSI_READ(sc, TWSI_CONTROL); + val = TWSI_READ(sc, sc->reg_control); val |= mask; - TWSI_WRITE(sc, TWSI_CONTROL, val); + TWSI_WRITE(sc, sc->reg_control, val); } static __inline void -twsi_clear_iflg(struct mv_twsi_softc *sc) +twsi_clear_iflg(struct twsi_softc *sc) { DELAY(1000); twsi_control_clear(sc, TWSI_CONTROL_IFLG); DELAY(1000); } /* * timeout given in us * returns * 0 on sucessfull mask change * non-zero on timeout */ static int -twsi_poll_ctrl(struct mv_twsi_softc *sc, int timeout, uint32_t mask) +twsi_poll_ctrl(struct twsi_softc *sc, int timeout, uint32_t mask) { timeout /= 10; - while (!(TWSI_READ(sc, TWSI_CONTROL) & mask)) { + while (!(TWSI_READ(sc, sc->reg_control) & mask)) { DELAY(10); if (--timeout < 0) return (timeout); } return (0); } /* * 'timeout' is given in us. Note also that timeout handling is not exact -- * twsi_locked_start() total wait can be more than 2 x timeout * (twsi_poll_ctrl() is called twice). 'mask' can be either TWSI_STATUS_START * or TWSI_STATUS_RPTD_START */ static int -twsi_locked_start(device_t dev, struct mv_twsi_softc *sc, int32_t mask, +twsi_locked_start(device_t dev, struct twsi_softc *sc, int32_t mask, u_char slave, int timeout) { int read_access, iflg_set = 0; uint32_t status; mtx_assert(&sc->mutex, MA_OWNED); if (mask == TWSI_STATUS_RPTD_START) /* read IFLG to know if it should be cleared later; from NBSD */ - iflg_set = TWSI_READ(sc, TWSI_CONTROL) & TWSI_CONTROL_IFLG; + iflg_set = TWSI_READ(sc, sc->reg_control) & TWSI_CONTROL_IFLG; twsi_control_set(sc, TWSI_CONTROL_START); if (mask == TWSI_STATUS_RPTD_START && iflg_set) { debugf("IFLG set, clearing\n"); twsi_clear_iflg(sc); } /* * Without this delay we timeout checking IFLG if the timeout is 0. * NBSD driver always waits here too. */ DELAY(1000); if (twsi_poll_ctrl(sc, timeout, TWSI_CONTROL_IFLG)) { debugf("timeout sending %sSTART condition\n", mask == TWSI_STATUS_START ? "" : "repeated "); return (IIC_ETIMEOUT); } - status = TWSI_READ(sc, TWSI_STATUS); + status = TWSI_READ(sc, sc->reg_status); if (status != mask) { debugf("wrong status (%02x) after sending %sSTART condition\n", status, mask == TWSI_STATUS_START ? "" : "repeated "); return (IIC_ESTATUS); } - TWSI_WRITE(sc, TWSI_DATA, slave); + TWSI_WRITE(sc, sc->reg_data, slave); DELAY(1000); twsi_clear_iflg(sc); if (twsi_poll_ctrl(sc, timeout, TWSI_CONTROL_IFLG)) { debugf("timeout sending slave address\n"); return (IIC_ETIMEOUT); } read_access = (slave & 0x1) ? 1 : 0; - status = TWSI_READ(sc, TWSI_STATUS); + status = TWSI_READ(sc, sc->reg_status); if (status != (read_access ? TWSI_STATUS_ADDR_R_ACK : TWSI_STATUS_ADDR_W_ACK)) { debugf("no ACK (status: %02x) after sending slave address\n", status); return (IIC_ENOACK); } return (IIC_NOERR); } -static int -mv_twsi_probe(device_t dev) -{ - - if (!ofw_bus_status_okay(dev)) - return (ENXIO); - - if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) - return (ENXIO); - - device_set_desc(dev, "Marvell Integrated I2C Bus Controller"); - return (BUS_PROBE_DEFAULT); -} - -#define ABSSUB(a,b) (((a) > (b)) ? (a) - (b) : (b) - (a)) -static void -mv_twsi_cal_baud_rate(const uint32_t target, struct mv_twsi_baud_rate *rate) -{ - uint32_t clk, cur, diff, diff0; - int m, n, m0, n0; - - /* Calculate baud rate. */ - m0 = n0 = 4; /* Default values on reset */ - diff0 = 0xffffffff; - clk = get_tclk(); - - for (n = 0; n < 8; n++) { - for (m = 0; m < 16; m++) { - cur = TWSI_BAUD_RATE_RAW(clk,m,n); - diff = ABSSUB(target, cur); - if (diff < diff0) { - m0 = m; - n0 = n; - diff0 = diff; - } - } - } - rate->raw = TWSI_BAUD_RATE_RAW(clk, m0, n0); - rate->param = TWSI_BAUD_RATE_PARAM(m0, n0); - rate->m = m0; - rate->n = n0; -} - -static int -mv_twsi_attach(device_t dev) -{ - struct mv_twsi_softc *sc; - phandle_t child, iicbusnode; - device_t childdev; - struct iicbus_ivar *devi; - char dname[32]; /* 32 is taken from struct u_device */ - uint32_t paddr; - int len, error; - - sc = device_get_softc(dev); - sc->dev = dev; - bzero(baud_rate, sizeof(baud_rate)); - - mtx_init(&sc->mutex, device_get_nameunit(dev), MV_TWSI_NAME, MTX_DEF); - - /* Allocate IO resources */ - if (bus_alloc_resources(dev, res_spec, sc->res)) { - device_printf(dev, "could not allocate resources\n"); - mv_twsi_detach(dev); - return (ENXIO); - } - - mv_twsi_cal_baud_rate(TWSI_BAUD_RATE_SLOW, &baud_rate[IIC_SLOW]); - mv_twsi_cal_baud_rate(TWSI_BAUD_RATE_FAST, &baud_rate[IIC_FAST]); - if (bootverbose) - device_printf(dev, "calculated baud rates are:\n" - " %" PRIu32 " kHz (M=%d, N=%d) for slow,\n" - " %" PRIu32 " kHz (M=%d, N=%d) for fast.\n", - baud_rate[IIC_SLOW].raw / 1000, - baud_rate[IIC_SLOW].m, - baud_rate[IIC_SLOW].n, - baud_rate[IIC_FAST].raw / 1000, - baud_rate[IIC_FAST].m, - baud_rate[IIC_FAST].n); - - sc->iicbus = device_add_child(dev, IICBUS_DEVNAME, -1); - if (sc->iicbus == NULL) { - device_printf(dev, "could not add iicbus child\n"); - mv_twsi_detach(dev); - return (ENXIO); - } - /* Attach iicbus. */ - bus_generic_attach(dev); - - iicbusnode = 0; - /* Find iicbus as the child devices in the device tree. */ - for (child = OF_child(ofw_bus_get_node(dev)); child != 0; - child = OF_peer(child)) { - len = OF_getproplen(child, "model"); - if (len <= 0 || len > sizeof(dname)) - continue; - error = OF_getprop(child, "model", &dname, len); - if (error == -1) - continue; - len = strlen(dname); - if (len == strlen(IICBUS_DEVNAME) && - strncasecmp(dname, IICBUS_DEVNAME, len) == 0) { - iicbusnode = child; - break; - } - } - if (iicbusnode == 0) - goto attach_end; - - /* Attach child devices onto iicbus. */ - for (child = OF_child(iicbusnode); child != 0; child = OF_peer(child)) { - /* Get slave address. */ - error = OF_getprop(child, "i2c-address", &paddr, sizeof(paddr)); - if (error == -1) - error = OF_getprop(child, "reg", &paddr, sizeof(paddr)); - if (error == -1) - continue; - - /* Get device driver name. */ - len = OF_getproplen(child, "model"); - if (len <= 0 || len > sizeof(dname)) - continue; - OF_getprop(child, "model", &dname, len); - - if (bootverbose) - device_printf(dev, "adding a device %s at %d.\n", - dname, fdt32_to_cpu(paddr)); - childdev = BUS_ADD_CHILD(sc->iicbus, 0, dname, -1); - devi = IICBUS_IVAR(childdev); - devi->addr = fdt32_to_cpu(paddr); - } - -attach_end: - bus_generic_attach(sc->iicbus); - - return (0); -} - -static int -mv_twsi_detach(device_t dev) -{ - struct mv_twsi_softc *sc; - int rv; - - sc = device_get_softc(dev); - - if ((rv = bus_generic_detach(dev)) != 0) - return (rv); - - if (sc->iicbus != NULL) - if ((rv = device_delete_child(dev, sc->iicbus)) != 0) - return (rv); - - bus_release_resources(dev, res_spec, sc->res); - - mtx_destroy(&sc->mutex); - return (0); -} - /* * Only slave mode supported, disregard [old]addr */ static int -mv_twsi_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr) +twsi_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr) { - struct mv_twsi_softc *sc; + struct twsi_softc *sc; uint32_t param; sc = device_get_softc(dev); switch (speed) { case IIC_SLOW: case IIC_FAST: - param = baud_rate[speed].param; + param = sc->baud_rate[speed].param; break; case IIC_FASTEST: case IIC_UNKNOWN: default: - param = baud_rate[IIC_FAST].param; + param = sc->baud_rate[IIC_FAST].param; break; } mtx_lock(&sc->mutex); - TWSI_WRITE(sc, TWSI_SOFT_RESET, 0x0); + TWSI_WRITE(sc, sc->reg_soft_reset, 0x0); DELAY(2000); - TWSI_WRITE(sc, TWSI_BAUD_RATE, param); - TWSI_WRITE(sc, TWSI_CONTROL, TWSI_CONTROL_TWSIEN | TWSI_CONTROL_ACK); + TWSI_WRITE(sc, sc->reg_baud_rate, param); + TWSI_WRITE(sc, sc->reg_control, TWSI_CONTROL_TWSIEN | TWSI_CONTROL_ACK); DELAY(1000); mtx_unlock(&sc->mutex); return (0); } +static int +twsi_stop(device_t dev) +{ + struct twsi_softc *sc; + + sc = device_get_softc(dev); + + mtx_lock(&sc->mutex); + twsi_control_set(sc, TWSI_CONTROL_STOP); + DELAY(1000); + twsi_clear_iflg(sc); + mtx_unlock(&sc->mutex); + + return (IIC_NOERR); +} + /* * timeout is given in us */ static int -mv_twsi_repeated_start(device_t dev, u_char slave, int timeout) +twsi_repeated_start(device_t dev, u_char slave, int timeout) { - struct mv_twsi_softc *sc; + struct twsi_softc *sc; int rv; sc = device_get_softc(dev); mtx_lock(&sc->mutex); rv = twsi_locked_start(dev, sc, TWSI_STATUS_RPTD_START, slave, timeout); mtx_unlock(&sc->mutex); if (rv) { - mv_twsi_stop(dev); + twsi_stop(dev); return (rv); } else return (IIC_NOERR); } /* * timeout is given in us */ static int -mv_twsi_start(device_t dev, u_char slave, int timeout) +twsi_start(device_t dev, u_char slave, int timeout) { - struct mv_twsi_softc *sc; + struct twsi_softc *sc; int rv; sc = device_get_softc(dev); mtx_lock(&sc->mutex); rv = twsi_locked_start(dev, sc, TWSI_STATUS_START, slave, timeout); mtx_unlock(&sc->mutex); if (rv) { - mv_twsi_stop(dev); + twsi_stop(dev); return (rv); } else return (IIC_NOERR); } static int -mv_twsi_stop(device_t dev) +twsi_read(device_t dev, char *buf, int len, int *read, int last, int delay) { - struct mv_twsi_softc *sc; - - sc = device_get_softc(dev); - - mtx_lock(&sc->mutex); - twsi_control_set(sc, TWSI_CONTROL_STOP); - DELAY(1000); - twsi_clear_iflg(sc); - mtx_unlock(&sc->mutex); - - return (IIC_NOERR); -} - -static int -mv_twsi_read(device_t dev, char *buf, int len, int *read, int last, int delay) -{ - struct mv_twsi_softc *sc; + struct twsi_softc *sc; uint32_t status; int last_byte, rv; sc = device_get_softc(dev); mtx_lock(&sc->mutex); *read = 0; while (*read < len) { /* * Check if we are reading last byte of the last buffer, * do not send ACK then, per I2C specs */ last_byte = ((*read == len - 1) && last) ? 1 : 0; if (last_byte) twsi_control_clear(sc, TWSI_CONTROL_ACK); else twsi_control_set(sc, TWSI_CONTROL_ACK); DELAY (1000); twsi_clear_iflg(sc); if (twsi_poll_ctrl(sc, delay, TWSI_CONTROL_IFLG)) { debugf("timeout reading data\n"); rv = IIC_ETIMEOUT; goto out; } - status = TWSI_READ(sc, TWSI_STATUS); + status = TWSI_READ(sc, sc->reg_status); if (status != (last_byte ? TWSI_STATUS_DATA_RD_NOACK : TWSI_STATUS_DATA_RD_ACK)) { debugf("wrong status (%02x) while reading\n", status); rv = IIC_ESTATUS; goto out; } - *buf++ = TWSI_READ(sc, TWSI_DATA); + *buf++ = TWSI_READ(sc, sc->reg_data); (*read)++; } rv = IIC_NOERR; out: mtx_unlock(&sc->mutex); return (rv); } static int -mv_twsi_write(device_t dev, const char *buf, int len, int *sent, int timeout) +twsi_write(device_t dev, const char *buf, int len, int *sent, int timeout) { - struct mv_twsi_softc *sc; + struct twsi_softc *sc; uint32_t status; int rv; sc = device_get_softc(dev); mtx_lock(&sc->mutex); *sent = 0; while (*sent < len) { - TWSI_WRITE(sc, TWSI_DATA, *buf++); + TWSI_WRITE(sc, sc->reg_data, *buf++); twsi_clear_iflg(sc); if (twsi_poll_ctrl(sc, timeout, TWSI_CONTROL_IFLG)) { debugf("timeout writing data\n"); rv = IIC_ETIMEOUT; goto out; } - status = TWSI_READ(sc, TWSI_STATUS); + status = TWSI_READ(sc, sc->reg_status); if (status != TWSI_STATUS_DATA_WR_ACK) { debugf("wrong status (%02x) while writing\n", status); rv = IIC_ESTATUS; goto out; } (*sent)++; } rv = IIC_NOERR; out: mtx_unlock(&sc->mutex); return (rv); } + +int +twsi_attach(device_t dev) +{ + struct twsi_softc *sc; + + sc = device_get_softc(dev); + sc->dev = dev; + + mtx_init(&sc->mutex, device_get_nameunit(dev), "twsi", MTX_DEF); + + if (bus_alloc_resources(dev, res_spec, sc->res)) { + device_printf(dev, "could not allocate resources\n"); + twsi_detach(dev); + return (ENXIO); + } + + /* Attach the iicbus. */ + if ((sc->iicbus = device_add_child(dev, "iicbus", -1)) == NULL) { + device_printf(dev, "could not allocate iicbus instance\n"); + twsi_detach(dev); + return (ENXIO); + } + bus_generic_attach(dev); + + return (0); +} + +int +twsi_detach(device_t dev) +{ + struct twsi_softc *sc; + int rv; + + sc = device_get_softc(dev); + + if ((rv = bus_generic_detach(dev)) != 0) + return (rv); + + if (sc->iicbus != NULL) + if ((rv = device_delete_child(dev, sc->iicbus)) != 0) + return (rv); + + bus_release_resources(dev, res_spec, sc->res); + + mtx_destroy(&sc->mutex); + return (0); +} + +static device_method_t twsi_methods[] = { + /* device interface */ + DEVMETHOD(device_detach, twsi_detach), + + /* Bus interface */ + DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), + DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), + DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), + DEVMETHOD(bus_release_resource, bus_generic_release_resource), + DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), + DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), + DEVMETHOD(bus_adjust_resource, bus_generic_adjust_resource), + DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource), + DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), + + /* iicbus interface */ + DEVMETHOD(iicbus_callback, iicbus_null_callback), + DEVMETHOD(iicbus_repeated_start, twsi_repeated_start), + DEVMETHOD(iicbus_start, twsi_start), + DEVMETHOD(iicbus_stop, twsi_stop), + DEVMETHOD(iicbus_write, twsi_write), + DEVMETHOD(iicbus_read, twsi_read), + DEVMETHOD(iicbus_reset, twsi_reset), + DEVMETHOD(iicbus_transfer, iicbus_transfer_gen), + { 0, 0 } +}; + +DEFINE_CLASS_0(twsi, twsi_driver, twsi_methods, + sizeof(struct twsi_softc)); Index: head/sys/dev/iicbus/twsi/twsi.h =================================================================== --- head/sys/dev/iicbus/twsi/twsi.h (nonexistent) +++ head/sys/dev/iicbus/twsi/twsi.h (revision 295626) @@ -0,0 +1,67 @@ +/*- + * Copyright (C) 2008 MARVELL INTERNATIONAL LTD. + * All rights reserved. + * + * Developed by Semihalf. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of MARVELL nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _TWSI_H_ +#define _TWSI_H_ + +struct twsi_baud_rate { + uint32_t raw; + int param; + int m; + int n; +}; + +struct twsi_softc { + device_t dev; + struct resource *res[1]; /* SYS_RES_MEMORY */ + struct mtx mutex; + device_t iicbus; + + bus_size_t reg_data; + bus_size_t reg_slave_addr; + bus_size_t reg_slave_ext_addr; + bus_size_t reg_control; + bus_size_t reg_status; + bus_size_t reg_baud_rate; + bus_size_t reg_soft_reset; + struct twsi_baud_rate baud_rate[IIC_FASTEST + 1]; +}; + +DECLARE_CLASS(twsi_driver); + +#define TWSI_BAUD_RATE_PARAM(M,N) ((((M) << 3) | ((N) & 0x7)) & 0x7f) + +int twsi_attach(device_t); +int twsi_detach(device_t); + +#endif /* _TWSI_H_ */ Property changes on: head/sys/dev/iicbus/twsi/twsi.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property