You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

469 lines
12 KiB

/* vim: set ts=4 sw=4 et fdm=marker: */
#include <vxWorks.h>
#include <stdio.h>
#include <string.h>
#include <logLib.h>
#include <vxBusLib.h>
#include <semLib.h>
#include <taskLib.h>
#include <sysLib.h>
#include <tickLib.h>
#include <iosLib.h>
#include <selectLib.h>
#include <errnoLib.h>
#include <hwif/vxbus/vxBus.h>
#include <hwif/vxbus/hwConf.h>
#include <hwif/vxbus/vxbPlbLib.h>
#include <hwif/util/hwMemLib.h>
#include <hwif/util/vxbParamSys.h>
#include <hwif/vxbus/vxbSpiLib.h>
#include "vxbSm2130SpiDev.h"
#include <usrLib.h>
#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;
}
if (devResourceGet(pHcf, "reqIsr", HCF_RES_ADDR, (void *)&pDrvCtrl->reqIsr) != OK) {
pDrvCtrl->reqIsr = NULL;
}
}
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 doXferMem(SM2130_SPI_DEV * pDrvCtrl, SM2130_MEM_XFER *mxfr)
{
STATUS ret = OK;
int i;
if (mxfr->type == XFER_TYPE_WR) {
for (i = 0; i < mxfr->count; ++i) {
pDrvCtrl->write(pDrvCtrl->pDev, mxfr->regbuf[i], mxfr->membuf[i]);
}
} else if (mxfr->type == XFER_TYPE_RD) {
for (i = 0; i < mxfr->count; ++i) {
mxfr->membuf[i] = pDrvCtrl->read(pDrvCtrl->pDev, mxfr->regbuf[i]);
}
} else {
ret = ERROR;
}
return (OK);
}
LOCAL int drv1553bIoctl(SM2310_DEV_HANDLE *dev, int cmd, _Vx_ioctl_arg_t arg)
{
SM2130_XFER *xfer;
SM2130_MEM_XFER *mxfr;
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 FIOC_SM2130_WR:
xfer = (SM2130_XFER *)(arg);
pDrvCtrl->write(pDrvCtrl->pDev, xfer->reg, xfer->val);
break;
case FIOC_SM2130_RD:
xfer = (SM2130_XFER *)(arg);
xfer->val = pDrvCtrl->read(pDrvCtrl->pDev, xfer->reg);
break;
case FIOC_SM2130_MEM:
mxfr = (SM2130_MEM_XFER *)(arg);
if (mxfr) {
doXferMem(pDrvCtrl, mxfr);
}
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);
}
LOCAL void sm1553isr(void *data)
{
SM2310_DEV_HANDLE *dev = data;
logMsg("sm1553isr interrupt", 1, 2, 3, 4, 5, 6);
selWakeupAll(&dev->selList, SELREAD);
}
/*
* 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;
if (pDrvCtrl->reqIsr) {
pDrvCtrl->reqIsr(dev, sm1553isr);
}
} 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);
printf(" reqIsr: %p\n", pDrvCtrl->reqIsr);
}
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);
}
/* }}} */