/** * @brief Close SPI device * * This function is called when the caller is no longer using this driver. It * should release or close all resources that were allocated by the open() * function. This function should be called after the open() function. If the * device is not opened yet, this function should return without any operations. * * @param dev pointer to structure of device data */ static void tsb_spi_dev_close(struct device *dev) { int i; struct tsb_spi_dev_info *info = NULL; /* check input parameter */ if (!dev || !device_get_private(dev)) { return; } info = device_get_private(dev); sem_wait(&info->lock); up_disable_irq(TSB_IRQ_SPI); irq_detach(TSB_IRQ_SPI); tsb_spi_hw_deinit(info); for (i = 0; i < info->num_boards; i++) { device_close(info->dev_spi_board[i]); info->dev_spi_board[i] = NULL; } info->state = TSB_SPI_STATE_CLOSED; sem_post(&info->lock); }
/** * @brief Remove SPI device * * This function is called by the system to unregister the driver. It should * release the hardware resource and interrupt setting, and then free memory * that allocated by the probe() function. * This function should be called after probe() function. If driver was opened, * this function should call close() function before releasing resources. * * @param dev pointer to structure of device data */ static void tsb_spi_dev_remove(struct device *dev) { struct tsb_spi_info *info = NULL; /* check input parameter */ if (!dev || !device_get_private(dev)) { return; } info = device_get_private(dev); info->state = TSB_SPI_STATE_INVALID; sem_destroy(&info->lock); sem_destroy(&info->bus); /* deinitialize gpio pins */ tsb_spi_hw_deinit(dev); device_set_private(dev, NULL); free(info); }
/** * @brief Open SPI device * * This function is called when the caller is preparing to use this device * driver. This function should be called after probe() function and needs to * check whether the driver is already open. If driver was opened, it needs * to return an error code to the caller. * * @param dev pointer to structure of device data * @return 0 on success, negative errno on error */ static int tsb_spi_dev_open(struct device *dev) { struct tsb_spi_dev_info *info = NULL; struct device *spi_board; int i; int ret = 0; /* check input parameter */ if (!dev || !device_get_private(dev)) { return -EINVAL; } info = device_get_private(dev); sem_wait(&info->lock); if (info->state != TSB_SPI_STATE_CLOSED) { ret = -EBUSY; goto err_open; } /* open all the consecutive slaves we can find */ info->num_boards = 0; for (i = 0; i < SPI_MAX_SLAVES; i++) { spi_board = device_open(DEVICE_TYPE_SPI_BOARD_HW, i); if (spi_board) { info->num_boards++; info->dev_spi_board[i] = spi_board; } else break; } info->curr_xfer.cs_high = 0; info->curr_xfer.bpw = 8; ret = tsb_spi_hw_init(info); if (ret) { goto err_hwinit; } /* register SPI IRQ number */ ret = irq_attach(TSB_IRQ_SPI, tsb_spi_irq_handler, NULL); if (ret != OK) { ret = -EIO; goto err_irq; } up_enable_irq(TSB_IRQ_SPI); info->state = TSB_SPI_STATE_OPEN; sem_post(&info->lock); return ret; err_irq: tsb_spi_hw_deinit(info); err_hwinit: for (i = 0; i < info->num_boards; i++) { device_close(info->dev_spi_board[i]); info->dev_spi_board[i] = NULL; } err_open: sem_post(&info->lock); return ret; }