Home | History | Annotate | Line # | Download | only in shark
      1 /*	$NetBSD: shark_iic.c,v 1.3 2025/09/15 13:23:02 thorpej Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2021 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Julian Coleman.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 
     34 __KERNEL_RCSID(0, "$NetBSD: shark_iic.c,v 1.3 2025/09/15 13:23:02 thorpej Exp $");
     35 
     36 #include <sys/param.h>
     37 #include <sys/systm.h>
     38 #include <sys/device.h>
     39 
     40 #include <dev/ofw/openfirm.h>
     41 
     42 #include <shark/shark/sequoia.h>
     43 
     44 #include <dev/i2c/i2cvar.h>
     45 #include <dev/i2c/i2c_bitbang.h>
     46 
     47 #include <arm/cpufunc.h>
     48 
     49 /* define registers on sequoia used by pins  */
     50 #define	SEQUOIA_1GPIO		PMC_GPCR_REG		/* reg 0x007 gpio 0-3 */
     51 #define	SEQUOIA_2GPIO		SEQ2_OGPIOCR_REG	/* reg 0x304 gpio 4.8 */
     52 
     53 /* define pins on sequoia that talk to the DIMM I2C bus */
     54 #define	IIC_CLK			FOMPCR_M_PCON9
     55 #define	IIC_DATA_IN_DIR		GPCR_M_GPIODIR3
     56 #define	IIC_DATA_IN		GPCR_M_GPIODATA3
     57 #define	IIC_DATA_OUT_DIR	GPIOCR2_M_GPIOBDIR1
     58 
     59 /* logical i2c signals */
     60 #define	SHARK_IIC_BIT_SDA	0x01
     61 #define	SHARK_IIC_BIT_SCL	0x02
     62 #define	SHARK_IIC_BIT_OUTPUT	0x04
     63 #define	SHARK_IIC_BIT_INPUT	0x08
     64 
     65 struct sharkiic_softc {
     66 	device_t		sc_dev;
     67 	struct i2c_controller	sc_i2c;
     68 };
     69 
     70 /* I2C bitbanging */
     71 
     72 static void
     73 sequoiaBBInit(void)
     74 {
     75 	uint16_t	seqReg;
     76 
     77 	sequoiaLock();
     78 
     79 	/*
     80 	 * SCL initialization
     81 	 * - enable pc[9]
     82 	 * - set pin to low (0)
     83 	 */
     84 	sequoiaRead(SEQR_SEQPSR3_REG, &seqReg);
     85 	CLR(seqReg, SEQPSR3_M_PC9PINEN);
     86 	sequoiaWrite(SEQR_SEQPSR3_REG, seqReg);
     87 	sequoiaRead(PMC_FOMPCR_REG, &seqReg);
     88 	SET(seqReg, IIC_CLK);
     89 	sequoiaWrite(PMC_FOMPCR_REG, seqReg);
     90 
     91 	/*
     92 	 * SDA (Output) initialization
     93 	 * - set direction to output
     94 	 * - enable GPIO B1 (sets pin to low)
     95 	 */
     96 	sequoiaRead(PMC_GPIOCR2_REG, &seqReg);
     97 	SET(seqReg, IIC_DATA_OUT_DIR);
     98 	sequoiaWrite(PMC_GPIOCR2_REG, seqReg);
     99 	sequoiaRead(SEQR_SEQPSR2_REG, &seqReg);
    100 	SET(seqReg, SEQPSR2_M_GPIOB1PINEN);
    101 	sequoiaWrite(SEQR_SEQPSR2_REG, seqReg);
    102 
    103 	/*
    104 	 * SDA (Input) initialization
    105 	 * - enable GPIO
    106 	 * - set direction to input
    107 	 */
    108 	sequoiaRead(SEQ2_SEQ2PSR_REG, &seqReg);
    109 	CLR(seqReg, SEQ2PSR_M_GPIOPINEN);
    110 	sequoiaWrite(SEQ2_SEQ2PSR_REG, seqReg);
    111 	sequoiaRead(SEQUOIA_1GPIO, &seqReg);
    112 	CLR(seqReg, IIC_DATA_IN_DIR);
    113 	sequoiaWrite(SEQUOIA_1GPIO, seqReg);
    114 
    115 	sequoiaUnlock();
    116 }
    117 
    118 static void
    119 sequoiaBBSetBits(uint32_t bits)
    120 {
    121 	uint16_t	seqRegSDA, seqRegSCL;
    122 
    123 	sequoiaLock();
    124 
    125 	sequoiaRead(PMC_FOMPCR_REG, &seqRegSCL);
    126 	sequoiaRead(SEQR_SEQPSR2_REG, &seqRegSDA);
    127 
    128 	/*
    129 	 * For SCL and SDA:
    130 	 * - output is the inverse of the desired signal
    131 	 * - the pin enable bit drives the signal
    132 	 */
    133 	if (bits & SHARK_IIC_BIT_SCL) {
    134 		CLR(seqRegSCL, IIC_CLK);
    135 	} else {
    136 		SET(seqRegSCL, IIC_CLK);
    137 	}
    138 
    139 	if (bits & SHARK_IIC_BIT_SDA) {
    140 		CLR(seqRegSDA, SEQPSR2_M_GPIOB1PINEN);
    141 	} else {
    142 		SET(seqRegSDA, SEQPSR2_M_GPIOB1PINEN);
    143 	}
    144 
    145 	sequoiaWrite(PMC_FOMPCR_REG, seqRegSCL);
    146 	sequoiaWrite(SEQR_SEQPSR2_REG, seqRegSDA);
    147 
    148 	sequoiaUnlock();
    149 }
    150 
    151 static void
    152 sequoiaBBSetDir(uint32_t dir)
    153 {
    154 	uint16_t	seqReg;
    155 
    156 	sequoiaLock();
    157 
    158 	/*
    159 	 * For direction = Input, set SDA (Output) direction to input,
    160 	 * otherwise we'll only read our own signal on SDA (Input)
    161 	 */
    162 	sequoiaRead(PMC_GPIOCR2_REG, &seqReg);
    163 	if (dir & SHARK_IIC_BIT_OUTPUT)
    164 		SET(seqReg, IIC_DATA_OUT_DIR);
    165 	else
    166 		CLR(seqReg, IIC_DATA_OUT_DIR);
    167 	sequoiaWrite(PMC_GPIOCR2_REG, seqReg);
    168 
    169 	sequoiaUnlock();
    170 }
    171 
    172 static uint32_t
    173 sequoiaBBRead(void)
    174 {
    175 	uint16_t	seqRegSDA, seqRegSCL;
    176 	uint32_t	bits = 0;
    177 
    178 	sequoiaLock();
    179 
    180 	sequoiaRead(SEQUOIA_1GPIO, &seqRegSDA);
    181 	sequoiaRead(PMC_FOMPCR_REG, &seqRegSCL);
    182 
    183 	sequoiaUnlock();
    184 
    185 	if (ISSET(seqRegSDA, IIC_DATA_IN))
    186 		bits |= SHARK_IIC_BIT_SDA;
    187 	if (!ISSET(seqRegSCL, IIC_CLK))
    188 		bits |= SHARK_IIC_BIT_SCL;
    189 
    190 	return bits;
    191 }
    192 
    193 static void
    194 sharkiicbb_set_bits(void *cookie, uint32_t bits)
    195 {
    196 	sequoiaBBSetBits(bits);
    197 }
    198 
    199 static void
    200 sharkiicbb_set_dir(void *cookie, uint32_t dir)
    201 {
    202 	sequoiaBBSetDir(dir);
    203 }
    204 
    205 static uint32_t
    206 sharkiicbb_read(void *cookie)
    207 {
    208 	return sequoiaBBRead();
    209 }
    210 
    211 static const struct i2c_bitbang_ops sharkiicbb_ops = {
    212 	.ibo_set_bits	=	sharkiicbb_set_bits,
    213 	.ibo_set_dir	=	sharkiicbb_set_dir,
    214 	.ibo_read_bits	=	sharkiicbb_read,
    215 	.ibo_bits = {
    216 		[I2C_BIT_SDA]		=	SHARK_IIC_BIT_SDA,
    217 		[I2C_BIT_SCL]		=	SHARK_IIC_BIT_SCL,
    218 		[I2C_BIT_OUTPUT]	=	SHARK_IIC_BIT_OUTPUT,
    219 		[I2C_BIT_INPUT]		=	SHARK_IIC_BIT_INPUT,
    220 	},
    221 };
    222 
    223 /* higher level I2C stuff */
    224 
    225 static int
    226 sharkiic_send_start(void *cookie, int flags)
    227 {
    228 	return (i2c_bitbang_send_start(cookie, flags, &sharkiicbb_ops));
    229 }
    230 
    231 static int
    232 sharkiic_send_stop(void *cookie, int flags)
    233 {
    234 	return (i2c_bitbang_send_stop(cookie, flags, &sharkiicbb_ops));
    235 }
    236 
    237 static int
    238 sharkiic_initiate_xfer(void *cookie, i2c_addr_t addr, int flags)
    239 {
    240 	return (i2c_bitbang_initiate_xfer(cookie, addr, flags,
    241 	    &sharkiicbb_ops));
    242 }
    243 
    244 static int
    245 sharkiic_read_byte(void *cookie, uint8_t *valp, int flags)
    246 {
    247 	return (i2c_bitbang_read_byte(cookie, valp, flags, &sharkiicbb_ops));
    248 }
    249 
    250 static int
    251 sharkiic_write_byte(void *cookie, uint8_t val, int flags)
    252 {
    253 	return (i2c_bitbang_write_byte(cookie, val, flags, &sharkiicbb_ops));
    254 }
    255 
    256 static int
    257 sharkiic_match(device_t parent, cfdata_t match, void *aux)
    258 {
    259 	struct ofbus_attach_args *oba = aux;
    260 
    261 	/* "sequoia" interface fills out oba_ofname */
    262 	return strcmp(oba->oba_ofname, "dec,dnard-i2c") == 0;
    263 }
    264 
    265 static void
    266 sharkiic_attach(device_t parent, device_t self, void *aux)
    267 {
    268 	struct sharkiic_softc *sc = device_private(self);
    269 
    270 	aprint_naive("\n");
    271 	aprint_normal("\n");
    272 
    273 	sequoiaBBInit();
    274 
    275 	iic_tag_init(&sc->sc_i2c);
    276 	sc->sc_i2c.ic_cookie = sc;
    277 	sc->sc_i2c.ic_send_start = sharkiic_send_start;
    278 	sc->sc_i2c.ic_send_stop = sharkiic_send_stop;
    279 	sc->sc_i2c.ic_initiate_xfer = sharkiic_initiate_xfer;
    280 	sc->sc_i2c.ic_read_byte = sharkiic_read_byte;
    281 	sc->sc_i2c.ic_write_byte = sharkiic_write_byte;
    282 
    283 	iicbus_attach(self, &sc->sc_i2c);
    284 }
    285 
    286 CFATTACH_DECL_NEW(sharkiic, sizeof(struct sharkiic_softc),
    287     sharkiic_match, sharkiic_attach, NULL, NULL);
    288