Home | History | Annotate | Line # | Download | only in apple
apple_iic.c revision 1.1
      1  1.1  skrll /*	$NetBSD: apple_iic.c,v 1.1 2022/05/10 08:05:32 skrll Exp $	*/
      2  1.1  skrll /*	$OpenBSD: apliic.c,v 1.3 2022/02/14 14:55:53 kettenis Exp $	*/
      3  1.1  skrll 
      4  1.1  skrll /*-
      5  1.1  skrll  * Copyright (c) 2022 The NetBSD Foundation, Inc.
      6  1.1  skrll  * All rights reserved.
      7  1.1  skrll  *
      8  1.1  skrll  * This code is derived from software contributed to The NetBSD Foundation
      9  1.1  skrll  * by Nick Hudson
     10  1.1  skrll  *
     11  1.1  skrll  * Redistribution and use in source and binary forms, with or without
     12  1.1  skrll  * modification, are permitted provided that the following conditions
     13  1.1  skrll  * are met:
     14  1.1  skrll  * 1. Redistributions of source code must retain the above copyright
     15  1.1  skrll  *    notice, this list of conditions and the following disclaimer.
     16  1.1  skrll  * 2. Redistributions in binary form must reproduce the above copyright
     17  1.1  skrll  *    notice, this list of conditions and the following disclaimer in the
     18  1.1  skrll  *    documentation and/or other materials provided with the distribution.
     19  1.1  skrll  *
     20  1.1  skrll  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     21  1.1  skrll  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     22  1.1  skrll  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     23  1.1  skrll  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     24  1.1  skrll  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     25  1.1  skrll  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     26  1.1  skrll  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     27  1.1  skrll  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     28  1.1  skrll  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     29  1.1  skrll  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     30  1.1  skrll  * POSSIBILITY OF SUCH DAMAGE.
     31  1.1  skrll  */
     32  1.1  skrll 
     33  1.1  skrll /*
     34  1.1  skrll  * Copyright (c) 2021 Patrick Wildt <patrick (at) blueri.se>
     35  1.1  skrll  *
     36  1.1  skrll  * Permission to use, copy, modify, and distribute this software for any
     37  1.1  skrll  * purpose with or without fee is hereby granted, provided that the above
     38  1.1  skrll  * copyright notice and this permission notice appear in all copies.
     39  1.1  skrll  *
     40  1.1  skrll  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     41  1.1  skrll  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     42  1.1  skrll  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     43  1.1  skrll  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     44  1.1  skrll  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     45  1.1  skrll  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     46  1.1  skrll  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     47  1.1  skrll  */
     48  1.1  skrll 
     49  1.1  skrll #include <sys/param.h>
     50  1.1  skrll 
     51  1.1  skrll #include <sys/bus.h>
     52  1.1  skrll #include <sys/device.h>
     53  1.1  skrll 
     54  1.1  skrll #include <dev/i2c/i2cvar.h>
     55  1.1  skrll 
     56  1.1  skrll #include <dev/fdt/fdtvar.h>
     57  1.1  skrll 
     58  1.1  skrll /* Registers. */
     59  1.1  skrll #define I2C_MTXFIFO		0x00
     60  1.1  skrll #define  I2C_MTXFIFO_DATA_MASK		__BITS(7,0)
     61  1.1  skrll #define  I2C_MTXFIFO_START		__BIT(8)
     62  1.1  skrll #define  I2C_MTXFIFO_STOP		__BIT(9)
     63  1.1  skrll #define  I2C_MTXFIFO_READ		__BIT(10)
     64  1.1  skrll #define I2C_MRXFIFO		0x04
     65  1.1  skrll #define  I2C_MRXFIFO_DATA_MASK		__BITS(7,0)
     66  1.1  skrll #define  I2C_MRXFIFO_EMPTY		__BIT(8)
     67  1.1  skrll #define I2C_SMSTA		0x14
     68  1.1  skrll #define  I2C_SMSTA_MTN			__BIT(21)
     69  1.1  skrll #define  I2C_SMSTA_XEN			__BIT(27)
     70  1.1  skrll #define  I2C_SMSTA_XBUSY		__BIT(28)
     71  1.1  skrll #define I2C_CTL			0x1c
     72  1.1  skrll #define  I2C_CTL_CLK_MASK		__BITS(7,0)
     73  1.1  skrll #define  I2C_CTL_MTR			__BIT(9)
     74  1.1  skrll #define  I2C_CTL_MRR			__BIT(10)
     75  1.1  skrll #define  I2C_CTL_EN			__BIT(11)
     76  1.1  skrll #define I2C_REV			0x28
     77  1.1  skrll 
     78  1.1  skrll #define IIC_READ(sc, reg)						\
     79  1.1  skrll 	(bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)))
     80  1.1  skrll #define IIC_WRITE(sc, reg, val)						\
     81  1.1  skrll 	bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
     82  1.1  skrll #define HSET4(sc, reg, bits)						\
     83  1.1  skrll 	IIC_WRITE((sc), (reg), IIC_READ((sc), (reg)) | (bits))
     84  1.1  skrll #define HCLR4(sc, reg, bits)						\
     85  1.1  skrll 	IIC_WRITE((sc), (reg), IIC_READ((sc), (reg)) & ~(bits))
     86  1.1  skrll 
     87  1.1  skrll struct apple_iic_softc {
     88  1.1  skrll 	device_t		sc_dev;
     89  1.1  skrll 	bus_space_tag_t		sc_bst;
     90  1.1  skrll 	bus_space_handle_t	sc_bsh;
     91  1.1  skrll 
     92  1.1  skrll 	struct clk *		sc_clk;
     93  1.1  skrll 	int			sc_hwrev;
     94  1.1  skrll 	uint32_t		sc_clkdiv;
     95  1.1  skrll 	struct i2c_controller	sc_i2c;
     96  1.1  skrll };
     97  1.1  skrll 
     98  1.1  skrll 
     99  1.1  skrll static int
    100  1.1  skrll apple_iic_acquire_bus(void *cookie, int flags)
    101  1.1  skrll {
    102  1.1  skrll 	return 0;
    103  1.1  skrll }
    104  1.1  skrll 
    105  1.1  skrll static void
    106  1.1  skrll apple_iic_release_bus(void *cookie, int flags)
    107  1.1  skrll {
    108  1.1  skrll }
    109  1.1  skrll 
    110  1.1  skrll static int
    111  1.1  skrll apple_iic_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *cmd,
    112  1.1  skrll     size_t cmdlen, void *buf, size_t buflen, int flags)
    113  1.1  skrll {
    114  1.1  skrll 	struct apple_iic_softc *sc = cookie;
    115  1.1  skrll 	const uint8_t * const cmdbytes = cmd;
    116  1.1  skrll 	uint8_t * const bufbytes = buf;
    117  1.1  skrll 	uint32_t reg;
    118  1.1  skrll 	int i;
    119  1.1  skrll 
    120  1.1  skrll 	if (!I2C_OP_STOP_P(op))
    121  1.1  skrll 		return EINVAL;
    122  1.1  skrll 
    123  1.1  skrll 	IIC_WRITE(sc, I2C_SMSTA, 0xffffffff);
    124  1.1  skrll 
    125  1.1  skrll 	if (cmdlen > 0) {
    126  1.1  skrll 		IIC_WRITE(sc, I2C_MTXFIFO, I2C_MTXFIFO_START | addr << 1);
    127  1.1  skrll 		for (i = 0; i < cmdlen - 1; i++)
    128  1.1  skrll 			IIC_WRITE(sc, I2C_MTXFIFO, cmdbytes[i]);
    129  1.1  skrll 		IIC_WRITE(sc, I2C_MTXFIFO, cmdbytes[cmdlen - 1] |
    130  1.1  skrll 		    (buflen == 0 ? I2C_MTXFIFO_STOP : 0));
    131  1.1  skrll 	}
    132  1.1  skrll 
    133  1.1  skrll 	if (buflen == 0)
    134  1.1  skrll 		return 0;
    135  1.1  skrll 
    136  1.1  skrll 	if (I2C_OP_READ_P(op)) {
    137  1.1  skrll 		IIC_WRITE(sc, I2C_MTXFIFO, I2C_MTXFIFO_START | addr << 1 | 1);
    138  1.1  skrll 		IIC_WRITE(sc, I2C_MTXFIFO, I2C_MTXFIFO_READ | buflen |
    139  1.1  skrll 		    I2C_MTXFIFO_STOP);
    140  1.1  skrll 		for (i = 10; i > 0; i--) {
    141  1.1  skrll 			delay(1000);
    142  1.1  skrll 			reg = IIC_READ(sc, I2C_SMSTA);
    143  1.1  skrll 			if (reg & I2C_SMSTA_XEN)
    144  1.1  skrll 				break;
    145  1.1  skrll 		}
    146  1.1  skrll 		if (reg & I2C_SMSTA_MTN)
    147  1.1  skrll 			return ENXIO;
    148  1.1  skrll 		if (i == 0)
    149  1.1  skrll 			return ETIMEDOUT;
    150  1.1  skrll 		IIC_WRITE(sc, I2C_SMSTA, I2C_SMSTA_XEN);
    151  1.1  skrll 		for (i = 0; i < buflen; i++) {
    152  1.1  skrll 			reg = IIC_READ(sc, I2C_MRXFIFO);
    153  1.1  skrll 			if (reg & I2C_MRXFIFO_EMPTY)
    154  1.1  skrll 				return EIO;
    155  1.1  skrll 			bufbytes[i] = reg & I2C_MRXFIFO_DATA_MASK;
    156  1.1  skrll 		}
    157  1.1  skrll 	} else {
    158  1.1  skrll 		if (cmdlen == 0)
    159  1.1  skrll 			IIC_WRITE(sc, I2C_MTXFIFO, I2C_MTXFIFO_START | addr << 1);
    160  1.1  skrll 		for (i = 0; i < buflen - 1; i++)
    161  1.1  skrll 			IIC_WRITE(sc, I2C_MTXFIFO, bufbytes[i]);
    162  1.1  skrll 		IIC_WRITE(sc, I2C_MTXFIFO, bufbytes[buflen - 1] |
    163  1.1  skrll 		    I2C_MTXFIFO_STOP);
    164  1.1  skrll 	}
    165  1.1  skrll 
    166  1.1  skrll 	return 0;
    167  1.1  skrll }
    168  1.1  skrll 
    169  1.1  skrll 
    170  1.1  skrll static const struct device_compatible_entry compat_data[] = {
    171  1.1  skrll 	{ .compat = "apple,i2c" },
    172  1.1  skrll 	DEVICE_COMPAT_EOL
    173  1.1  skrll };
    174  1.1  skrll 
    175  1.1  skrll static int
    176  1.1  skrll apple_iic_match(device_t parent, cfdata_t cf, void *aux)
    177  1.1  skrll {
    178  1.1  skrll 	struct fdt_attach_args * const faa = aux;
    179  1.1  skrll 
    180  1.1  skrll 	return of_compatible_match(faa->faa_phandle, compat_data);
    181  1.1  skrll }
    182  1.1  skrll 
    183  1.1  skrll static void
    184  1.1  skrll apple_iic_attach(device_t parent, device_t self, void *aux)
    185  1.1  skrll {
    186  1.1  skrll 	struct apple_iic_softc * const sc = device_private(self);
    187  1.1  skrll 	struct fdt_attach_args * const faa = aux;
    188  1.1  skrll 	const int phandle = faa->faa_phandle;
    189  1.1  skrll 	uint32_t clock_speed, bus_speed;
    190  1.1  skrll 	bus_addr_t addr;
    191  1.1  skrll 	bus_size_t size;
    192  1.1  skrll 
    193  1.1  skrll 	sc->sc_dev = self;
    194  1.1  skrll 	sc->sc_bst = faa->faa_bst;
    195  1.1  skrll 
    196  1.1  skrll 	int error = fdtbus_get_reg(phandle, 0, &addr, &size);
    197  1.1  skrll 	if (error) {
    198  1.1  skrll 		aprint_error(": unable to get device registers\n");
    199  1.1  skrll 		return;
    200  1.1  skrll 	}
    201  1.1  skrll 
    202  1.1  skrll 	/* Enable clock */
    203  1.1  skrll 	sc->sc_clk = fdtbus_clock_get_index(phandle, 0);
    204  1.1  skrll 	if (sc->sc_clk == NULL) {
    205  1.1  skrll 		aprint_error(": couldn't acquire clock\n");
    206  1.1  skrll 		return;
    207  1.1  skrll 	}
    208  1.1  skrll 
    209  1.1  skrll 	if (clk_enable(sc->sc_clk) != 0) {
    210  1.1  skrll 		aprint_error(": failed to enable clock\n");
    211  1.1  skrll 		return;
    212  1.1  skrll 	}
    213  1.1  skrll 
    214  1.1  skrll 	clock_speed = clk_get_rate(sc->sc_clk);
    215  1.1  skrll 
    216  1.1  skrll 	if (of_getprop_uint32(phandle, "clock-frequency",
    217  1.1  skrll 	    &bus_speed) != 0) {
    218  1.1  skrll 		bus_speed = 100000;
    219  1.1  skrll 	}
    220  1.1  skrll 	bus_speed *= 16;
    221  1.1  skrll 
    222  1.1  skrll 	if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh)) {
    223  1.1  skrll 		aprint_error(": unable to map device\n");
    224  1.1  skrll 		return;
    225  1.1  skrll 	}
    226  1.1  skrll 
    227  1.1  skrll 	aprint_naive("\n");
    228  1.1  skrll 	aprint_normal(": Apple I2C\n");
    229  1.1  skrll 
    230  1.1  skrll 	sc->sc_clkdiv = howmany(clock_speed, bus_speed);
    231  1.1  skrll 	KASSERT(sc->sc_clkdiv <= __SHIFTOUT_MASK(I2C_CTL_CLK_MASK));
    232  1.1  skrll 
    233  1.1  skrll 	sc->sc_hwrev = IIC_READ(sc, I2C_REV);
    234  1.1  skrll 
    235  1.1  skrll 	IIC_WRITE(sc, I2C_CTL,
    236  1.1  skrll 	    __SHIFTIN(sc->sc_clkdiv, I2C_CTL_CLK_MASK) |
    237  1.1  skrll 	    I2C_CTL_MTR | I2C_CTL_MRR |
    238  1.1  skrll 	    (sc->sc_hwrev >= 6 ? I2C_CTL_EN : 0));
    239  1.1  skrll 
    240  1.1  skrll 	iic_tag_init(&sc->sc_i2c);
    241  1.1  skrll 	sc->sc_i2c.ic_cookie = sc;
    242  1.1  skrll 	sc->sc_i2c.ic_acquire_bus = apple_iic_acquire_bus;
    243  1.1  skrll 	sc->sc_i2c.ic_release_bus = apple_iic_release_bus;
    244  1.1  skrll 	sc->sc_i2c.ic_exec = apple_iic_exec;
    245  1.1  skrll 
    246  1.1  skrll 	fdtbus_register_i2c_controller(&sc->sc_i2c, phandle);
    247  1.1  skrll 
    248  1.1  skrll 	fdtbus_attach_i2cbus(self, phandle, &sc->sc_i2c, iicbus_print);
    249  1.1  skrll }
    250  1.1  skrll 
    251  1.1  skrll 
    252  1.1  skrll CFATTACH_DECL_NEW(apple_iic, sizeof(struct apple_iic_softc),
    253  1.1  skrll     apple_iic_match, apple_iic_attach, NULL, NULL);
    254