/* vim: set ts=4 sw=4 et fdm=marker: */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "vxbSm2130SpiDev.h" #include #define SPI_DEV_MUTEX_OPT (SEM_Q_PRIORITY | SEM_DELETE_SAFE | SEM_INVERSION_SAFE) typedef struct _Sm2310_DEV_HANDLE { DEV_HDR devHdr; SEL_WAKEUP_LIST selList; SM2130_SPI_DEV *pDevCtrl; } SM2310_DEV_HANDLE; LOCAL int sm2130_driver_node = -1; /* locals */ LOCAL void sm2130SpiDevShow(VXB_DEVICE_ID pDev, int verbose); LOCAL INT32 sm2130BusDevRead(VXB_DEVICE_ID pDev, UINT8 cmd); LOCAL STATUS sm2130BusDevWrite(VXB_DEVICE_ID pDev, UINT8 cmd, UINT16 var); /* VxBus methods */ LOCAL void sm2130SpiDevInstInit(VXB_DEVICE_ID pDev); LOCAL void sm2130SpiDevInstInit2(VXB_DEVICE_ID pDev); LOCAL void sm2130SpiDevInstConnect(VXB_DEVICE_ID pDev); LOCAL STATUS sm2130SpiDevInstUnlink(VXB_DEVICE_ID pDev, void *unused); /* Structs */ LOCAL struct drvBusFuncs sm2130SpiDevFuncs = { sm2130SpiDevInstInit, /* devInstanceInit */ sm2130SpiDevInstInit2, /* devInstanceInit2 */ sm2130SpiDevInstConnect /* devConnect */ }; /* Publish the methods for the resources controlled with this file */ /* clang-format off */ LOCAL struct vxbDeviceMethod sm2130SpiDevMethods[] = { DEVMETHOD(busDevShow , sm2130SpiDevShow), DEVMETHOD(vxbDrvUnlink, sm2130SpiDevInstUnlink), { 0, 0 } }; LOCAL struct vxbSpiRegister sm2130SpiDevRegister = { { NULL, /* pNext */ VXB_DEVID_DEVICE, /* devID */ VXB_BUSID_SPI, /* busID = SPI */ VXB_VER_4_0_0, /* vxbVersion */ SPI_DEV_SM2130, /* drvName */ &sm2130SpiDevFuncs, /* pDrvBusFuncs */ sm2130SpiDevMethods, /* pMethods */ NULL, /* devProbe */ NULL, /* pParamDefaults */ }, }; /* clang-format on */ /* * * vxbSm2130SpiDevRegister - register with the VxBus subsystem * * This routine registers the driver to VxBus Systems. * * RETURNS: N/A * * ERRNO: N/A * * \NOMANUAL */ void vxbSm2130SpiDevRegister(void) { (void)vxbDevRegister((struct vxbDevRegInfo *)&sm2130SpiDevRegister); } /* * * sm2130SpiDevInstInit - first level initialization routine of spi flash device * * RETURNS: N/A * * ERRNO: N/A */ LOCAL void sm2130SpiDevInstInit(VXB_DEVICE_ID pDev) { SM2130_SPI_DEV *pDrvCtrl; struct hcfDevice *pHcf; /* Check for vaild parameter */ VXB_ASSERT_NONNULL_V(pDev); pDrvCtrl = (SM2130_SPI_DEV *)hwMemAlloc(sizeof(SM2130_SPI_DEV)); if (pDrvCtrl == NULL) { return; } pDrvCtrl->pDev = pDev; pDev->pDrvCtrl = pDrvCtrl; pDrvCtrl->devHandle = NULL; snprintf(pDrvCtrl->name, sizeof (pDrvCtrl->name), "%s/%d", SM2130_DEV_NAME, pDev->unitNumber); pDrvCtrl->devName = pDrvCtrl->name; pHcf = (struct hcfDevice *)hcfDeviceGet(pDev); if (pHcf) { if (devResourceGet(pHcf, "devName", HCF_RES_STRING, (void *)&pDrvCtrl->devName) != OK) { pDrvCtrl->devName = pDrvCtrl->name; } } pDrvCtrl->read = sm2130BusDevRead; pDrvCtrl->write = sm2130BusDevWrite; vxbNextUnitGet(pDev); } /* {{{ device driver api */ LOCAL SM2310_DEV_HANDLE *drv1553bOpen(SM2310_DEV_HANDLE *dev, const char *name, int flags, int mode) { SM2130_SPI_DEV *pDrvCtrl = dev->pDevCtrl; (void)semTake(pDrvCtrl->muteSem, WAIT_FOREVER); ++pDrvCtrl->refcount; (void)semGive(pDrvCtrl->muteSem); return dev; } LOCAL int drv1553bClose(SM2310_DEV_HANDLE *dev) { SM2130_SPI_DEV *pDrvCtrl = dev->pDevCtrl; (void)semTake(pDrvCtrl->muteSem, WAIT_FOREVER); --pDrvCtrl->refcount; (void)semGive(pDrvCtrl->muteSem); return (OK); } LOCAL int drv1553bIoctl(SM2310_DEV_HANDLE *dev, int cmd, _Vx_ioctl_arg_t arg) { SM2130_XFER *xfer; SM2130_SPI_DEV *pDrvCtrl = dev->pDevCtrl; STATUS ret = OK; (void)semTake(pDrvCtrl->muteSem, WAIT_FOREVER); switch (cmd) { case FIOSELECT: ret = selNodeAdd(&dev->selList, (SEL_WAKEUP_NODE *)arg); break; case FIOUNSELECT: ret = selNodeDelete(&dev->selList, (SEL_WAKEUP_NODE *)arg); break; case FIO_XFER: xfer = (SM2130_XFER *)(arg); switch (xfer->type) { case FIO_WR: pDrvCtrl->write(pDrvCtrl->pDev, xfer->reg, xfer->val); break; case FIO_RD: xfer->val = pDrvCtrl->read(pDrvCtrl->pDev, xfer->reg); break; default: errnoSet(EINVAL); ret = ERROR; } break; default: printf("sm2130 unsupported ioctl: %d\r\n", cmd); errnoSet(ENOTSUP); ret = ERROR; break; } semGive(pDrvCtrl->muteSem); return (ret); } /* }}} */ /* * * sm2130SpiDevInstInit2 - first level initialization routine of spi flash device * * * RETURNS: N/A * * ERRNO: N/A */ LOCAL void sm2130SpiDevInstInit2(VXB_DEVICE_ID pDev) { SM2130_SPI_DEV *pDrvCtrl; FUNCPTR pFunc; /* Check for vaild parameter */ VXB_ASSERT_NONNULL_V(pDev); pDrvCtrl = (SM2130_SPI_DEV *)pDev->pDrvCtrl; /* Mutex semaphore is initialized and necessary at this point */ pDrvCtrl->muteSem = semMCreate(SPI_DEV_MUTEX_OPT); pFunc = vxbDevMethodGet(vxbDevParent(pDev), (VXB_METHOD_ID)vxbSpiSpecialGet_desc); /* Retrieve the SPI master special information */ if (pFunc != NULL) (*pFunc)(vxbDevParent(pDev), &pDrvCtrl->specialInfo); } /* * sm2130SpiDevInstConnect - third level initialization routine of spi flash * * This function implements the VxBus instConnect handler for a SPI Flash * device instance. * * RETURNS: N/A * * ERRNO: N/A */ LOCAL void sm2130SpiDevInstConnect(VXB_DEVICE_ID pDev) { SM2130_SPI_DEV *pDrvCtrl; SM2310_DEV_HANDLE *dev; /* Check for vaild parameter */ VXB_ASSERT_NONNULL_V(pDev); pDrvCtrl = (SM2130_SPI_DEV *)pDev->pDrvCtrl; if (sm2130_driver_node < 0) { /* clang-format off */ sm2130_driver_node = iosDrvInstall( (DRV_CREATE_PTR)drv1553bOpen , (DRV_REMOVE_PTR)NULL , (DRV_OPEN_PTR)drv1553bOpen , (DRV_CLOSE_PTR)drv1553bClose , (DRV_READ_PTR)NULL , (DRV_WRITE_PTR)NULL , (DRV_IOCTL_PTR)drv1553bIoctl); /* clang-format on */ } semTake(pDrvCtrl->muteSem, WAIT_FOREVER); if (sm2130_driver_node > 0) { dev = (SM2310_DEV_HANDLE *)hwMemAlloc(sizeof(SM2310_DEV_HANDLE)); if (dev) { pDrvCtrl->refcount = 0; selWakeupListInit(&dev->selList); if (iosDevAdd(&dev->devHdr, pDrvCtrl->devName, sm2130_driver_node) == OK) { pDrvCtrl->devHandle = dev; dev->pDevCtrl = pDrvCtrl; } else { #ifndef _VXBUS_BASIC_HWMEMLIB hwMemFree((char *)dev); #endif /* _VXBUS_BASIC_HWMEMLIB */ } } } semGive(pDrvCtrl->muteSem); } /* * sm2130SpiDevInstUnlink - VxBus unlink handler * * This function shuts down a SPI Flash device instance in response to an * unlink event from VxBus. This may occur if our VxBus instance has been * terminated, or if the driver has been unloaded. * * RETURNS: OK always. * * ERRNO: N/A */ LOCAL STATUS sm2130SpiDevInstUnlink(VXB_DEVICE_ID pDev, void *unused) { SM2130_SPI_DEV *pDrvCtrl; /* Check for vaild parameter */ VXB_ASSERT_NONNULL_V(pDev); pDrvCtrl = (SM2130_SPI_DEV *)pDev->pDrvCtrl; if (pDrvCtrl->muteSem) { (void)semTake(pDrvCtrl->muteSem, WAIT_FOREVER); (void)semDelete(pDrvCtrl->muteSem); pDrvCtrl->muteSem = NULL; } #ifndef _VXBUS_BASIC_HWMEMLIB hwMemFree((char *)pDrvCtrl); #endif /* _VXBUS_BASIC_HWMEMLIB */ pDev->pDrvCtrl = NULL; return OK; } /* * * sm2130SpiDevShow - show the SPI 1553B info. * * This routine show the SPI flash info by vxBusShow. * * RETURNS: N/A * * ERRNO: N/A */ LOCAL void sm2130SpiDevShow(VXB_DEVICE_ID pDev, int verbose) { SM2130_SPI_DEV *pDrvCtrl = (SM2130_SPI_DEV *)pDev->pDrvCtrl; printf(" %s unit %d on %s @ 0x%08x", pDev->pName, pDev->unitNumber, vxbBusTypeString(pDev->busID), pDev); printf(" with busInfo %p\n", pDev->u.pSubordinateBus); if (verbose) { printf(" chipSelect: %d\n", pDrvCtrl->cs); printf(" mode: %d\n", pDrvCtrl->mode); printf(" speed: %u\n", pDrvCtrl->freq); printf(" devName: %s\n", pDrvCtrl->devName); printf(" devHandle: %p\n", pDrvCtrl->devHandle); printf(" refCount: %d\n", pDrvCtrl->refcount); } return; } /* * sm2130BusDevWrite - VxBus SPI device write by name support routine * * This routine firstly finds the VXB_DEVICE_ID for a given instance * identified by name and unit number, then call vxbI2cDevWrite() routine to * write the device. * * RETURNS: OK/ERROR * * ERRNO : N/A */ LOCAL STATUS sm2130BusDevWrite(VXB_DEVICE_ID pDev, UINT8 cmd, UINT16 var) { SPI_TRANSFER transInfo = { NULL, NULL, 0, 0, 0 }; UINT8 buf[3]; /* Check if the pDev pointer is valid */ VXB_ASSERT(pDev != NULL, ERROR) buf[0] = cmd; buf[1] = var & 0xff; buf[1] = (var >> 8) & 0xff; transInfo.txBuf = buf; transInfo.txLen = 3; return vxbSpiTransfer(pDev, &transInfo); } /* * sm2130BusDevRead - read register routine * * This is the SPI flash status /config register read out routine. * * RETURNS: status register value. * * ERRNO: N/A */ LOCAL INT32 sm2130BusDevRead(VXB_DEVICE_ID pDev, UINT8 cmd) { SPI_TRANSFER transInfo = { NULL, NULL, 0, 0, 0 }; UINT16 buffer; UINT8 buf[3] = { 0xff, 0xff, 0xff }; /* check if the pDev pointer is valid */ VXB_ASSERT(pDev != NULL, ERROR) buf[0] = cmd; transInfo.txBuf = buf; transInfo.txLen = 1; transInfo.rxBuf = buf; transInfo.rxLen = 3; if (vxbSpiTransfer(pDev, &transInfo) != OK) return ERROR; buffer = (buf[2] << 8) | buf[1]; return (buffer); } /* {{{ Test Read write */ INT32 sm2130Read(UINT8 cmd) { VXB_DEVICE_ID pDev; SM2130_SPI_DEV *pCtrl; pDev = vxbInstByNameFind(SPI_DEV_SM2130, 0); if (pDev == NULL) { return ERROR; } pCtrl = pDev->pDrvCtrl; /* printf("pDev @ %p, pCtrl %p\n", pDev, pCtrl); */ return pCtrl->read(pDev, cmd); } STATUS sm2130Write(UINT8 cmd, UINT16 var) { VXB_DEVICE_ID pDev; SM2130_SPI_DEV *pCtrl; pDev = vxbInstByNameFind(SPI_DEV_SM2130, 0); if (pDev == NULL) { return ERROR; } pCtrl = pDev->pDrvCtrl; /* printf("pDev @ %p, pCtrl %p\n", pDev, pCtrl); */ return pCtrl->write(pDev, cmd, var); } /* }}} */