📄 mxcspi.c
字号:
/* * $QNXLicenseC: * Copyright 2007, QNX Software Systems. * * Licensed under the Apache License, Version 2.0 (the "License"). You * may not reproduce, modify or distribute this software except in * compliance with the License. You may obtain a copy of the License * at: http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTIES OF ANY KIND, either express or implied. * * This file may contain contributions from others, either as * contributors under the License or as licensors under other terms. * Please review this entire file for other proprietary rights or license * notices, as well as the QNX Development Suite License Guide at * http://licensing.qnx.com/license-guide/ for other information. * $ */#include "mxcspi.h"static char *mx21_opts[] = { "base", /* Base address for this CSPI controller */ "irq", /* IRQ for this CSPI intereface */ "clock", /* CSPI clock */ "period", /* CSPI sample period clock */ NULL};spi_funcs_t spi_drv_entry = { sizeof(spi_funcs_t), mx21_init, /* init() */ mx21_dinit, /* fini() */ mx21_drvinfo, /* drvinfo() */ mx21_devinfo, /* devinfo() */ mx21_setcfg, /* setcfg() */ mx21_xfer, /* xfer() */ NULL /* dma_xfer() */};/* * Note: * The devices listed are just examples, users should change * this according to their own hardware spec. */static spi_devinfo_t devlist[4] = { { 0x00, // Device ID, for SS0 "CSPI-DEV0", // Description { 16 | SPI_MODE_BODER_MSB, // data length 16bit, MSB 5000000 // Clock rate 5M }, }, { 0x01, // Device ID, for SS1 "CSPI-DEV1", // Description { 16 | SPI_MODE_BODER_MSB, // data length 16bit, MSB 5000000 // Clock rate 5M }, }, { 0x02, // Device ID, for SS2 "CSPI-DEV2", // Description { 16 | SPI_MODE_BODER_MSB, // data length 16bit, MSB 5000000 // Clock rate 5M }, },};static uint32_t devctrl[3];static int mx21_options(mx21_cspi_t *dev, char *optstring){ int opt, rc = 0, err = EOK; char *options, *freeptr, *c, *value; if (optstring == NULL) return 0; freeptr = options = strdup(optstring); while (options && *options != '\0') { c = options; if ((opt = getsubopt(&options, mx21_opts, &value)) == -1) goto error; switch (opt) { case 0: dev->pbase = strtoul(value, 0, 0); continue; case 1: dev->irq = strtoul(value, 0, 0); continue; case 2: dev->clock = strtoul(value, 0, 0); continue; case 3: if (strncmp(value, "32K=", 4) == 0) { dev->period = 0x8000; value += 4; } dev->period |= strtoul(value, 0, 0); continue; }error: fprintf(stderr, "spi-mx21: unknown option %s", c); err = EINVAL; rc = -1; } free(freeptr); return rc;}void *mx21_init(void *hdl, char *options){ mx21_cspi_t *dev; uintptr_t base; int i; dev = calloc(1, sizeof(mx21_cspi_t)); if (dev == NULL) return NULL; dev->pbase = 0x1000F000;//MX21_CSPI1_BASE; dev->irq = 15; //16; dev->clock = 33250000; /* 33.25 MHz CSPI clock */ if (mx21_options(dev, options)) goto fail0; /* * Map in SPI and EDMA register */ if ((base = mmap_device_io(0x20, dev->pbase)) == (uintptr_t)MAP_FAILED) goto fail0; dev->vbase = base; /* * Perform a software reset */ out32(base + MX21_CSPI_RESETREG, 0x01); delay(1); out32(base + MX21_CSPI_PERIODREG, 0x00000000); /* FIXME commandline option ? */ /* * Calculate all device configuration here */ for (i = 0; i < 3; i++) devctrl[i] = mx21_cfg(dev, &devlist[i].cfg); /* * Attach SPI interrupt */ if (mx21_attach_intr(dev)) goto fail1; dev->spi.hdl = hdl; return dev;fail1: munmap_device_io(dev->vbase, 0x20);fail0: free(dev); return NULL;}void mx21_dinit(void *hdl){ mx21_cspi_t *dev = hdl; /* * unmap the register, detach the interrupt */ InterruptDetach(dev->iid); ConnectDetach(dev->coid); ChannelDestroy(dev->chid); /* * Disable SPI */ out32(dev->vbase + MX21_CSPI_RESETREG, 0x01); munmap_device_io(dev->vbase, 0x20); free(hdl);}int mx21_drvinfo(void *hdl, spi_drvinfo_t *info){ info->version = (SPI_VERSION_MAJOR << SPI_VERMAJOR_SHIFT) | (SPI_VERSION_MINOR << SPI_VERMINOR_SHIFT) | (SPI_REVISION << SPI_VERREV_SHIFT); strcpy(info->name, "MX21 CSPI"); info->feature = 0; return (EOK);}int mx21_setcfg(void *hdl, uint16_t device, spi_cfg_t *cfg){ uint32_t control; if (device > 2) return (EINVAL); memcpy(&devlist[device].cfg, cfg, sizeof(spi_cfg_t)); control = mx21_cfg(hdl, &devlist[device].cfg); if (control == 0) return (EINVAL); devctrl[device] = control; return (EOK);}int mx21_devinfo(void *hdl, uint32_t device, spi_devinfo_t *info){ int dev = device & SPI_DEV_ID_MASK; if (!(device & SPI_DEV_DEFAULT)) { if (dev != SPI_DEV_ID_NONE) dev++; else dev = 0; } if (dev > 2) return (EINVAL); memcpy(info, &devlist[dev], sizeof(spi_devinfo_t)); return (EOK);}void *mx21_xfer(void *hdl, uint32_t device, uint8_t *buf, int *len){ mx21_cspi_t *dev = hdl; uintptr_t base = dev->vbase; uint32_t ctrl, i, id; id = device & SPI_DEV_ID_MASK; if (id > 2) { *len = -1; return buf; } dev->xlen = *len; dev->rlen = 0; dev->pbuf = buf; dev->dlen = ((devlist[id].cfg.mode & 0x1F) + 7) >> 3; dev->dtime = dev->dlen * 8 * 1000 * 1000 / devlist[id].cfg.clock_rate; ctrl = devctrl[id] | (id << 19); out32(base + MX21_CSPI_CONREG, ctrl | (1 << 11)); /* Flush FIFO */ out32(base + MX21_CSPI_CONREG, ctrl | (1 << 10) | (1 << 11)); /* Enable SPI */ for (dev->tlen = 0, i = 0; i < 8; i++) { if (dev->tlen >= dev->xlen) break; switch (dev->dlen) { case 1: out32(base + MX21_CSPI_TXDATA, buf[dev->tlen]); dev->tlen++; break; case 2: out32(base + MX21_CSPI_TXDATA, *(uint16_t *)(&buf[dev->tlen])); dev->tlen += 2; break; case 3: case 4: out32(base + MX21_CSPI_TXDATA, *(uint32_t *)(&buf[dev->tlen])); dev->tlen += 4; break; } } /* * Enable interrupt */ if (i >= 4) out32(base + MX21_CSPI_INTREG, 1 << 14); /* Enable RxFIFO half interrupt */ else out32(base + MX21_CSPI_INTREG, 1 << 12); /* Enable RxFIFO data ready interrupt */ out32(base + MX21_CSPI_CONREG, ctrl | (1 << 9) | (1 << 10) | (1 << 11)); /* Start exchange */ /* * Wait for exchange to finish with timeout */ if (mx21_wait(dev, dev->xlen * 10)) dev->rlen = -1; /* * Disable CSPI */ out32(base + MX21_CSPI_CONREG, 1 << 11); *len = dev->rlen; return buf;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -