1/*- 2 * Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27/* 28 * Vybrid Family 12-bit Analog to Digital Converter (ADC) 29 * Chapter 37, Vybrid Reference Manual, Rev. 5, 07/2013 30 */ 31 32#include <sys/cdefs.h> 33__FBSDID("$FreeBSD$"); 34 35#include <sys/param.h> 36#include <sys/systm.h> 37#include <sys/bus.h> 38#include <sys/kernel.h> 39#include <sys/module.h> 40#include <sys/malloc.h> 41#include <sys/rman.h> 42#include <sys/timeet.h> 43#include <sys/timetc.h> 44 45#include <dev/ofw/openfirm.h> 46#include <dev/ofw/ofw_bus.h> 47#include <dev/ofw/ofw_bus_subr.h> 48 49#include <machine/bus.h> 50#include <machine/cpu.h> 51#include <machine/intr.h> 52 53#include <arm/freescale/vybrid/vf_common.h> 54#include <arm/freescale/vybrid/vf_adc.h> 55 56#define ADC_HC0 0x00 /* Ctrl reg for hardware triggers */ 57#define ADC_HC1 0x04 /* Ctrl reg for hardware triggers */ 58#define HC_AIEN (1 << 7) /* Conversion Complete Int Control */ 59#define HC_ADCH_M 0x1f /* Input Channel Select Mask */ 60#define HC_ADCH_S 0 /* Input Channel Select Shift */ 61#define ADC_HS 0x08 /* Status register for HW triggers */ 62#define HS_COCO0 (1 << 0) /* Conversion Complete Flag */ 63#define HS_COCO1 (1 << 1) /* Conversion Complete Flag */ 64#define ADC_R0 0x0C /* Data result reg for HW triggers */ 65#define ADC_R1 0x10 /* Data result reg for HW triggers */ 66#define ADC_CFG 0x14 /* Configuration register */ 67#define CFG_OVWREN (1 << 16) /* Data Overwrite Enable */ 68#define CFG_AVGS_M 0x3 /* Hardware Average select Mask */ 69#define CFG_AVGS_S 14 /* Hardware Average select Shift */ 70#define CFG_ADTRG (1 << 13) /* Conversion Trigger Select */ 71#define CFG_REFSEL_M 0x3 /* Voltage Reference Select Mask */ 72#define CFG_REFSEL_S 11 /* Voltage Reference Select Shift */ 73#define CFG_ADHSC (1 << 10) /* High Speed Configuration */ 74#define CFG_ADSTS_M 0x3 /* Defines the sample time duration */ 75#define CFG_ADSTS_S 8 /* Defines the sample time duration */ 76#define CFG_ADLPC (1 << 7) /* Low-Power Configuration */ 77#define CFG_ADIV_M 0x3 /* Clock Divide Select */ 78#define CFG_ADIV_S 5 /* Clock Divide Select */ 79#define CFG_ADLSMP (1 << 4) /* Long Sample Time Configuration */ 80#define CFG_MODE_M 0x3 /* Conversion Mode Selection Mask */ 81#define CFG_MODE_S 2 /* Conversion Mode Selection Shift */ 82#define CFG_MODE_12 0x2 /* 12-bit mode */ 83#define CFG_ADICLK_M 0x3 /* Input Clock Select Mask */ 84#define CFG_ADICLK_S 0 /* Input Clock Select Shift */ 85#define ADC_GC 0x18 /* General control register */ 86#define GC_CAL (1 << 7) /* Calibration */ 87#define GC_ADCO (1 << 6) /* Continuous Conversion Enable */ 88#define GC_AVGE (1 << 5) /* Hardware average enable */ 89#define GC_ACFE (1 << 4) /* Compare Function Enable */ 90#define GC_ACFGT (1 << 3) /* Compare Function Greater Than En */ 91#define GC_ACREN (1 << 2) /* Compare Function Range En */ 92#define GC_DMAEN (1 << 1) /* DMA Enable */ 93#define GC_ADACKEN (1 << 0) /* Asynchronous clock output enable */ 94#define ADC_GS 0x1C /* General status register */ 95#define GS_AWKST (1 << 2) /* Asynchronous wakeup int status */ 96#define GS_CALF (1 << 1) /* Calibration Failed Flag */ 97#define GS_ADACT (1 << 0) /* Conversion Active */ 98#define ADC_CV 0x20 /* Compare value register */ 99#define CV_CV2_M 0xfff /* Compare Value 2 Mask */ 100#define CV_CV2_S 16 /* Compare Value 2 Shift */ 101#define CV_CV1_M 0xfff /* Compare Value 1 Mask */ 102#define CV_CV1_S 0 /* Compare Value 1 Shift */ 103#define ADC_OFS 0x24 /* Offset correction value register */ 104#define OFS_SIGN 12 /* Sign bit */ 105#define OFS_M 0xfff /* Offset value Mask */ 106#define OFS_S 0 /* Offset value Shift */ 107#define ADC_CAL 0x28 /* Calibration value register */ 108#define CAL_CODE_M 0xf /* Calibration Result Value Mask */ 109#define CAL_CODE_S 0 /* Calibration Result Value Shift */ 110#define ADC_PCTL 0x30 /* Pin control register */ 111 112struct adc_softc { 113 struct resource *res[2]; 114 bus_space_tag_t bst; 115 bus_space_handle_t bsh; 116 void *ih; 117}; 118 119struct adc_softc *adc_sc; 120 121static struct resource_spec adc_spec[] = { 122 { SYS_RES_MEMORY, 0, RF_ACTIVE }, 123 { SYS_RES_IRQ, 0, RF_ACTIVE }, 124 { -1, 0 } 125}; 126 127static int 128adc_probe(device_t dev) 129{ 130 131 if (!ofw_bus_status_okay(dev)) 132 return (ENXIO); 133 134 if (!ofw_bus_is_compatible(dev, "fsl,mvf600-adc")) 135 return (ENXIO); 136 137 device_set_desc(dev, "Vybrid Family " 138 "12-bit Analog to Digital Converter"); 139 return (BUS_PROBE_DEFAULT); 140} 141 142static void 143adc_intr(void *arg) 144{ 145 struct adc_softc *sc; 146 147 sc = arg; 148 149 /* Conversation complete */ 150} 151 152uint32_t 153adc_read(void) 154{ 155 struct adc_softc *sc; 156 157 sc = adc_sc; 158 if (sc == NULL) 159 return (0); 160 161 return (READ4(sc, ADC_R0)); 162} 163 164uint32_t 165adc_enable(int channel) 166{ 167 struct adc_softc *sc; 168 int reg; 169 170 sc = adc_sc; 171 if (sc == NULL) 172 return (1); 173 174 reg = READ4(sc, ADC_HC0); 175 reg &= ~(HC_ADCH_M << HC_ADCH_S); 176 reg |= (channel << HC_ADCH_S); 177 WRITE4(sc, ADC_HC0, reg); 178 179 return (0); 180} 181 182static int 183adc_attach(device_t dev) 184{ 185 struct adc_softc *sc; 186 int err; 187 int reg; 188 189 sc = device_get_softc(dev); 190 191 if (bus_alloc_resources(dev, adc_spec, sc->res)) { 192 device_printf(dev, "could not allocate resources\n"); 193 return (ENXIO); 194 } 195 196 /* Memory interface */ 197 sc->bst = rman_get_bustag(sc->res[0]); 198 sc->bsh = rman_get_bushandle(sc->res[0]); 199 200 adc_sc = sc; 201 202 /* Setup interrupt handler */ 203 err = bus_setup_intr(dev, sc->res[1], INTR_TYPE_BIO | INTR_MPSAFE, 204 NULL, adc_intr, sc, &sc->ih); 205 if (err) { 206 device_printf(dev, "Unable to alloc interrupt resource.\n"); 207 return (ENXIO); 208 } 209 210 /* Configure 12-bit mode */ 211 reg = READ4(sc, ADC_CFG); 212 reg &= ~(CFG_MODE_M << CFG_MODE_S); 213 reg |= (CFG_MODE_12 << CFG_MODE_S); /* 12bit */ 214 WRITE4(sc, ADC_CFG, reg); 215 216 /* Configure for continuous conversion */ 217 reg = READ4(sc, ADC_GC); 218 reg |= (GC_ADCO | GC_AVGE); 219 WRITE4(sc, ADC_GC, reg); 220 221 /* Disable interrupts */ 222 reg = READ4(sc, ADC_HC0); 223 reg &= HC_AIEN; 224 WRITE4(sc, ADC_HC0, reg); 225 226 return (0); 227} 228 229static device_method_t adc_methods[] = { 230 DEVMETHOD(device_probe, adc_probe), 231 DEVMETHOD(device_attach, adc_attach), 232 { 0, 0 } 233}; 234 235static driver_t adc_driver = { 236 "adc", 237 adc_methods, 238 sizeof(struct adc_softc), 239}; 240 241static devclass_t adc_devclass; 242 243DRIVER_MODULE(adc, simplebus, adc_driver, adc_devclass, 0, 0); 244