Home | History | Annotate | Line # | Download | only in amlogic
meson_i2c.c revision 1.5
      1  1.5  thorpej /* $NetBSD: meson_i2c.c,v 1.5 2025/09/16 11:55:16 thorpej Exp $ */
      2  1.1      rjs 
      3  1.1      rjs /*-
      4  1.1      rjs  * Copyright (c) 2025 The NetBSD Foundation, Inc.
      5  1.1      rjs  * All rights reserved.
      6  1.1      rjs  *
      7  1.1      rjs  * Written by Vincent Defert for The NetBSD Foundation, Inc.
      8  1.1      rjs  *
      9  1.1      rjs  * Redistribution and use in source and binary forms, with or without
     10  1.1      rjs  * modification, are permitted provided that the following conditions
     11  1.1      rjs  * are met:
     12  1.1      rjs  * 1. Redistributions of source code must retain the above copyright
     13  1.1      rjs  *    notice, this list of conditions and the following disclaimer.
     14  1.1      rjs  * 2. Redistributions in binary form must reproduce the above copyright
     15  1.1      rjs  *    notice, this list of conditions and the following disclaimer in the
     16  1.1      rjs  *    documentation and/or other materials provided with the distribution.
     17  1.1      rjs  *
     18  1.1      rjs  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     19  1.1      rjs  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     20  1.1      rjs  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     21  1.1      rjs  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     22  1.1      rjs  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     23  1.1      rjs  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     24  1.1      rjs  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     25  1.1      rjs  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     26  1.1      rjs  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     27  1.1      rjs  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     28  1.1      rjs  * POSSIBILITY OF SUCH DAMAGE.
     29  1.1      rjs  */
     30  1.1      rjs 
     31  1.1      rjs #include <sys/cdefs.h>
     32  1.5  thorpej __KERNEL_RCSID(1, "$NetBSD: meson_i2c.c,v 1.5 2025/09/16 11:55:16 thorpej Exp $");
     33  1.1      rjs 
     34  1.1      rjs #include <sys/param.h>
     35  1.1      rjs #include <sys/bus.h>
     36  1.1      rjs #include <sys/device.h>
     37  1.1      rjs #include <sys/intr.h>
     38  1.1      rjs #include <sys/systm.h>
     39  1.1      rjs #include <sys/time.h>
     40  1.1      rjs #include <sys/kmem.h>
     41  1.1      rjs #include <sys/mutex.h>
     42  1.1      rjs #include <sys/condvar.h>
     43  1.1      rjs #include <dev/i2c/i2cvar.h>
     44  1.1      rjs #include <dev/fdt/fdtvar.h>
     45  1.1      rjs 
     46  1.1      rjs #define MESONI2C_CTRL_REG		0x00
     47  1.1      rjs #define MESONI2C_CTRL_START		__BIT(0)
     48  1.1      rjs #define MESONI2C_CTRL_ACK_IGNORE	__BIT(1)
     49  1.1      rjs #define MESONI2C_CTRL_STATUS		__BIT(2)
     50  1.1      rjs #define MESONI2C_CTRL_ERROR		__BIT(3)
     51  1.1      rjs #define MESONI2C_CTRL_READ_DATA_SHIFT	8
     52  1.1      rjs #define MESONI2C_CTRL_READ_DATA_MASK	__BITS(11, MESONI2C_CTRL_READ_DATA_SHIFT)
     53  1.1      rjs #define MESONI2C_CTRL_CLKDIV_SHIFT	12
     54  1.1      rjs #define MESONI2C_CTRL_CLKDIV_MASK	__BITS(21, MESONI2C_CTRL_CLKDIV_SHIFT)
     55  1.1      rjs #define MESONI2C_CTRL_CLKDIVEXT_SHIFT	28
     56  1.1      rjs #define MESONI2C_CTRL_CLKDIVEXT_MASK	__BITS(29, MESONI2C_CTRL_CLKDIVEXT_SHIFT)
     57  1.1      rjs 
     58  1.1      rjs #define MESONI2C_SLAVE_ADDR_REG		0x04
     59  1.1      rjs #define MESONI2C_SLAVE_ADDR_MASK	__BITS(7, 0)
     60  1.1      rjs #define MESONI2C_SLAVE_SDA_FILTER_MASK	__BITS(10, 8)
     61  1.1      rjs #define MESONI2C_SLAVE_SCL_FILTER_MASK	__BITS(13, 11)
     62  1.1      rjs #define MESONI2C_SLAVE_SCL_LOW_SHIFT	16
     63  1.1      rjs #define MESONI2C_SLAVE_SCL_LOW_MASK	__BITS(27, MESONI2C_SLAVE_SCL_LOW_SHIFT)
     64  1.1      rjs #define MESONI2C_SLAVE_SCL_LOW_EN	__BIT(28)
     65  1.1      rjs 
     66  1.1      rjs #define MESONI2C_TOKEN_LIST_REG0	0x08
     67  1.1      rjs #define MESONI2C_TOKEN_LIST_REG1	0x0c
     68  1.1      rjs #define MESONI2C_TOKEN_WDATA_REG0	0x10
     69  1.1      rjs #define MESONI2C_TOKEN_WDATA_REG1	0x14
     70  1.1      rjs #define MESONI2C_TOKEN_RDATA_REG0	0x18
     71  1.1      rjs #define MESONI2C_TOKEN_RDATA_REG1	0x1c
     72  1.1      rjs 
     73  1.1      rjs #define MESONI2C_TOKEN_BITS		4
     74  1.1      rjs #define MESONI2C_TOKEN_MASK		((1 << MESONI2C_TOKEN_BITS) - 1)
     75  1.1      rjs #define MESONI2C_TOKEN_REG_HALF		(32 / MESONI2C_TOKEN_BITS)
     76  1.1      rjs #define MESONI2C_TOKEN_REG_FULL		(64 / MESONI2C_TOKEN_BITS)
     77  1.1      rjs 
     78  1.1      rjs #define MESONI2C_DATA_BITS		8
     79  1.1      rjs #define MESONI2C_DATA_MASK		((1 << MESONI2C_DATA_BITS) - 1)
     80  1.1      rjs #define MESONI2C_DATA_REG_HALF		(32 / MESONI2C_DATA_BITS)
     81  1.1      rjs #define MESONI2C_DATA_REG_FULL		(64 / MESONI2C_DATA_BITS)
     82  1.1      rjs 
     83  1.1      rjs #define I2C_TIMEOUT_MS			1000
     84  1.1      rjs #define FILTER_DELAY			15
     85  1.1      rjs 
     86  1.1      rjs enum mesoni2c_token {
     87  1.1      rjs 	TOKEN_END = 0,
     88  1.1      rjs 	TOKEN_START,
     89  1.1      rjs 	TOKEN_SLAVE_ADDR_WRITE,
     90  1.1      rjs 	TOKEN_SLAVE_ADDR_READ,
     91  1.1      rjs 	TOKEN_DATA,
     92  1.1      rjs 	TOKEN_DATA_LAST,
     93  1.1      rjs 	TOKEN_STOP,
     94  1.1      rjs };
     95  1.1      rjs 
     96  1.1      rjs enum mesoni2c_type {
     97  1.1      rjs 	TYPE_MESON6,
     98  1.1      rjs 	TYPE_GXBB,
     99  1.1      rjs 	TYPE_AXG,
    100  1.1      rjs };
    101  1.1      rjs 
    102  1.1      rjs struct mesoni2c_softc {
    103  1.1      rjs 	device_t		sc_dev;
    104  1.1      rjs 	bus_space_tag_t		sc_bst;
    105  1.1      rjs 	bus_space_handle_t	sc_bsh;
    106  1.1      rjs 	struct clk		*sc_clk;
    107  1.1      rjs 	u_int			sc_clkfreq;
    108  1.1      rjs 	struct i2c_controller	sc_ic;
    109  1.1      rjs 	kcondvar_t		sc_cv;
    110  1.1      rjs 	kmutex_t		sc_mtx;
    111  1.1      rjs 	void			*sc_ih;
    112  1.1      rjs 
    113  1.1      rjs 	u_int			sc_token_index;
    114  1.1      rjs 	u_int			sc_wdata_index;
    115  1.1      rjs 	u_int			sc_rdata_index;
    116  1.1      rjs 
    117  1.1      rjs 	const uint8_t		*sc_cmdbuf;
    118  1.1      rjs 	size_t			sc_cmdlen;
    119  1.1      rjs 	uint8_t			*sc_databuf;
    120  1.1      rjs 	size_t			sc_datalen;
    121  1.1      rjs 	i2c_op_t		sc_op;
    122  1.1      rjs 
    123  1.1      rjs 	size_t			sc_curlen;
    124  1.1      rjs 	i2c_op_t		sc_curop;
    125  1.1      rjs 	int			sc_sendingCmd;
    126  1.1      rjs 	int			sc_error;
    127  1.1      rjs };
    128  1.1      rjs 
    129  1.1      rjs static void mesoni2c_set_mask(struct mesoni2c_softc *sc, bus_size_t reg, uint32_t mask, uint32_t value);
    130  1.1      rjs static void mesoni2c_reset_state(struct mesoni2c_softc *sc);
    131  1.1      rjs static int mesoni2c_push_token(struct mesoni2c_softc *sc, enum mesoni2c_token token);
    132  1.1      rjs static void mesoni2c_write_byte(struct mesoni2c_softc *sc, uint8_t data);
    133  1.1      rjs static uint8_t mesoni2c_get_byte(struct mesoni2c_softc *sc);
    134  1.1      rjs static void mesoni2c_prepare_xfer(struct mesoni2c_softc *sc, i2c_op_t op);
    135  1.1      rjs static void mesoni2c_partial_xfer(struct mesoni2c_softc *sc);
    136  1.1      rjs static int mesoni2c_exec(void *priv, i2c_op_t op, i2c_addr_t addr, const void *cmdbuf, size_t cmdlen, void *buf, size_t buflen, int flags);
    137  1.1      rjs static int mesoni2c_intr(void *arg);
    138  1.1      rjs static void mesoni2c_set_clock_div_meson6(struct mesoni2c_softc *sc);
    139  1.1      rjs static void mesoni2c_set_clock_div_gxbb_axg(struct mesoni2c_softc *sc);
    140  1.1      rjs static int mesoni2c_match(device_t parent, cfdata_t cf, void *aux);
    141  1.1      rjs static void mesoni2c_attach(device_t parent, device_t self, void *aux);
    142  1.1      rjs 
    143  1.1      rjs CFATTACH_DECL_NEW(meson_i2c, sizeof(struct mesoni2c_softc),
    144  1.1      rjs     mesoni2c_match, mesoni2c_attach, NULL, NULL);
    145  1.1      rjs 
    146  1.1      rjs static const struct device_compatible_entry compat_data[] = {
    147  1.1      rjs 	{ .compat = "amlogic,meson6-i2c",	.value = TYPE_MESON6 },
    148  1.1      rjs 	{ .compat = "amlogic,meson-gxbb-i2c",	.value = TYPE_GXBB },
    149  1.1      rjs 	{ .compat = "amlogic,meson-axg-i2c",	.value = TYPE_AXG },
    150  1.1      rjs 	DEVICE_COMPAT_EOL
    151  1.1      rjs };
    152  1.1      rjs 
    153  1.1      rjs #define	RD4(sc, reg)		\
    154  1.1      rjs 	bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
    155  1.1      rjs 
    156  1.1      rjs #define	WR4(sc, reg, val)	\
    157  1.1      rjs 	bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
    158  1.1      rjs 
    159  1.1      rjs static void
    160  1.1      rjs mesoni2c_set_mask(struct mesoni2c_softc *sc, bus_size_t reg, uint32_t mask,
    161  1.1      rjs 	uint32_t value)
    162  1.1      rjs {
    163  1.1      rjs 	uint32_t data = RD4(sc, reg);
    164  1.1      rjs 	data &= ~mask;
    165  1.1      rjs 	data |= value & mask;
    166  1.1      rjs 	WR4(sc, reg, data);
    167  1.1      rjs }
    168  1.1      rjs 
    169  1.1      rjs static void
    170  1.1      rjs mesoni2c_reset_state(struct mesoni2c_softc *sc)
    171  1.1      rjs {
    172  1.1      rjs 	sc->sc_token_index = 0;
    173  1.1      rjs 	sc->sc_wdata_index = 0;
    174  1.1      rjs 	sc->sc_rdata_index = 0;
    175  1.1      rjs }
    176  1.1      rjs 
    177  1.1      rjs static int
    178  1.1      rjs mesoni2c_push_token(struct mesoni2c_softc *sc, enum mesoni2c_token token)
    179  1.1      rjs {
    180  1.1      rjs 	bus_size_t reg;
    181  1.1      rjs 	u_int pos;
    182  1.1      rjs 
    183  1.1      rjs 	if (sc->sc_token_index >= MESONI2C_TOKEN_REG_HALF) {
    184  1.1      rjs 		reg = MESONI2C_TOKEN_LIST_REG1;
    185  1.1      rjs 		pos = sc->sc_token_index - MESONI2C_TOKEN_REG_HALF;
    186  1.1      rjs 	} else {
    187  1.1      rjs 		reg = MESONI2C_TOKEN_LIST_REG0;
    188  1.1      rjs 		pos = sc->sc_token_index;
    189  1.1      rjs 	}
    190  1.1      rjs 
    191  1.1      rjs 	sc->sc_token_index++;
    192  1.1      rjs 	pos *= MESONI2C_TOKEN_BITS;
    193  1.1      rjs 	mesoni2c_set_mask(sc, reg, MESONI2C_TOKEN_MASK << pos, token << pos);
    194  1.1      rjs 
    195  1.1      rjs 	return sc->sc_token_index == MESONI2C_TOKEN_REG_FULL;
    196  1.1      rjs }
    197  1.1      rjs 
    198  1.1      rjs static void
    199  1.1      rjs mesoni2c_write_byte(struct mesoni2c_softc *sc, uint8_t data)
    200  1.1      rjs {
    201  1.1      rjs 	bus_size_t reg;
    202  1.1      rjs 	u_int pos;
    203  1.1      rjs 
    204  1.1      rjs 	if (sc->sc_wdata_index >= MESONI2C_DATA_REG_HALF) {
    205  1.1      rjs 		reg = MESONI2C_TOKEN_WDATA_REG1;
    206  1.1      rjs 		pos = sc->sc_wdata_index - MESONI2C_DATA_REG_HALF;
    207  1.1      rjs 	} else {
    208  1.1      rjs 		reg = MESONI2C_TOKEN_WDATA_REG0;
    209  1.1      rjs 		pos = sc->sc_wdata_index;
    210  1.1      rjs 	}
    211  1.1      rjs 
    212  1.1      rjs 	sc->sc_wdata_index++;
    213  1.1      rjs 	pos *= MESONI2C_DATA_BITS;
    214  1.1      rjs 	mesoni2c_set_mask(sc, reg, MESONI2C_DATA_MASK << pos, ((uint32_t) data) << pos);
    215  1.1      rjs 	mesoni2c_push_token(sc, TOKEN_DATA);
    216  1.1      rjs }
    217  1.1      rjs 
    218  1.1      rjs static uint8_t
    219  1.1      rjs mesoni2c_get_byte(struct mesoni2c_softc *sc)
    220  1.1      rjs {
    221  1.1      rjs 	bus_size_t reg;
    222  1.1      rjs 	u_int pos;
    223  1.1      rjs 
    224  1.1      rjs 	if (sc->sc_rdata_index >= MESONI2C_DATA_REG_HALF) {
    225  1.1      rjs 		reg = MESONI2C_TOKEN_RDATA_REG1;
    226  1.1      rjs 		pos = sc->sc_rdata_index - MESONI2C_DATA_REG_HALF;
    227  1.1      rjs 	} else {
    228  1.1      rjs 		reg = MESONI2C_TOKEN_RDATA_REG0;
    229  1.1      rjs 		pos = sc->sc_rdata_index;
    230  1.1      rjs 	}
    231  1.1      rjs 
    232  1.1      rjs 	sc->sc_rdata_index++;
    233  1.1      rjs 	pos *= MESONI2C_DATA_BITS;
    234  1.1      rjs 
    235  1.1      rjs 	return (RD4(sc, reg) >> pos) & MESONI2C_DATA_MASK;
    236  1.1      rjs }
    237  1.1      rjs 
    238  1.1      rjs static void
    239  1.1      rjs mesoni2c_prepare_xfer(struct mesoni2c_softc *sc, i2c_op_t op)
    240  1.1      rjs {
    241  1.1      rjs 	mesoni2c_reset_state(sc);
    242  1.1      rjs 	mesoni2c_push_token(sc, TOKEN_START);
    243  1.1      rjs 	mesoni2c_push_token(sc, I2C_OP_WRITE_P(op) ? TOKEN_SLAVE_ADDR_WRITE : TOKEN_SLAVE_ADDR_READ);
    244  1.1      rjs }
    245  1.1      rjs 
    246  1.1      rjs static void
    247  1.1      rjs mesoni2c_partial_xfer(struct mesoni2c_softc *sc)
    248  1.1      rjs {
    249  1.1      rjs 	int dataBufferFree = MESONI2C_DATA_REG_FULL;
    250  1.1      rjs 
    251  1.1      rjs 	while (sc->sc_curlen && dataBufferFree) {
    252  1.1      rjs 		sc->sc_curlen--;
    253  1.1      rjs 		dataBufferFree--;
    254  1.1      rjs 
    255  1.1      rjs 		if (I2C_OP_WRITE_P(sc->sc_curop)) {
    256  1.1      rjs 			if (sc->sc_sendingCmd) {
    257  1.1      rjs 				uint8_t c = *(sc->sc_cmdbuf++);
    258  1.1      rjs 				mesoni2c_write_byte(sc, c);
    259  1.1      rjs 			} else {
    260  1.1      rjs 				mesoni2c_write_byte(sc, *(sc->sc_databuf++));
    261  1.1      rjs 			}
    262  1.1      rjs 		} else {
    263  1.1      rjs 			mesoni2c_push_token(sc, sc->sc_curlen ? TOKEN_DATA : TOKEN_DATA_LAST);
    264  1.1      rjs 		}
    265  1.1      rjs 	}
    266  1.1      rjs 
    267  1.1      rjs 	if (sc->sc_curlen == 0 && I2C_OP_STOP_P(sc->sc_curop)) {
    268  1.1      rjs 		mesoni2c_push_token(sc, TOKEN_STOP);
    269  1.1      rjs 	}
    270  1.1      rjs 
    271  1.1      rjs 	mesoni2c_push_token(sc, TOKEN_END);
    272  1.1      rjs 
    273  1.1      rjs 	mesoni2c_set_mask(sc, MESONI2C_CTRL_REG, MESONI2C_CTRL_START, 0);
    274  1.1      rjs 	mesoni2c_set_mask(sc, MESONI2C_CTRL_REG, MESONI2C_CTRL_START, 1);
    275  1.1      rjs }
    276  1.1      rjs 
    277  1.1      rjs static int
    278  1.1      rjs mesoni2c_exec(void *priv, i2c_op_t op, i2c_addr_t addr, const void *cmdbuf,
    279  1.1      rjs 	size_t cmdlen, void *databuf, size_t datalen, int flags)
    280  1.1      rjs {
    281  1.1      rjs 	struct mesoni2c_softc * const sc = priv;
    282  1.1      rjs 
    283  1.1      rjs 	mutex_enter(&sc->sc_mtx);
    284  1.1      rjs 
    285  1.1      rjs 	sc->sc_cmdbuf = cmdbuf;
    286  1.1      rjs 	sc->sc_cmdlen = cmdlen;
    287  1.1      rjs 	sc->sc_databuf = databuf;
    288  1.1      rjs 	sc->sc_datalen = datalen;
    289  1.1      rjs 	sc->sc_op = op;
    290  1.1      rjs 	sc->sc_error = 0;
    291  1.1      rjs 
    292  1.1      rjs 	mesoni2c_set_mask(sc, MESONI2C_SLAVE_ADDR_REG, MESONI2C_SLAVE_ADDR_MASK, addr << 1);
    293  1.2    skrll 
    294  1.1      rjs 	if (cmdlen) {
    295  1.1      rjs 		sc->sc_curlen = cmdlen;
    296  1.1      rjs 		sc->sc_curop = datalen ? I2C_OP_WRITE : op;
    297  1.1      rjs 		sc->sc_sendingCmd = 1;
    298  1.1      rjs 	} else {
    299  1.1      rjs 		sc->sc_curlen = datalen;
    300  1.1      rjs 		sc->sc_curop = op;
    301  1.1      rjs 		sc->sc_sendingCmd = 0;
    302  1.1      rjs 	}
    303  1.1      rjs 
    304  1.1      rjs 	mesoni2c_prepare_xfer(sc, sc->sc_curop);
    305  1.1      rjs 	mesoni2c_partial_xfer(sc);
    306  1.1      rjs 
    307  1.1      rjs 	if (cv_timedwait(&sc->sc_cv, &sc->sc_mtx, mstohz(I2C_TIMEOUT_MS)) == EWOULDBLOCK) {
    308  1.1      rjs 		sc->sc_error = EIO;
    309  1.1      rjs 	}
    310  1.1      rjs 
    311  1.1      rjs 	mutex_exit(&sc->sc_mtx);
    312  1.1      rjs 
    313  1.1      rjs 	return sc->sc_error;
    314  1.1      rjs }
    315  1.1      rjs 
    316  1.1      rjs static int
    317  1.1      rjs mesoni2c_intr(void *arg)
    318  1.1      rjs {
    319  1.1      rjs 	struct mesoni2c_softc *sc = arg;
    320  1.1      rjs 	int done = 0;
    321  1.1      rjs 
    322  1.1      rjs 	mutex_enter(&sc->sc_mtx);
    323  1.1      rjs 
    324  1.1      rjs 	if (RD4(sc, MESONI2C_CTRL_REG) & MESONI2C_CTRL_ERROR) {
    325  1.1      rjs 		/*
    326  1.1      rjs 		 * The ERROR bit is set when the ACK_IGNORE bit is cleared
    327  1.1      rjs 		 * in MESONI2C_CTRL_REG and the device didn't respond with
    328  1.1      rjs 		 * an ACK. In this case, the I2C controller automatically
    329  1.1      rjs 		 * generates a STOP condition.
    330  1.1      rjs 		 */
    331  1.1      rjs 		sc->sc_error = EIO;
    332  1.1      rjs 		done = 1;
    333  1.1      rjs 	} else {
    334  1.1      rjs 		if (I2C_OP_READ_P(sc->sc_curop)) {
    335  1.1      rjs 			/* Read data bytes */
    336  1.1      rjs 			u_int count = (RD4(sc, MESONI2C_CTRL_REG) & MESONI2C_CTRL_READ_DATA_MASK)
    337  1.1      rjs 				>> MESONI2C_CTRL_READ_DATA_SHIFT;
    338  1.2    skrll 
    339  1.1      rjs 			while (count--) {
    340  1.1      rjs 				*(sc->sc_databuf++) = mesoni2c_get_byte(sc);
    341  1.1      rjs 			}
    342  1.1      rjs 		}
    343  1.1      rjs 
    344  1.1      rjs 		if (sc->sc_curlen) {
    345  1.1      rjs 			/* Continue transfer */
    346  1.1      rjs 			mesoni2c_reset_state(sc);
    347  1.1      rjs 			mesoni2c_partial_xfer(sc);
    348  1.1      rjs 		} else {
    349  1.1      rjs 			if (sc->sc_sendingCmd && sc->sc_datalen) {
    350  1.1      rjs 				/*
    351  1.1      rjs 				 * We've just finished transfering the command
    352  1.3   andvar 				 * bytes, we must now transfer the data.
    353  1.1      rjs 				 */
    354  1.1      rjs 				sc->sc_curlen = sc->sc_datalen;
    355  1.1      rjs 				sc->sc_curop = sc->sc_op;
    356  1.1      rjs 				sc->sc_sendingCmd = 0;
    357  1.1      rjs 
    358  1.1      rjs 				if (I2C_OP_READ_P(sc->sc_curop)) {
    359  1.1      rjs 					mesoni2c_prepare_xfer(sc, sc->sc_curop);
    360  1.1      rjs 				} else {
    361  1.1      rjs 					mesoni2c_reset_state(sc);
    362  1.1      rjs 				}
    363  1.1      rjs 
    364  1.1      rjs 				mesoni2c_partial_xfer(sc);
    365  1.1      rjs 			} else {
    366  1.1      rjs 				done = 1;
    367  1.1      rjs 			}
    368  1.1      rjs 		}
    369  1.1      rjs 	}
    370  1.1      rjs 
    371  1.1      rjs 	if (done) {
    372  1.1      rjs 		/* Tell mesoni2c_exec() we're done. */
    373  1.1      rjs 		cv_broadcast(&sc->sc_cv);
    374  1.1      rjs 	}
    375  1.1      rjs 
    376  1.1      rjs 	mutex_exit(&sc->sc_mtx);
    377  1.1      rjs 
    378  1.1      rjs 	return 1;
    379  1.1      rjs }
    380  1.1      rjs 
    381  1.1      rjs static void
    382  1.1      rjs mesoni2c_set_clock_div_meson6(struct mesoni2c_softc *sc)
    383  1.1      rjs {
    384  1.1      rjs 	u_int rate = clk_get_rate(sc->sc_clk);
    385  1.1      rjs 	u_int div = howmany(rate, sc->sc_clkfreq) - FILTER_DELAY;
    386  1.1      rjs 	div = howmany(div, 4);
    387  1.1      rjs 
    388  1.1      rjs 	/* Set prescaler */
    389  1.1      rjs 	mesoni2c_set_mask(sc, MESONI2C_CTRL_REG, MESONI2C_CTRL_CLKDIV_MASK, (div & __BITS(9, 0)) << MESONI2C_CTRL_CLKDIV_SHIFT);
    390  1.1      rjs 	mesoni2c_set_mask(sc, MESONI2C_CTRL_REG, MESONI2C_CTRL_CLKDIVEXT_MASK, (div >> 10) << MESONI2C_CTRL_CLKDIVEXT_SHIFT);
    391  1.1      rjs 
    392  1.1      rjs 	/* Disable HIGH/LOW mode */
    393  1.1      rjs 	mesoni2c_set_mask(sc, MESONI2C_SLAVE_ADDR_REG, MESONI2C_SLAVE_SCL_LOW_EN, 0);
    394  1.1      rjs }
    395  1.1      rjs 
    396  1.1      rjs static void
    397  1.1      rjs mesoni2c_set_clock_div_gxbb_axg(struct mesoni2c_softc *sc)
    398  1.1      rjs {
    399  1.1      rjs 	u_int rate = clk_get_rate(sc->sc_clk);
    400  1.1      rjs 	u_int divh, divl;
    401  1.1      rjs 
    402  1.1      rjs 	/*
    403  1.1      rjs 	 * According to I2C-BUS Spec 2.1, in FAST-MODE, the minimum
    404  1.1      rjs 	 * LOW period is 1.3uS, and minimum HIGH is least 0.6us.
    405  1.1      rjs 	 * For
    406  1.1      rjs 	 * 400000 freq, the period is 2.5us. To keep within the specs,
    407  1.1      rjs 	 * give 40% of period to HIGH and 60% to LOW. This means HIGH
    408  1.1      rjs 	 * at 1.0us and LOW 1.5us.
    409  1.1      rjs 	 * The same applies for Fast-mode plus, where LOW is 0.5us and
    410  1.1      rjs 	 * HIGH is 0.26us.
    411  1.1      rjs 	 * Duty = H/(H + L) = 2/5
    412  1.1      rjs 	 */
    413  1.1      rjs 	if (sc->sc_clkfreq <= 100000) {
    414  1.1      rjs 		divh = howmany(rate, sc->sc_clkfreq);
    415  1.1      rjs 		divl = howmany(divh, 4);
    416  1.1      rjs 		divh = howmany(divh, 2) - FILTER_DELAY;
    417  1.1      rjs 	} else {
    418  1.1      rjs 		divh = howmany(rate * 2, sc->sc_clkfreq * 5) - FILTER_DELAY;
    419  1.1      rjs 		divl = howmany(rate * 3, sc->sc_clkfreq * 5 * 2);
    420  1.1      rjs 	}
    421  1.1      rjs 
    422  1.1      rjs 	/* Set prescaler */
    423  1.1      rjs 	mesoni2c_set_mask(sc, MESONI2C_CTRL_REG, MESONI2C_CTRL_CLKDIV_MASK, (divh & __BITS(9, 0)) << MESONI2C_CTRL_CLKDIV_SHIFT);
    424  1.1      rjs 	mesoni2c_set_mask(sc, MESONI2C_CTRL_REG, MESONI2C_CTRL_CLKDIVEXT_MASK, (divh >> 10) << MESONI2C_CTRL_CLKDIVEXT_SHIFT);
    425  1.1      rjs 
    426  1.1      rjs 	/* Set SCL low delay */
    427  1.1      rjs 	mesoni2c_set_mask(sc, MESONI2C_SLAVE_ADDR_REG, MESONI2C_SLAVE_SCL_LOW_MASK, divl << MESONI2C_SLAVE_SCL_LOW_SHIFT);
    428  1.1      rjs 
    429  1.1      rjs 	/* Enable HIGH/LOW mode */
    430  1.1      rjs 	mesoni2c_set_mask(sc, MESONI2C_SLAVE_ADDR_REG, MESONI2C_SLAVE_SCL_LOW_EN, MESONI2C_SLAVE_SCL_LOW_EN);
    431  1.1      rjs }
    432  1.1      rjs 
    433  1.1      rjs static int
    434  1.1      rjs mesoni2c_match(device_t parent, cfdata_t cf, void *aux)
    435  1.1      rjs {
    436  1.1      rjs 	struct fdt_attach_args * const faa = aux;
    437  1.1      rjs 
    438  1.1      rjs 	return of_compatible_match(faa->faa_phandle, compat_data);
    439  1.1      rjs }
    440  1.1      rjs 
    441  1.1      rjs static void
    442  1.1      rjs mesoni2c_attach(device_t parent, device_t self, void *aux)
    443  1.1      rjs {
    444  1.1      rjs 	struct mesoni2c_softc * const sc = device_private(self);
    445  1.1      rjs 	struct fdt_attach_args * const faa = aux;
    446  1.1      rjs 	const int phandle = faa->faa_phandle;
    447  1.1      rjs 	bus_addr_t addr;
    448  1.1      rjs 	bus_size_t size;
    449  1.1      rjs 	char intrstr[128];
    450  1.1      rjs 
    451  1.1      rjs 	if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
    452  1.1      rjs 		aprint_error_dev(self, "couldn't get registers\n");
    453  1.1      rjs 		return;
    454  1.1      rjs 	}
    455  1.1      rjs 
    456  1.1      rjs 	sc->sc_clk = fdtbus_clock_get_index(phandle, 0);
    457  1.2    skrll 
    458  1.1      rjs 	if (sc->sc_clk == NULL || clk_enable(sc->sc_clk) != 0) {
    459  1.1      rjs 		aprint_error_dev(self, "couldn't enable clock\n");
    460  1.1      rjs 		return;
    461  1.1      rjs 	}
    462  1.1      rjs 
    463  1.1      rjs 	sc->sc_dev = self;
    464  1.1      rjs 	sc->sc_bst = faa->faa_bst;
    465  1.1      rjs 
    466  1.1      rjs 	if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) {
    467  1.1      rjs 		aprint_error_dev(self, "couldn't map registers\n");
    468  1.1      rjs 		return;
    469  1.1      rjs 	}
    470  1.1      rjs 
    471  1.1      rjs 	fdtbus_clock_assign(phandle);
    472  1.1      rjs 
    473  1.1      rjs 	if (of_getprop_uint32(phandle, "clock-frequency", &sc->sc_clkfreq)) {
    474  1.1      rjs 		sc->sc_clkfreq = 100000;
    475  1.1      rjs 	} else {
    476  1.1      rjs 		if (sc->sc_clkfreq < 100000) {
    477  1.1      rjs 			sc->sc_clkfreq = 100000;
    478  1.1      rjs 		} else if (sc->sc_clkfreq > 400000) {
    479  1.1      rjs 			sc->sc_clkfreq = 400000;
    480  1.1      rjs 		}
    481  1.1      rjs 	}
    482  1.1      rjs 
    483  1.1      rjs 	aprint_naive("\n");
    484  1.1      rjs 	aprint_normal(": Meson I2C (%u Hz)\n", sc->sc_clkfreq);
    485  1.1      rjs 
    486  1.1      rjs 	enum mesoni2c_type type = of_compatible_lookup(phandle, compat_data)->value;
    487  1.2    skrll 
    488  1.1      rjs 	switch (type) {
    489  1.1      rjs 	case TYPE_MESON6:
    490  1.1      rjs 		mesoni2c_set_clock_div_meson6(sc);
    491  1.1      rjs 		break;
    492  1.1      rjs 
    493  1.1      rjs 	case TYPE_GXBB:
    494  1.1      rjs 	case TYPE_AXG:
    495  1.1      rjs 		mesoni2c_set_clock_div_gxbb_axg(sc);
    496  1.1      rjs 		break;
    497  1.1      rjs 	}
    498  1.1      rjs 
    499  1.1      rjs 	mutex_init(&sc->sc_mtx, MUTEX_DEFAULT, IPL_VM);
    500  1.1      rjs 	cv_init(&sc->sc_cv, "mesoniic");
    501  1.1      rjs 
    502  1.1      rjs 	if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) {
    503  1.1      rjs 		aprint_error_dev(self, "failed to decode interrupt\n");
    504  1.1      rjs 		return;
    505  1.1      rjs 	}
    506  1.1      rjs 
    507  1.1      rjs 	sc->sc_ih = fdtbus_intr_establish_xname(phandle, 0, IPL_VM, 0,
    508  1.1      rjs 		mesoni2c_intr, sc, device_xname(self));
    509  1.1      rjs 
    510  1.1      rjs 	if (sc->sc_ih == NULL) {
    511  1.1      rjs 		aprint_error_dev(self, "couldn't establish interrupt\n");
    512  1.1      rjs 		return;
    513  1.1      rjs 	}
    514  1.1      rjs 
    515  1.1      rjs 	aprint_normal_dev(self, "interrupting on %s\n", intrstr);
    516  1.1      rjs 
    517  1.1      rjs 	iic_tag_init(&sc->sc_ic);
    518  1.1      rjs 	sc->sc_ic.ic_cookie = sc;
    519  1.1      rjs 	sc->sc_ic.ic_exec = mesoni2c_exec;
    520  1.1      rjs 
    521  1.4  thorpej 	iicbus_attach(self, &sc->sc_ic);
    522  1.1      rjs }
    523