Module Name: src Committed By: jmcneill Date: Sun Nov 2 23:55:48 UTC 2014
Modified Files: src/sys/arch/arm/allwinner: awin_io.c files.awin Added Files: src/sys/arch/arm/allwinner: awin_ir.c Log Message: work in progress CIR driver To generate a diff of this commit: cvs rdiff -u -r1.23 -r1.24 src/sys/arch/arm/allwinner/awin_io.c cvs rdiff -u -r0 -r1.1 src/sys/arch/arm/allwinner/awin_ir.c cvs rdiff -u -r1.17 -r1.18 src/sys/arch/arm/allwinner/files.awin 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/allwinner/awin_io.c diff -u src/sys/arch/arm/allwinner/awin_io.c:1.23 src/sys/arch/arm/allwinner/awin_io.c:1.24 --- src/sys/arch/arm/allwinner/awin_io.c:1.23 Sun Oct 19 23:18:22 2014 +++ src/sys/arch/arm/allwinner/awin_io.c Sun Nov 2 23:55:48 2014 @@ -31,7 +31,7 @@ #include <sys/cdefs.h> -__KERNEL_RCSID(1, "$NetBSD: awin_io.c,v 1.23 2014/10/19 23:18:22 jmcneill Exp $"); +__KERNEL_RCSID(1, "$NetBSD: awin_io.c,v 1.24 2014/11/02 23:55:48 jmcneill Exp $"); #include <sys/param.h> #include <sys/bus.h> @@ -147,6 +147,9 @@ static const struct awin_locators awin_l { "awincrypto", OFFANDSIZE(SS), NOPORT, AWIN_IRQ_SS, AANY }, { "awinac", OFFANDSIZE(AC), NOPORT, AWIN_IRQ_AC, A10|A20 }, { "awinac", OFFANDSIZE(AC), NOPORT, AWIN_A31_IRQ_AC, A31 }, + { "awinir", OFFANDSIZE(IR0), 0, AWIN_IRQ_IR0, A10|A20 }, + { "awinir", OFFANDSIZE(IR1), 1, AWIN_IRQ_IR1, A10|A20 }, + { "awinir", OFFANDSIZE(A31_CIR), NOPORT, AWIN_A31_IRQ_CIR, A31 }, }; static int Index: src/sys/arch/arm/allwinner/files.awin diff -u src/sys/arch/arm/allwinner/files.awin:1.17 src/sys/arch/arm/allwinner/files.awin:1.18 --- src/sys/arch/arm/allwinner/files.awin:1.17 Mon Oct 13 12:34:00 2014 +++ src/sys/arch/arm/allwinner/files.awin Sun Nov 2 23:55:48 2014 @@ -1,4 +1,4 @@ -# $NetBSD: files.awin,v 1.17 2014/10/13 12:34:00 jmcneill Exp $ +# $NetBSD: files.awin,v 1.18 2014/11/02 23:55:48 jmcneill Exp $ # # Configuration info for Allwinner ARM Peripherals # @@ -132,3 +132,8 @@ file arch/arm/allwinner/awin_ac.c awin_ device awinhdmi: edid, ddc_read_edid attach awinhdmi at awinio with awin_hdmi file arch/arm/allwinner/awin_hdmi.c awin_hdmi + +# A10/A20/A31 Consumer IR (CIR) +device awinir: irbus +attach awinir at awinio with awin_ir +file arch/arm/allwinner/awin_ir.c awin_ir Added files: Index: src/sys/arch/arm/allwinner/awin_ir.c diff -u /dev/null src/sys/arch/arm/allwinner/awin_ir.c:1.1 --- /dev/null Sun Nov 2 23:55:48 2014 +++ src/sys/arch/arm/allwinner/awin_ir.c Sun Nov 2 23:55:48 2014 @@ -0,0 +1,314 @@ +/* $NetBSD: awin_ir.c,v 1.1 2014/11/02 23:55:48 jmcneill Exp $ */ + +/*- + * Copyright (c) 2014 Jared D. McNeill <jmcne...@invisible.ca> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "opt_ddb.h" + +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD: awin_ir.c,v 1.1 2014/11/02 23:55:48 jmcneill Exp $"); + +#include <sys/param.h> +#include <sys/bus.h> +#include <sys/device.h> +#include <sys/intr.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/select.h> +#include <sys/mutex.h> +#include <sys/condvar.h> + +#include <arm/allwinner/awin_reg.h> +#include <arm/allwinner/awin_var.h> + +#include <dev/ir/ir.h> +#include <dev/ir/cirio.h> +#include <dev/ir/cirvar.h> + +#define AWIN_IR_RXSTA_MASK __BITS(7,0) + +struct awin_ir_softc { + device_t sc_dev; + device_t sc_cirdev; + bus_space_tag_t sc_bst; + bus_space_handle_t sc_bsh; + kmutex_t sc_lock; + kcondvar_t sc_cv; + device_t sc_i2cdev; + void *sc_ih; + size_t sc_avail; +}; + +#define IR_READ(sc, reg) \ + bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) +#define IR_WRITE(sc, reg, val) \ + bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) + +static int awin_ir_match(device_t, cfdata_t, void *); +static void awin_ir_attach(device_t, device_t, void *); + +static void awin_ir_init(struct awin_ir_softc *, + struct awinio_attach_args * const); + +static int awin_ir_intr(void *); + +static int awin_ir_open(void *, int, int, struct proc *); +static int awin_ir_close(void *, int, int, struct proc *); +static int awin_ir_read(void *, struct uio *, int); +static int awin_ir_write(void *, struct uio *, int); +static int awin_ir_setparams(void *, struct cir_params *); + +#ifdef DDB +void awin_ir_dump_regs(void); +#endif + +static const struct cir_methods awin_ir_methods = { + .im_open = awin_ir_open, + .im_close = awin_ir_close, + .im_read = awin_ir_read, + .im_write = awin_ir_write, + .im_setparams = awin_ir_setparams, +}; + +CFATTACH_DECL_NEW(awin_ir, sizeof(struct awin_ir_softc), + awin_ir_match, awin_ir_attach, NULL, NULL); + +static int +awin_ir_match(device_t parent, cfdata_t cf, void *aux) +{ + struct awinio_attach_args * const aio = aux; + const struct awin_locators * const loc = &aio->aio_loc; + + if (strcmp(cf->cf_name, loc->loc_name)) + return 0; + + return 1; +} + +static void +awin_ir_attach(device_t parent, device_t self, void *aux) +{ + struct awin_ir_softc *sc = device_private(self); + struct awinio_attach_args * const aio = aux; + const struct awin_locators * const loc = &aio->aio_loc; + struct ir_attach_args iaa; + + sc->sc_dev = self; + sc->sc_bst = aio->aio_core_bst; + mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_IR); + cv_init(&sc->sc_cv, "awinir"); + bus_space_subregion(sc->sc_bst, aio->aio_core_bsh, + loc->loc_offset, loc->loc_size, &sc->sc_bsh); + + aprint_naive("\n"); + aprint_normal(": IR\n"); + + sc->sc_ih = intr_establish(loc->loc_intr, IPL_IR, IST_LEVEL, + awin_ir_intr, sc); + if (sc->sc_ih == NULL) { + aprint_error_dev(self, "couldn't establish interrupt %d\n", + loc->loc_intr); + return; + } + aprint_normal_dev(self, "interrupting on irq %d\n", loc->loc_intr); + + awin_ir_init(sc, aio); + + memset(&iaa, 0, sizeof(iaa)); + iaa.ia_type = IR_TYPE_CIR; + iaa.ia_methods = &awin_ir_methods; + iaa.ia_handle = sc; + sc->sc_cirdev = config_found_ia(self, "irbus", &iaa, ir_print); +} + +static void +awin_ir_init(struct awin_ir_softc *sc, struct awinio_attach_args * const aio) +{ + if (awin_chip_id() == AWIN_CHIP_ID_A31) { + const struct awin_gpio_pinset pinset = + { 'L', AWIN_A31_PIO_PL_IR_FUNC, AWIN_A31_PIO_PL_IR_PINS, + GPIO_PIN_PULLUP }; + bus_space_handle_t prcm_bsh; + bus_size_t prcm_size = 0x200; + uint32_t clk, reset, gating; + + bus_space_subregion(sc->sc_bst, aio->aio_core_bsh, + AWIN_A31_PRCM_OFFSET, prcm_size, &prcm_bsh); + + awin_gpio_pinset_acquire(&pinset); + + gating = bus_space_read_4(sc->sc_bst, prcm_bsh, + AWIN_A31_PRCM_APB0_GATING_REG); + gating |= AWIN_A31_PRCM_APB0_GATING_CIR; + bus_space_write_4(sc->sc_bst, prcm_bsh, + AWIN_A31_PRCM_APB0_GATING_REG, gating); + + reset = bus_space_read_4(sc->sc_bst, prcm_bsh, + AWIN_A31_PRCM_APB0_RESET_REG); + reset |= AWIN_A31_PRCM_APB0_RESET_CIR; + bus_space_write_4(sc->sc_bst, prcm_bsh, + AWIN_A31_PRCM_APB0_RESET_REG, reset); + + clk = bus_space_read_4(sc->sc_bst, prcm_bsh, + AWIN_A31_PRCM_CIR_CLK_REG); + clk &= ~AWIN_CLK_SRC_SEL; + clk |= 1; /* HOSC */ + clk &= ~AWIN_CLK_DIV_RATIO_M; + clk |= 7; /* (24MHz / 3MHz) - 1 */ + clk &= ~AWIN_CLK_DIV_RATIO_N; + clk |= 0; /* 1 - 1 */ + clk |= AWIN_CLK_ENABLE; + bus_space_write_4(sc->sc_bst, prcm_bsh, + AWIN_A31_PRCM_CIR_CLK_REG, clk); + + bus_space_unmap(sc->sc_bst, prcm_bsh, prcm_size); + } +} + +static int +awin_ir_intr(void *priv) +{ + struct awin_ir_softc *sc = priv; + uint32_t sta; + + sta = IR_READ(sc, AWIN_IR_RXSTA_REG); + + printf("%s: sta = 0x%08x\n", __func__, sta); + + if ((sta & AWIN_IR_RXSTA_MASK) == 0) + return 0; + + IR_WRITE(sc, AWIN_IR_RXSTA_REG, sta & AWIN_IR_RXSTA_MASK); + + if (sta & AWIN_IR_RXSTA_RA) { + mutex_enter(&sc->sc_lock); + sc->sc_avail = __SHIFTOUT(sta, AWIN_IR_RXSTA_RAC); + cv_broadcast(&sc->sc_cv); + mutex_exit(&sc->sc_lock); + } + + return 1; +} + +static int +awin_ir_open(void *priv, int flag, int mode, struct proc *p) +{ + struct awin_ir_softc *sc = priv; + uint32_t ctl, rxint; + + ctl = __SHIFTIN(AWIN_IR_CTL_MD_CIR, AWIN_IR_CTL_MD); + IR_WRITE(sc, AWIN_IR_CTL_REG, ctl); + + IR_WRITE(sc, AWIN_IR_RXCTL_REG, AWIN_IR_RXCTL_RPPI); + + IR_WRITE(sc, AWIN_IR_RXSTA_REG, AWIN_IR_RXSTA_MASK); + + rxint = AWIN_IR_RXINT_RAI_EN; + rxint |= __SHIFTIN(0, AWIN_IR_RXINT_RAL); + IR_WRITE(sc, AWIN_IR_RXINT_REG, rxint); + + ctl |= AWIN_IR_CTL_GEN; + ctl |= AWIN_IR_CTL_RXEN; + IR_WRITE(sc, AWIN_IR_CTL_REG, ctl); + + return 0; +} + +static int +awin_ir_close(void *priv, int flag, int mode, struct proc *p) +{ + struct awin_ir_softc *sc = priv; + + IR_WRITE(sc, AWIN_IR_RXINT_REG, 0); + IR_WRITE(sc, AWIN_IR_CTL_REG, 0); + sc->sc_avail = 0; + + return 0; +} + +static int +awin_ir_read(void *priv, struct uio *uio, int flag) +{ + struct awin_ir_softc *sc = priv; + uint8_t data; + int error = 0; + + mutex_enter(&sc->sc_lock); + while (uio->uio_resid > 0) { + if (sc->sc_avail == 0) { + error = cv_wait_sig(&sc->sc_cv, &sc->sc_lock); + if (error) { + break; + } + } + if (sc->sc_avail > 0) { + --sc->sc_avail; + data = IR_READ(sc, AWIN_IR_RXFIFO_REG) & + AWIN_IR_RXFIFO_DATA; + error = uiomove(&data, sizeof(data), uio); + if (error) { + break; + } + } + } + mutex_exit(&sc->sc_lock); + + return error; +} + +static int +awin_ir_write(void *priv, struct uio *uio, int flag) +{ + return EIO; +} + +static int +awin_ir_setparams(void *priv, struct cir_params *params) +{ + return 0; +} + +#ifdef DDB +void +awin_ir_dump_regs(void) +{ + struct awin_ir_softc *sc; + device_t dev; + + dev = device_find_by_driver_unit("awinir", 0); + if (dev == NULL) + return; + sc = device_private(dev); + + printf("CTL: 0x%08x\n", IR_READ(sc, AWIN_IR_CTL_REG)); + printf("RXCTL: 0x%08x\n", IR_READ(sc, AWIN_IR_RXCTL_REG)); + printf("RXADR: 0x%08x\n", IR_READ(sc, AWIN_IR_RXADR_REG)); + printf("RXFIFO: ...\n"); + printf("RXINT: 0x%08x\n", IR_READ(sc, AWIN_IR_RXINT_REG)); + printf("RXSTA: 0x%08x\n", IR_READ(sc, AWIN_IR_RXSTA_REG)); + printf("CIR: 0x%08x\n", IR_READ(sc, AWIN_IR_CIR_REG)); +} +#endif