Module Name: src Committed By: jmcneill Date: Thu Nov 30 20:41:21 UTC 2017
Modified Files: src/sys/arch/arm/sunxi: sunxi_twi.c Log Message: Set twi clock based on parent clock, and fix register remapping for writes. To generate a diff of this commit: cvs rdiff -u -r1.6 -r1.7 src/sys/arch/arm/sunxi/sunxi_twi.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/arm/sunxi/sunxi_twi.c diff -u src/sys/arch/arm/sunxi/sunxi_twi.c:1.6 src/sys/arch/arm/sunxi/sunxi_twi.c:1.7 --- src/sys/arch/arm/sunxi/sunxi_twi.c:1.6 Sun Oct 29 15:00:00 2017 +++ src/sys/arch/arm/sunxi/sunxi_twi.c Thu Nov 30 20:41:21 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: sunxi_twi.c,v 1.6 2017/10/29 15:00:00 jmcneill Exp $ */ +/* $NetBSD: sunxi_twi.c,v 1.7 2017/11/30 20:41:21 jmcneill Exp $ */ /*- * Copyright (c) 2017 Jared McNeill <jmcne...@invisible.ca> @@ -33,7 +33,7 @@ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: sunxi_twi.c,v 1.6 2017/10/29 15:00:00 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sunxi_twi.c,v 1.7 2017/11/30 20:41:21 jmcneill Exp $"); #include <sys/param.h> #include <sys/bus.h> @@ -52,14 +52,22 @@ __KERNEL_RCSID(0, "$NetBSD: sunxi_twi.c, #define TWI_CCR_CLK_M __BITS(6,3) #define TWI_CCR_CLK_N __BITS(2,0) -static uint8_t sunxi_twi_regmap[] = { - [TWSI_SLAVEADDR] = 0x00, - [TWSI_EXTEND_SLAVEADDR] = 0x04, - [TWSI_DATA] = 0x08, - [TWSI_CONTROL] = 0x0c, - [TWSI_STATUS] = 0x10, - [TWSI_BAUDRATE] = 0x14, - [TWSI_SOFTRESET] = 0x18, +static uint8_t sunxi_twi_regmap_rd[] = { + [TWSI_SLAVEADDR/4] = 0x00, + [TWSI_EXTEND_SLAVEADDR/4] = 0x04, + [TWSI_DATA/4] = 0x08, + [TWSI_CONTROL/4] = 0x0c, + [TWSI_STATUS/4] = 0x10, + [TWSI_SOFTRESET/4] = 0x18, +}; + +static uint8_t sunxi_twi_regmap_wr[] = { + [TWSI_SLAVEADDR/4] = 0x00, + [TWSI_EXTEND_SLAVEADDR/4] = 0x04, + [TWSI_DATA/4] = 0x08, + [TWSI_CONTROL/4] = 0x0c, + [TWSI_BAUDRATE/4] = 0x14, + [TWSI_SOFTRESET/4] = 0x18, }; static int sunxi_twi_match(device_t, cfdata_t, void *); @@ -101,13 +109,42 @@ const struct fdtbus_i2c_controller_func static uint32_t sunxi_twi_reg_read(struct gttwsi_softc *sc, uint32_t reg) { - return bus_space_read_4(sc->sc_bust, sc->sc_bush, sunxi_twi_regmap[reg]); + return bus_space_read_4(sc->sc_bust, sc->sc_bush, sunxi_twi_regmap_rd[reg/4]); } static void sunxi_twi_reg_write(struct gttwsi_softc *sc, uint32_t reg, uint32_t val) { - bus_space_write_4(sc->sc_bust, sc->sc_bush, sunxi_twi_regmap[reg], val); + bus_space_write_4(sc->sc_bust, sc->sc_bush, sunxi_twi_regmap_wr[reg/4], val); +} + +static u_int +sunxi_twi_calc_rate(u_int parent_rate, u_int n, u_int m) +{ + return parent_rate / (10 * (m + 1) * (1 << n)); +} + +static void +sunxi_twi_set_clock(struct gttwsi_softc *sc, u_int parent_rate, u_int rate) +{ + uint32_t baud; + u_int n, m, best_rate; + + baud = sunxi_twi_reg_read(sc, TWSI_BAUDRATE); + + for (best_rate = 0, n = 0; n < 8; n++) { + for (m = 0; m < 16; m++) { + const u_int tmp_rate = sunxi_twi_calc_rate(parent_rate, n, m); + if (tmp_rate <= rate && tmp_rate > best_rate) { + best_rate = tmp_rate; + baud = __SHIFTIN(n, TWI_CCR_CLK_N) | + __SHIFTIN(m, TWI_CCR_CLK_M); + } + } + } + + sunxi_twi_reg_write(sc, TWSI_BAUDRATE, baud); + delay(10000); } static int @@ -152,11 +189,11 @@ sunxi_twi_attach(device_t parent, device return; } - if ((clk = fdtbus_clock_get_index(phandle, 0)) != NULL) - if (clk_enable(clk) != 0) { - aprint_error(": couldn't enable clock\n"); - return; - } + clk = fdtbus_clock_get_index(phandle, 0); + if (clk == NULL || clk_enable(clk) != 0) { + aprint_error(": couldn't enable clock\n"); + return; + } if ((rst = fdtbus_reset_get_index(phandle, 0)) != NULL) if (fdtbus_reset_deassert(rst) != 0) { aprint_error(": couldn't de-assert reset\n"); @@ -167,21 +204,16 @@ sunxi_twi_attach(device_t parent, device prop_dictionary_set_bool(device_properties(self), "iflg-rwc", conf->iflg_rwc); - /* - * Set clock rate to 100kHz. From the datasheet: - * For 100Khz standard speed 2Wire, CLK_N=2, CLK_M=11 - * F0=48M/2^2=12Mhz, F1=F0/(10*(11+1)) = 0.1Mhz - */ - const u_int m = 11, n = 2; - const uint32_t ccr = __SHIFTIN(n, TWI_CCR_CLK_N) | - __SHIFTIN(m, TWI_CCR_CLK_M); - bus_space_write_4(bst, bsh, TWI_CCR_REG, ccr); - + /* Attach gttwsi core */ sc->sc_reg_read = sunxi_twi_reg_read; sc->sc_reg_write = sunxi_twi_reg_write; - gttwsi_attach_subr(self, bst, bsh); + /* + * Set clock rate to 100kHz. + */ + sunxi_twi_set_clock(sc, clk_get_rate(clk), 100000); + ih = fdtbus_intr_establish(phandle, 0, IPL_VM, 0, gttwsi_intr, sc); if (ih == NULL) { aprint_error_dev(self, "couldn't establish interrupt on %s\n",