[RFC] AM335x (Beaglebone-black) ADC driver
Luiz Otavio O Souza
loos.br at gmail.com
Mon Mar 17 13:31:57 UTC 2014
Hi,
I've written a driver for the am335x ADC module (AIN inputs on BBB).
It works from the sysctl(8) interface, each input can be individually
enabled/disabled. When all the inputs are disabled, the ADC is turned
off.
The sysctl(8) interface also allows the selection of the number of the
samples average for each input (none, 2, 4, 8, 16) and the setting of
the ADC prescaler value (low clock speeds gives far stable readings
with the cost of loading - sometimes too much - the input circuit as
conversions can take a long time).
The converted values are exported as raw values (12 bits - 0 ~ 4095).
The ADC module can also work as a touchscreen sensor, but i have no
idea how to program the module as TSC sensor neither have the hardware
to test it, so this driver only works for reading the AIN converted
values.
Here is the output of the sysctl(8) for this driver:
# sysctl dev.am335x_adc.0
dev.am335x_adc.0.%desc: AM335x ADC controller
dev.am335x_adc.0.%driver: am335x_adc
dev.am335x_adc.0.%pnpinfo: name=adc at 44E0D000 compat=ti,am335x-adc
dev.am335x_adc.0.%parent: simplebus0
dev.am335x_adc.0.clockdiv: 30000
dev.am335x_adc.0.ain.0.enable: 0
dev.am335x_adc.0.ain.0.samples_avg: 0
dev.am335x_adc.0.ain.0.input: 0
dev.am335x_adc.0.ain.1.enable: 0
dev.am335x_adc.0.ain.1.samples_avg: 0
dev.am335x_adc.0.ain.1.input: 0
dev.am335x_adc.0.ain.2.enable: 0
dev.am335x_adc.0.ain.2.samples_avg: 0
dev.am335x_adc.0.ain.2.input: 0
dev.am335x_adc.0.ain.3.enable: 0
dev.am335x_adc.0.ain.3.samples_avg: 0
dev.am335x_adc.0.ain.3.input: 0
dev.am335x_adc.0.ain.4.enable: 0
dev.am335x_adc.0.ain.4.samples_avg: 0
dev.am335x_adc.0.ain.4.input: 0
dev.am335x_adc.0.ain.5.enable: 0
dev.am335x_adc.0.ain.5.samples_avg: 0
dev.am335x_adc.0.ain.5.input: 0
dev.am335x_adc.0.ain.6.enable: 1
dev.am335x_adc.0.ain.6.samples_avg: 0
dev.am335x_adc.0.ain.6.input: 2176
I've checked the 7 AINs with a potentiometer connected to them (and
using VDD_ADC and GNDA_ADC).
I am now writing the man page so i can ask for a approval to commit it.
Comments ?
Regards,
Luiz
-------------- next part --------------
Index: sys/arm/ti/am335x/am335x_prcm.c
===================================================================
--- sys/arm/ti/am335x/am335x_prcm.c (revision 262131)
+++ sys/arm/ti/am335x/am335x_prcm.c (working copy)
@@ -107,6 +107,7 @@
#define CM_WKUP_CM_CLKDCOLDO_DPLL_PER (CM_WKUP + 0x07C)
#define CM_WKUP_CM_CLKMODE_DPLL_DISP (CM_WKUP + 0x098)
#define CM_WKUP_I2C0_CLKCTRL (CM_WKUP + 0x0B8)
+#define CM_WKUP_ADC_TSC_CLKCTRL (CM_WKUP + 0x0BC)
#define CM_DPLL 0x500
#define CLKSEL_TIMER7_CLK (CM_DPLL + 0x004)
@@ -260,6 +261,9 @@
AM335X_GENERIC_CLOCK_DEV(I2C1_CLK),
AM335X_GENERIC_CLOCK_DEV(I2C2_CLK),
+ /* TSC_ADC */
+ AM335X_GENERIC_CLOCK_DEV(TSC_ADC_CLK),
+
/* EDMA */
AM335X_GENERIC_CLOCK_DEV(EDMA_TPCC_CLK),
AM335X_GENERIC_CLOCK_DEV(EDMA_TPTC0_CLK),
@@ -337,6 +341,9 @@
_CLK_DETAIL(I2C1_CLK, CM_PER_I2C1_CLKCTRL, 0),
_CLK_DETAIL(I2C2_CLK, CM_PER_I2C2_CLKCTRL, 0),
+ /* TSC_ADC module */
+ _CLK_DETAIL(TSC_ADC_CLK, CM_WKUP_ADC_TSC_CLKCTRL, 0),
+
/* EDMA modules */
_CLK_DETAIL(EDMA_TPCC_CLK, CM_PER_TPCC_CLKCTRL, 0),
_CLK_DETAIL(EDMA_TPTC0_CLK, CM_PER_TPTC0_CLKCTRL, 0),
Index: sys/arm/ti/am335x/files.beaglebone
===================================================================
--- sys/arm/ti/am335x/files.beaglebone (revision 262131)
+++ sys/arm/ti/am335x/files.beaglebone (working copy)
@@ -1,3 +1,4 @@
#$FreeBSD$
+arm/ti/am335x/am335x_adc.c optional am335x_adc
arm/ti/am335x/am335x_pmic.c optional am335x_pmic
Index: sys/arm/ti/ti_prcm.h
===================================================================
--- sys/arm/ti/ti_prcm.h (revision 262131)
+++ sys/arm/ti/ti_prcm.h (working copy)
@@ -162,6 +162,8 @@
PRUSS_CLK = 1700,
+ TSC_ADC_CLK = 1800,
+
INVALID_CLK_IDENT
} clk_ident_t;
--- /dev/null 2014-03-16 11:00:00.000000000 -0300
+++ sys/arm/ti/am335x/am335x_adc.c 2014-03-15 23:48:37.099205803 -0300
@@ -0,0 +1,497 @@
+/*-
+ * Copyright 2014 Luiz Otavio O Souza <loos at freebsd.org>
+ * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/sysctl.h>
+
+#include <machine/bus.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm/ti/ti_prcm.h>
+#include <arm/ti/am335x/am335x_adcreg.h>
+#include <arm/ti/am335x/am335x_adcvar.h>
+
+/* Define our 7 steps, one for each input channel. */
+static struct am335x_adc_input am335x_adc_inputs[AM335X_ADC_NPINS] = {
+ { .stepreg = ADC_STEPCFG1, },
+ { .stepreg = ADC_STEPCFG2, },
+ { .stepreg = ADC_STEPCFG3, },
+ { .stepreg = ADC_STEPCFG4, },
+ { .stepreg = ADC_STEPCFG5, },
+ { .stepreg = ADC_STEPCFG6, },
+ { .stepreg = ADC_STEPCFG7, },
+};
+
+static int am335x_adc_samples[5] = { 0, 2, 4, 8, 16 };
+
+static void
+am335x_adc_enable(struct am335x_adc_softc *sc)
+{
+ uint32_t val;
+
+ AM335X_ADC_LOCK_ASSERT(sc);
+
+ /* Enable the FIFO0 threshold interrupt. */
+ ADC_WRITE4(sc, ADC_IRQENABLE_SET, ADC_IRQ_FIFO0_THRES);
+
+ /* Enable the ADC. Run thru enabled steps, start the convertions. */
+ val = ADC_READ4(sc, ADC_CTRL);
+ ADC_WRITE4(sc, ADC_CTRL, val | ADC_CTRL_ENABLE);
+}
+
+static void
+am335x_adc_disable(struct am335x_adc_softc *sc)
+{
+ uint32_t val;
+
+ AM335X_ADC_LOCK_ASSERT(sc);
+
+ /* Disable the FIFO0 threshold interrupt. */
+ ADC_WRITE4(sc, ADC_IRQENABLE_CLR, ADC_IRQ_FIFO0_THRES);
+
+ /* Disable the ADC. */
+ val = ADC_READ4(sc, ADC_CTRL);
+ val &= ~ADC_CTRL_ENABLE;
+ ADC_WRITE4(sc, ADC_CTRL, val);
+}
+
+static void
+am335x_adc_enable_input(struct am335x_adc_softc *sc, int32_t input)
+{
+ uint32_t reg, val;
+
+ AM335X_ADC_LOCK_ASSERT(sc);
+
+ reg = am335x_adc_inputs[input].stepreg;
+ val = ADC_READ4(sc, reg);
+
+ /* Set the negative voltage reference. */
+ val &= ~ADC_STEP_RFM_MSK;
+ val |= ADC_STEP_RFM_VREFN << ADC_STEP_RFM_SHIFT;
+
+ /* Set the positive voltage reference. */
+ val &= ~ADC_STEP_RFP_MSK;
+ val |= ADC_STEP_RFP_VREFP << ADC_STEP_RFP_SHIFT;
+
+ /* Set the samples average. */
+ val &= ~ADC_STEP_AVG_MSK;
+ val |= am335x_adc_inputs[input].samples << ADC_STEP_AVG_SHIFT;
+
+ /* Select the desired input. */
+ val &= ~ADC_STEP_INP_MSK;
+ val |= input << ADC_STEP_INP_SHIFT;
+
+ /* Set the ADC to continuous mode. */
+ val &= ~ADC_STEP_MODE_MSK;
+ val |= ADC_STEP_MODE_CONTINUOUS;
+
+ ADC_WRITE4(sc, reg, val);
+}
+
+static void
+am335x_adc_disable_input(struct am335x_adc_softc *sc, int32_t input)
+{
+ uint32_t reg, val;
+
+ AM335X_ADC_LOCK_ASSERT(sc);
+
+ /* Reset the input read data. */
+ am335x_adc_inputs[input].value = 0;
+
+ reg = am335x_adc_inputs[input].stepreg;
+ val = ADC_READ4(sc, reg);
+
+ /* Reset the ADC operation mode. */
+ val &= ~ADC_STEP_MODE_MSK;
+
+ /* Reset the input pin selection. */
+ val &= ~ADC_STEP_INP_MSK;
+
+ /* Reset the samples average. */
+ val &= ~ADC_STEP_AVG_MSK;
+
+ /* Reset the positive voltage reference. */
+ val &= ~ADC_STEP_RFP_MSK;
+
+ /* Reset the negative voltage reference. */
+ val &= ~ADC_STEP_RFM_MSK;
+
+ ADC_WRITE4(sc, reg, val);
+}
+
+static void
+am335x_adc_reset(struct am335x_adc_softc *sc)
+{
+ int i;
+
+ AM335X_ADC_LOCK_ASSERT(sc);
+
+ /* Disable all the inputs. */
+ for (i = 0; i < AM335X_ADC_NPINS; i++)
+ am335x_adc_inputs[i].enable = 0;
+}
+
+static int
+am335x_adc_setup(struct am335x_adc_softc *sc)
+{
+ int enabled, i;
+
+ AM335X_ADC_LOCK_ASSERT(sc);
+
+ /* Check if we have any input enabled. */
+ enabled = 0;
+ for (i = 0; i < AM335X_ADC_NPINS; i++) {
+ if (am335x_adc_inputs[i].enable) {
+ enabled |= (1U << (i + 1));
+ am335x_adc_enable_input(sc, i);
+ } else
+ am335x_adc_disable_input(sc, i);
+ }
+
+ /* Enable the selected steps. */
+ ADC_WRITE4(sc, ADC_STEPENABLE, enabled);
+
+ /* Set the global ADC status. */
+ if (enabled != 0)
+ am335x_adc_enable(sc);
+ else
+ am335x_adc_disable(sc);
+
+ return (0);
+}
+
+static int
+am335x_adc_clockdiv_proc(SYSCTL_HANDLER_ARGS)
+{
+ int error, reg;
+ struct am335x_adc_softc *sc;
+
+ sc = (struct am335x_adc_softc *)arg1;
+
+ AM335X_ADC_LOCK(sc);
+ reg = (int)ADC_READ4(sc, ADC_CLKDIV) + 1;
+ AM335X_ADC_UNLOCK(sc);
+
+ error = sysctl_handle_int(oidp, ®, sizeof(reg), req);
+ if (error != 0 || req->newptr == NULL)
+ return (error);
+
+ /* The actual written value is the prescaler setting - 1. */
+ reg--;
+ if (reg < 0)
+ reg = 0;
+ if (reg > 65535)
+ reg = 65535;
+
+ AM335X_ADC_LOCK(sc);
+ /* Disable the ADC. */
+ am335x_adc_disable(sc);
+ /* Update the ADC prescaler setting. */
+ ADC_WRITE4(sc, ADC_CLKDIV, reg);
+ /* Enable the ADC again. */
+ am335x_adc_setup(sc);
+ AM335X_ADC_UNLOCK(sc);
+
+ return (0);
+}
+
+static int
+am335x_adc_enable_proc(SYSCTL_HANDLER_ARGS)
+{
+ int error;
+ int32_t enable;
+ struct am335x_adc_softc *sc;
+ struct am335x_adc_input *input;
+
+ input = (struct am335x_adc_input *)arg1;
+ sc = input->sc;
+
+ enable = input->enable;
+ error = sysctl_handle_int(oidp, &enable, sizeof(enable),
+ req);
+ if (error != 0 || req->newptr == NULL)
+ return (error);
+
+ if (enable)
+ enable = 1;
+
+ AM335X_ADC_LOCK(sc);
+ /* Setup the ADC as needed. */
+ if (input->enable != enable) {
+ input->enable = enable;
+ am335x_adc_setup(sc);
+ }
+ AM335X_ADC_UNLOCK(sc);
+
+ return (0);
+}
+
+static int
+am335x_adc_samples_avg_proc(SYSCTL_HANDLER_ARGS)
+{
+ int error, samples, i;
+ struct am335x_adc_softc *sc;
+ struct am335x_adc_input *input;
+
+ input = (struct am335x_adc_input *)arg1;
+ sc = input->sc;
+
+ if (input->samples > nitems(am335x_adc_samples))
+ input->samples = nitems(am335x_adc_samples);
+ samples = am335x_adc_samples[input->samples];
+
+ error = sysctl_handle_int(oidp, &samples, 0, req);
+ if (error != 0 || req->newptr == NULL)
+ return (error);
+
+ if (samples != am335x_adc_samples[input->samples]) {
+ AM335X_ADC_LOCK(sc);
+ am335x_adc_disable(sc);
+ input->samples = 0;
+ for (i = 0; i < nitems(am335x_adc_samples); i++)
+ if (samples >= am335x_adc_samples[i])
+ input->samples = i;
+
+ /* Update the ADC setup as needed. */
+ am335x_adc_setup(sc);
+ AM335X_ADC_UNLOCK(sc);
+ }
+
+ return (error);
+}
+
+static void
+am335x_adc_intr(void *arg)
+{
+ int count, input;
+ struct am335x_adc_softc *sc;
+ uint32_t data, status;
+
+ sc = (struct am335x_adc_softc *)arg;
+
+ status = ADC_READ4(sc, ADC_IRQSTATUS);
+ if (status & ~ADC_IRQ_FIFO0_THRES)
+ device_printf(sc->sc_dev, "stray interrupt: %#x\n", status);
+
+ /* Clear the interrupt. */
+ ADC_WRITE4(sc, ADC_IRQSTATUS, ADC_IRQ_FIFO0_THRES);
+
+ /* Read the available data. */
+ count = ADC_READ4(sc, ADC_FIFO0COUNT) & ADC_FIFO_COUNT_MSK;
+ while (count-- > 0) {
+ data = ADC_READ4(sc, ADC_FIFO0DATA);
+ input = (data & ADC_FIFO_STEP_ID_MSK) >> ADC_FIFO_STEP_ID_SHIFT;
+ am335x_adc_inputs[input].value = data & ADC_FIFO_DATA_MSK;
+ }
+}
+
+static void
+am335x_adc_sysctl_init(struct am335x_adc_softc *sc)
+{
+ char pinbuf[3];
+ struct sysctl_ctx_list *ctx;
+ struct sysctl_oid *tree_node, *inp_node, *inpN_node;
+ struct sysctl_oid_list *tree, *inp_tree, *inpN_tree;
+ int i;
+
+ /*
+ * Add per-pin sysctl tree/handlers.
+ */
+ ctx = device_get_sysctl_ctx(sc->sc_dev);
+ tree_node = device_get_sysctl_tree(sc->sc_dev);
+ tree = SYSCTL_CHILDREN(tree_node);
+ SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "clockdiv",
+ CTLFLAG_RW | CTLTYPE_UINT, sc, 0,
+ am335x_adc_clockdiv_proc, "IU", "ADC clock prescaler");
+ inp_node = SYSCTL_ADD_NODE(ctx, tree, OID_AUTO, "ain",
+ CTLFLAG_RD, NULL, "ADC inputs");
+ inp_tree = SYSCTL_CHILDREN(inp_node);
+
+ for (i = 0; i < AM335X_ADC_NPINS; i++) {
+
+ snprintf(pinbuf, sizeof(pinbuf), "%d", i);
+ inpN_node = SYSCTL_ADD_NODE(ctx, inp_tree, OID_AUTO, pinbuf,
+ CTLFLAG_RD, NULL, "ADC input");
+ inpN_tree = SYSCTL_CHILDREN(inpN_node);
+
+ am335x_adc_inputs[i].sc = sc;
+ am335x_adc_inputs[i].input = i;
+ am335x_adc_inputs[i].value = 0;
+ am335x_adc_inputs[i].enable = 0;
+ am335x_adc_inputs[i].samples = 0;
+ SYSCTL_ADD_PROC(ctx, inpN_tree, OID_AUTO, "enable",
+ CTLFLAG_RW | CTLTYPE_UINT, &am335x_adc_inputs[i], 0,
+ am335x_adc_enable_proc, "IU", "Enable ADC input");
+ SYSCTL_ADD_PROC(ctx, inpN_tree, OID_AUTO, "samples_avg",
+ CTLFLAG_RW | CTLTYPE_UINT, &am335x_adc_inputs[i], 0,
+ am335x_adc_samples_avg_proc, "IU", "ADC samples average");
+ SYSCTL_ADD_INT(ctx, inpN_tree, OID_AUTO, "input",
+ CTLFLAG_RD, &am335x_adc_inputs[i].value, 0,
+ "Converted value for the ADC input");
+ }
+}
+
+static int
+am335x_adc_probe(device_t dev)
+{
+
+ if (!ofw_bus_is_compatible(dev, "ti,am335x-adc"))
+ return (ENXIO);
+ device_set_desc(dev, "AM335x ADC controller");
+
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+am335x_adc_attach(device_t dev)
+{
+ int err, rid;
+ struct am335x_adc_softc *sc;
+ uint32_t reg, rev;
+
+ sc = device_get_softc(dev);
+ sc->sc_dev = dev;
+
+ rid = 0;
+ sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE);
+ if (!sc->sc_mem_res) {
+ device_printf(dev, "cannot allocate memory window\n");
+ return (ENXIO);
+ }
+
+ rid = 0;
+ sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+ RF_ACTIVE);
+ if (!sc->sc_irq_res) {
+ bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
+ device_printf(dev, "cannot allocate interrupt\n");
+ return (ENXIO);
+ }
+
+ if (bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
+ NULL, am335x_adc_intr, sc, &sc->sc_intrhand) != 0) {
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res);
+ bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
+ device_printf(dev, "Unable to setup the irq handler.\n");
+ return (ENXIO);
+ }
+
+ /* Activate the ADC_TSC module. */
+ err = ti_prcm_clk_enable(TSC_ADC_CLK);
+ if (err)
+ return (err);
+
+ /* Check the ADC revision. */
+ rev = ADC_READ4(sc, ADC_REVISION);
+ device_printf(dev,
+ "scheme: %#x func: %#x rtl: %d rev: %d.%d custom rev: %d\n",
+ (rev & ADC_REV_SCHEME_MSK) >> ADC_REV_SCHEME_SHIFT,
+ (rev & ADC_REV_FUNC_MSK) >> ADC_REV_FUNC_SHIFT,
+ (rev & ADC_REV_RTL_MSK) >> ADC_REV_RTL_SHIFT,
+ (rev & ADC_REV_MAJOR_MSK) >> ADC_REV_MAJOR_SHIFT,
+ rev & ADC_REV_MINOR_MSK,
+ (rev & ADC_REV_CUSTOM_MSK) >> ADC_REV_CUSTOM_SHIFT);
+
+ /*
+ * Disable the step write protect and make it store the step ID for
+ * the captured data on FIFO.
+ */
+ reg = ADC_READ4(sc, ADC_CTRL);
+ ADC_WRITE4(sc, ADC_CTRL, reg | ADC_CTRL_STEP_WP | ADC_CTRL_STEP_ID);
+
+ /*
+ * Set the ADC prescaler to 2000 (yes, the actual value written here
+ * is 2000 - 1).
+ */
+ ADC_WRITE4(sc, ADC_CLKDIV, 1999);
+
+ AM335X_ADC_LOCK_INIT(sc);
+
+ am335x_adc_sysctl_init(sc);
+
+ return (0);
+}
+
+static int
+am335x_adc_detach(device_t dev)
+{
+ struct am335x_adc_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ /* Turn off the ADC. */
+ AM335X_ADC_LOCK(sc);
+ am335x_adc_reset(sc);
+ am335x_adc_setup(sc);
+ AM335X_ADC_UNLOCK(sc);
+
+ AM335X_ADC_LOCK_DESTROY(sc);
+
+ if (sc->sc_intrhand)
+ bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_intrhand);
+ if (sc->sc_irq_res)
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res);
+ if (sc->sc_mem_res)
+ bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
+
+ return (bus_generic_detach(dev));
+}
+
+static device_method_t am335x_adc_methods[] = {
+ DEVMETHOD(device_probe, am335x_adc_probe),
+ DEVMETHOD(device_attach, am335x_adc_attach),
+ DEVMETHOD(device_detach, am335x_adc_detach),
+
+ DEVMETHOD_END
+};
+
+static driver_t am335x_adc_driver = {
+ "am335x_adc",
+ am335x_adc_methods,
+ sizeof(struct am335x_adc_softc),
+};
+
+static devclass_t am335x_adc_devclass;
+
+DRIVER_MODULE(am335x_adc, simplebus, am335x_adc_driver, am335x_adc_devclass, 0, 0);
+MODULE_VERSION(am335x_adc, 1);
+MODULE_DEPEND(am335x_adc, simplebus, 1, 1, 1);
--- /dev/null 2014-03-16 11:00:00.000000000 -0300
+++ sys/arm/ti/am335x/am335x_adcreg.h 2014-03-16 11:07:47.204396970 -0300
@@ -0,0 +1,105 @@
+/*-
+ * Copyright 2014 Luiz Otavio O Souza <loos at freebsd.org>
+ * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _AM335X_ADCREG_H_
+#define _AM335X_ADCREG_H_
+
+#define ADC_REVISION 0x000
+#define ADC_REV_SCHEME_MSK 0xc0000000
+#define ADC_REV_SCHEME_SHIFT 30
+#define ADC_REV_FUNC_MSK 0x0fff0000
+#define ADC_REV_FUNC_SHIFT 16
+#define ADC_REV_RTL_MSK 0x0000f800
+#define ADC_REV_RTL_SHIFT 11
+#define ADC_REV_MAJOR_MSK 0x00000700
+#define ADC_REV_MAJOR_SHIFT 8
+#define ADC_REV_CUSTOM_MSK 0x000000c0
+#define ADC_REV_CUSTOM_SHIFT 6
+#define ADC_REV_MINOR_MSK 0x0000003f
+#define ADC_SYSCFG 0x010
+#define ADC_SYSCFG_IDLE_MSK 0x000000c0
+#define ADC_SYSCFG_IDLE_SHIFT 2
+#define ADC_IRQSTATUS_RAW 0x024
+#define ADC_IRQSTATUS 0x028
+#define ADC_IRQENABLE_SET 0x02c
+#define ADC_IRQENABLE_CLR 0x030
+#define ADC_IRQ_HW_PEN_SYNC (1 << 10)
+#define ADC_IRQ_PEN_UP (1 << 9)
+#define ADC_IRQ_OUT_RANGE (1 << 8)
+#define ADC_IRQ_FIFO1_UNDR (1 << 7)
+#define ADC_IRQ_FIFO1_OVERR (1 << 6)
+#define ADC_IRQ_FIFO1_THRES (1 << 5)
+#define ADC_IRQ_FIFO0_UNDR (1 << 4)
+#define ADC_IRQ_FIFO0_OVERR (1 << 3)
+#define ADC_IRQ_FIFO0_THRES (1 << 2)
+#define ADC_IRQ_END_OF_SEQ (1 << 1)
+#define ADC_IRQ_HW_PEN_ASYNC (1 << 0)
+#define ADC_CTRL 0x040
+#define ADC_CTRL_STEP_WP 0x00000004
+#define ADC_CTRL_STEP_ID 0x00000002
+#define ADC_CTRL_ENABLE 0x00000001
+#define ADC_CLKDIV 0x04c
+#define ADC_STEPENABLE 0x054
+#define ADC_STEPCFG1 0x064
+#define ADC_STEPCFG2 0x06c
+#define ADC_STEPCFG3 0x074
+#define ADC_STEPCFG4 0x07c
+#define ADC_STEPCFG5 0x084
+#define ADC_STEPCFG6 0x08c
+#define ADC_STEPCFG7 0x094
+#define ADC_STEP_RFM_MSK 0x01800000
+#define ADC_STEP_RFM_SHIFT 23
+#define ADC_STEP_RFM_VSSA 0
+#define ADC_STEP_RFM_XNUR 1
+#define ADC_STEP_RFM_YNLR 2
+#define ADC_STEP_RFM_VREFN 3
+#define ADC_STEP_INP_MSK 0x00780000
+#define ADC_STEP_INP_SHIFT 19
+#define ADC_STEP_INM_MSK 0x00078000
+#define ADC_STEP_INM_SHIFT 15
+#define ADC_STEP_RFP_MSK 0x00007000
+#define ADC_STEP_RFP_SHIFT 12
+#define ADC_STEP_RFP_VDDA 0
+#define ADC_STEP_RFP_XPUL 1
+#define ADC_STEP_RFP_YPLL 2
+#define ADC_STEP_RFP_VREFP 3
+#define ADC_STEP_RFP_INTREF 4
+#define ADC_STEP_AVG_MSK 0x0000001c
+#define ADC_STEP_AVG_SHIFT 2
+#define ADC_STEP_MODE_MSK 0x00000003
+#define ADC_STEP_MODE_ONESHOT 0x00000000
+#define ADC_STEP_MODE_CONTINUOUS 0x00000001
+#define ADC_FIFO0COUNT 0x0e4
+#define ADC_FIFO0THRESHOLD 0x0e8
+#define ADC_FIFO0DATA 0x100
+#define ADC_FIFO_COUNT_MSK 0x0000007f
+#define ADC_FIFO_STEP_ID_MSK 0x000f0000
+#define ADC_FIFO_STEP_ID_SHIFT 16
+#define ADC_FIFO_DATA_MSK 0x00000fff
+
+#endif /* _AM335X_ADCREG_H_ */
--- /dev/null 2014-03-16 11:00:00.000000000 -0300
+++ sys/arm/ti/am335x/am335x_adcvar.h 2014-03-15 22:26:47.313542959 -0300
@@ -0,0 +1,67 @@
+/*-
+ * Copyright 2014 Luiz Otavio O Souza <loos at freebsd.org>
+ * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _AM335X_ADCVAR_H_
+#define _AM335X_ADCVAR_H_
+
+#define AM335X_ADC_NPINS 7
+
+#define ADC_READ4(_sc, reg) bus_read_4((_sc)->sc_mem_res, reg)
+#define ADC_WRITE4(_sc, reg, value) \
+ bus_write_4((_sc)->sc_mem_res, reg, value)
+
+struct am335x_adc_softc {
+ device_t sc_dev;
+ struct mtx sc_mtx;
+ struct resource *sc_mem_res;
+ struct resource *sc_irq_res;
+ void *sc_intrhand;
+};
+
+struct am335x_adc_input {
+ int32_t enable; /* input enabled */
+ int32_t samples; /* samples average */
+ int32_t input; /* input number */
+ int32_t value; /* raw converted value */
+ uint32_t stepreg; /* step register */
+ struct am335x_adc_softc *sc; /* pointer to adc softc */
+};
+
+#define AM335X_ADC_LOCK(_sc) \
+ mtx_lock(&(_sc)->sc_mtx)
+#define AM335X_ADC_UNLOCK(_sc) \
+ mtx_unlock(&(_sc)->sc_mtx)
+#define AM335X_ADC_LOCK_INIT(_sc) \
+ mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), \
+ "am335x_adc", MTX_DEF)
+#define AM335X_ADC_LOCK_DESTROY(_sc) \
+ mtx_destroy(&_sc->sc_mtx);
+#define AM335X_ADC_LOCK_ASSERT(_sc) \
+ mtx_assert(&(_sc)->sc_mtx, MA_OWNED)
+
+#endif /* _AM335X_ADCVAR_H_ */
Index: sys/boot/fdt/dts/am335x.dtsi
===================================================================
--- sys/boot/fdt/dts/am335x.dtsi (revision 262131)
+++ sys/boot/fdt/dts/am335x.dtsi (working copy)
@@ -75,6 +75,13 @@
interrupt-parent = <&AINTC>;
};
+ adc0: adc at 44E0D000 {
+ compatible = "ti,am335x-adc";
+ reg = <0x44E0D000 0x2000>;
+ interrupts = < 16 >;
+ interrupt-parent = <&AINTC>;
+ };
+
GPIO: gpio {
#gpio-cells = <3>;
compatible = "ti,gpio";
Index: sys/arm/conf/BEAGLEBONE
===================================================================
--- sys/arm/conf/BEAGLEBONE (revision 262131)
+++ sys/arm/conf/BEAGLEBONE (working copy)
@@ -103,6 +103,9 @@
device gpio
device gpioled
+# ADC support
+device am335x_adc
+
# USB support
device usb
options USB_HOST_ALIGN=64 # Cacheline size is 64 on AM335x.
More information about the freebsd-arm
mailing list