Home | History | Annotate | Line # | Download | only in samsung
exynos_i2c.c revision 1.5
      1 /*	$NetBSD: exynos_i2c.c,v 1.5 2015/12/21 00:52:50 marty Exp $ */
      2 
      3 /*
      4  * Copyright (c) 2014 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Reinoud Zandijk.
      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 
     33 #include "opt_exynos.h"
     34 #include "opt_arm_debug.h"
     35 #include "exynos_iic.h"
     36 
     37 #include <sys/cdefs.h>
     38 __KERNEL_RCSID(0, "$NetBSD: exynos_i2c.c,v 1.5 2015/12/21 00:52:50 marty Exp $");
     39 
     40 #include <sys/param.h>
     41 #include <sys/bus.h>
     42 #include <sys/device.h>
     43 #include <sys/intr.h>
     44 #include <sys/systm.h>
     45 #include <sys/kmem.h>
     46 
     47 #include <arm/samsung/exynos_reg.h>
     48 #include <arm/samsung/exynos_io.h>
     49 #include <arm/samsung/exynos_intr.h>
     50 
     51 #include <sys/gpio.h>
     52 #include <dev/gpio/gpiovar.h>
     53 
     54 #include <dev/i2c/i2cvar.h>
     55 #include <dev/i2c/i2c_bitbang.h>
     56 
     57 #include <dev/fdt/fdtvar.h>
     58 
     59 struct exynos_i2c_softc {
     60 	device_t		sc_dev;
     61 	bus_space_tag_t		sc_bst;
     62 	bus_space_handle_t	sc_bsh;
     63 	void *			sc_ih;
     64 	u_int			sc_port;
     65 
     66 	struct fdtbus_gpio_pin  sc_sda;
     67 	struct fdtbus_gpio_pin  sc_slc;
     68 	bool			sc_sda_is_output;
     69 	struct i2c_controller 	sc_ic;
     70 	kmutex_t		sc_lock;
     71 	kcondvar_t		sc_cv;
     72 	device_t		sc_i2cdev;
     73 };
     74 
     75 static u_int i2c_port;
     76 
     77 static int	exynos_i2c_intr(void *);
     78 
     79 static int	exynos_i2c_acquire_bus(void *, int);
     80 static void	exynos_i2c_release_bus(void *, int);
     81 
     82 static int	exynos_i2c_send_start(void *, int);
     83 static int	exynos_i2c_send_stop(void *, int);
     84 static int	exynos_i2c_initiate_xfer(void *, i2c_addr_t, int);
     85 static int	exynos_i2c_read_byte(void *, uint8_t *, int);
     86 static int	exynos_i2c_write_byte(void *, uint8_t , int);
     87 
     88 static bool exynos_i2c_attach_i2cbus(struct exynos_i2c_softc *,
     89 				     struct i2c_controller *);
     90 
     91 static int exynos_i2c_match(device_t, cfdata_t, void *);
     92 static void exynos_i2c_attach(device_t, device_t, void *);
     93 
     94 CFATTACH_DECL_NEW(exynos_i2c, sizeof(struct exynos_i2c_softc),
     95     exynos_i2c_match, exynos_i2c_attach, NULL, NULL);
     96 
     97 static int
     98 exynos_i2c_match(device_t self, cfdata_t cf, void *aux)
     99 {
    100 	const char * const compatible[] = { "samsung,s3c2440-i2c", NULL };
    101 	struct fdt_attach_args * const faa = aux;
    102 
    103 	return of_match_compatible(faa->faa_phandle, compatible);
    104 }
    105 
    106 static void
    107 exynos_i2c_attach(device_t parent, device_t self, void *aux)
    108 {
    109         struct exynos_i2c_softc * const sc =  device_private(self);
    110 	struct fdt_attach_args * const faa = aux;
    111 	const int phandle = faa->faa_phandle;
    112 	struct i2cbus_attach_args iba;
    113 
    114 	char intrstr[128];
    115 	bus_addr_t addr;
    116 	bus_size_t size;
    117 	int error;
    118 
    119 	if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
    120 		aprint_error(": couldn't get registers\n");
    121 		return;
    122 	}
    123 
    124 
    125 	sc->sc_dev  = self;
    126 	sc->sc_bst = faa->faa_bst;
    127 	error = bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh);
    128 	if (error) {
    129 		aprint_error(": couldn't map %#llx: %d", (uint64_t)addr,
    130 			     error);
    131 		return;
    132 	}
    133 
    134 	sc->sc_port = i2c_port++;
    135 	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_VM);
    136 	cv_init(&sc->sc_cv, device_xname(self));
    137 	aprint_normal(" @ 0x%08x", (uint)addr);
    138 
    139 	if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) {
    140 		aprint_error_dev(self, "failed to decode interrupt\n");
    141 		return;
    142 	}
    143 
    144 	sc->sc_ih = fdtbus_intr_establish(phandle, 0, IPL_VM,
    145 	    FDT_INTR_MPSAFE, exynos_i2c_intr, sc);
    146 	if (sc->sc_ih == NULL) {
    147 		aprint_error_dev(self, "couldn't establish interrupt on %s\n",
    148 		    intrstr);
    149 		return;
    150 	}
    151 	aprint_normal_dev(self, "interrupting on %s\n", intrstr);
    152 
    153 	if (!exynos_i2c_attach_i2cbus(sc, &sc->sc_ic))
    154 		return;
    155 
    156 	sc->sc_i2cdev = config_found_ia(self, "i2cbus", &iba, iicbus_print);
    157 
    158 }
    159 
    160 static bool
    161 exynos_i2c_attach_i2cbus(struct exynos_i2c_softc *i2c_sc,
    162 			 struct i2c_controller *i2c_cntr)
    163 {
    164 	i2c_cntr->ic_cookie = i2c_sc;
    165 	i2c_cntr->ic_acquire_bus = exynos_i2c_acquire_bus;
    166 	i2c_cntr->ic_release_bus = exynos_i2c_release_bus;
    167 	i2c_cntr->ic_send_start  = exynos_i2c_send_start;
    168 	i2c_cntr->ic_send_stop   = exynos_i2c_send_stop;
    169 	i2c_cntr->ic_initiate_xfer = exynos_i2c_initiate_xfer;
    170 	i2c_cntr->ic_read_byte   = exynos_i2c_read_byte;
    171 	i2c_cntr->ic_write_byte  = exynos_i2c_write_byte;
    172 
    173 	/*MJF: FIX ME needs gpio pins */
    174 //	exynos_gpio_pinset_acquire(pinset);
    175 	return 1;
    176 }
    177 
    178 #define EXYNOS_I2C_BB_SDA	__BIT(1)
    179 #define EXYNOS_I2C_BB_SCL	__BIT(2)
    180 #define EXYNOS_I2C_BB_SDA_OUT	__BIT(3)
    181 #define EXYNOS_I2C_BB_SDA_IN	0
    182 
    183 static void
    184 exynos_i2c_bb_set_bits(void *cookie, uint32_t bits)
    185 {
    186 	struct exynos_i2c_softc *i2c_sc = cookie;
    187 	int sda, slc;
    188 
    189 	sda = (bits & EXYNOS_I2C_BB_SDA) ? true : false;
    190 	slc = (bits & EXYNOS_I2C_BB_SCL) ? true : false;
    191 
    192 	if (i2c_sc->sc_sda_is_output)
    193 		fdtbus_gpio_write(&i2c_sc->sc_sda, sda);
    194 	fdtbus_gpio_write(&i2c_sc->sc_slc, slc);
    195 }
    196 
    197 static uint32_t
    198 exynos_i2c_bb_read_bits(void *cookie)
    199 {
    200 	struct exynos_i2c_softc *i2c_sc = cookie;
    201 	int sda, slc;
    202 
    203 	sda = 0;
    204 	if (!i2c_sc->sc_sda_is_output)
    205 		sda = fdtbus_gpio_read(&i2c_sc->sc_sda);
    206 	slc = fdtbus_gpio_read(&i2c_sc->sc_slc);
    207 
    208 	return (sda ? EXYNOS_I2C_BB_SDA : 0) | (slc ? EXYNOS_I2C_BB_SCL : 0);
    209 }
    210 
    211 static void
    212 exynos_i2c_bb_set_dir(void *cookie, uint32_t bits)
    213 {
    214 	struct exynos_i2c_softc *i2c_sc = cookie;
    215 	int flags;
    216 
    217 	flags = GPIO_PIN_INPUT | GPIO_PIN_TRISTATE;
    218 	i2c_sc->sc_sda_is_output = ((bits & EXYNOS_I2C_BB_SDA_OUT) != 0);
    219 	if (i2c_sc->sc_sda_is_output)
    220 		flags = GPIO_PIN_OUTPUT | GPIO_PIN_TRISTATE;
    221 
    222 	/* MJF: This is wrong but fdtbus has no ctrl operation */
    223 	fdtbus_gpio_write(&i2c_sc->sc_sda, flags);
    224 }
    225 
    226 static const struct i2c_bitbang_ops exynos_i2c_bbops = {
    227 	exynos_i2c_bb_set_bits,
    228 	exynos_i2c_bb_set_dir,
    229 	exynos_i2c_bb_read_bits,
    230 	{
    231 		EXYNOS_I2C_BB_SDA,
    232 		EXYNOS_I2C_BB_SCL,
    233 		EXYNOS_I2C_BB_SDA_OUT,
    234 		EXYNOS_I2C_BB_SDA_IN,
    235 	}
    236 };
    237 
    238 static int
    239 exynos_i2c_intr(void *priv)
    240 {
    241 	struct exynos_i2c_softc * const sc = priv;
    242 
    243 //	const uint32_t istatus = I2C_READ(sc, I2C_INTERRUPT_STATUS_REG);
    244 //	if (istatus == 0)
    245 //		return 0;
    246 //	I2C_WRITE(sc, I2C_INTERRUPT_STATUS_REG, istatus);
    247 
    248 	mutex_enter(&sc->sc_lock);
    249 	cv_broadcast(&sc->sc_cv);
    250 	mutex_exit(&sc->sc_lock);
    251 
    252 	return 1;
    253 }
    254 
    255 static int
    256 exynos_i2c_acquire_bus(void *cookie, int flags)
    257 {
    258 	struct exynos_i2c_softc *i2c_sc = cookie;
    259 
    260 	/* XXX what to do in polling case? could another cpu help */
    261 	if (flags & I2C_F_POLL)
    262 		return 0;
    263 	mutex_enter(&i2c_sc->sc_lock);
    264 	return 0;
    265 }
    266 
    267 static void
    268 exynos_i2c_release_bus(void *cookie, int flags)
    269 {
    270 	struct exynos_i2c_softc *i2c_sc = cookie;
    271 
    272 	/* XXX what to do in polling case? could another cpu help */
    273 	if (flags & I2C_F_POLL)
    274 		return;
    275 	mutex_exit(&i2c_sc->sc_lock);
    276 }
    277 
    278 static int
    279 exynos_i2c_send_start(void *cookie, int flags)
    280 {
    281 	return i2c_bitbang_send_start(cookie, flags, &exynos_i2c_bbops);
    282 }
    283 
    284 static int
    285 exynos_i2c_send_stop(void *cookie, int flags)
    286 {
    287 	return i2c_bitbang_send_stop(cookie, flags, &exynos_i2c_bbops);
    288 }
    289 
    290 static int
    291 exynos_i2c_initiate_xfer(void *cookie, i2c_addr_t addr, int flags)
    292 {
    293 	return i2c_bitbang_initiate_xfer(cookie, addr, flags,
    294 					 &exynos_i2c_bbops);
    295 }
    296 
    297 static int
    298 exynos_i2c_read_byte(void *cookie, uint8_t *bytep, int flags)
    299 {
    300 	return i2c_bitbang_read_byte(cookie, bytep, flags,
    301 				     &exynos_i2c_bbops);
    302 }
    303 
    304 static int
    305 exynos_i2c_write_byte(void *cookie, uint8_t byte, int flags)
    306 {
    307 	return i2c_bitbang_write_byte(cookie, byte, flags,
    308 				      &exynos_i2c_bbops);
    309 }
    310