Exemplo n.º 1
0
static int PROTONfp_Set_PIO_Mode(PIO_Mode_T Mode_PIO)
{
	if(Mode_PIO == PIO_Out)
		stpio_configure_pin(cfg.data, STPIO_OUT);
	else if(Mode_PIO == PIO_In)
		stpio_configure_pin(cfg.data, STPIO_IN);
	stpio_configure_pin(cfg.clk, STPIO_OUT);
	stpio_configure_pin(cfg.cs,  STPIO_OUT);
	return 0;
}
Exemplo n.º 2
0
static int PROTONfp_Set_PIO_Mode(PIO_Mode_T Mode_PIO)
{
   int ret = 0;

   if(Mode_PIO == PIO_Out)
   {
	   stpio_configure_pin(cfg.data, STPIO_OUT);
   }
   else if(Mode_PIO == PIO_In)
   {
	   stpio_configure_pin(cfg.data, STPIO_IN);
   }
   return ret;
}
Exemplo n.º 3
0
YW_ErrorType_T YWGPIO_SetIoMode(YWGPIO_Handle_T GpioHandle,
				YWGPIO_IOMode_T IoMode)
{
	struct stpio_pin *pPio = (struct stpio_pin *)GpioHandle;

	switch (IoMode)
	{
		case YWGPIO_IO_MODE_INPUT:
			stpio_configure_pin(pPio, STPIO_IN);
			break;
		case YWGPIO_IO_MODE_OUTPUT:
			stpio_configure_pin(pPio, STPIO_OUT);
			break;
		case YWGPIO_IO_MODE_BIDIRECTIONAL:
			stpio_configure_pin(pPio, STPIO_BIDIR);
			break;
		default:

			break;
	}
	return YW_NO_ERROR;
}
/* For SSC SPI as MASTER, TX/RX is handled as follows:

   1. Fill the TX_FIFO with up to (SSC_TXFIFO_SIZE - 1) words, and enable
      TX_FIFO_EMPTY interrupts.
   2. When the last word of TX_FIFO is copied to the shift register,
      a TX_FIFO_EMPTY interrupt is issued, and the last word will *start* being
      shifted out/in.
   3. On receiving a TX_FIFO_EMPTY interrupt, copy all *available* received
      words from the RX_FIFO. Note, depending on the time taken to shift out/in
      the 'last' word compared to the IRQ latency, the 'last' word may not be
      available yet in the RX_FIFO.
   4. If there are more bytes to TX, refill the TX_FIFO.  Since the 'last' word
      from the previous iteration may still be (or about to be) in the RX_FIFO,
      only add up to (SSC_TXFIFO_SIZE - 1) words.  If all bytes have been
      transmitted, disable TX and set completion.
   5. If we are interested in the received data, check to see if the 'last' word
      has been received.  If not, then wait the period of shifting 1 word, then
      read the 'last' word from the RX_FIFO.

*/
static void spi_stmssc_fill_tx_fifo(struct spi_stm_ssc *st_ssc)
{
	union {
		u8 bytes[4];
		u32 dword;
	} tmp = {.dword = 0,};
	int i;

	for (i = 0;
	     i < SSC_TXFIFO_SIZE - 1 && st_ssc->tx_bytes_pending > 0; i++) {
		if (st_ssc->bits_per_word > 8) {
			if (st_ssc->tx_ptr) {
				tmp.bytes[1] = *st_ssc->tx_ptr++;
				tmp.bytes[0] = *st_ssc->tx_ptr++;
			} else {
				tmp.bytes[1] = 0;
				tmp.bytes[0] = 0;
			}

			st_ssc->tx_bytes_pending -= 2;

		} else {
			if (st_ssc->tx_ptr)
				tmp.bytes[0] = *st_ssc->tx_ptr++;
			else
				tmp.bytes[0] = 0;

			st_ssc->tx_bytes_pending--;
		}
		ssc_store32(st_ssc, SSC_TBUF, tmp.dword);
	}
}

static int spi_stmssc_rx_mopup(struct spi_stm_ssc *st_ssc)
{
	unsigned long word_period_ns;
	u32 rx_fifo_status;
	union {
		u8 bytes[4];
		u32 dword;
	} tmp = {.dword = 0,};

	dgb_print("\n");

	word_period_ns = 1000000000 / st_ssc->baud;
	word_period_ns *= st_ssc->bits_per_word;

	/* delay for period equivalent to shifting 1 complete word
	   out of and into shift register */
	ndelay(word_period_ns);

	/* Check 'last' word is actually there! */
	rx_fifo_status = ssc_load32(st_ssc, SSC_RX_FSTAT);
	if (rx_fifo_status == 1) {
		tmp.dword = ssc_load32(st_ssc, SSC_RBUF);

		if (st_ssc->bits_per_word > 8) {
			if (st_ssc->rx_ptr) {
				*st_ssc->rx_ptr++ = tmp.bytes[1];
				*st_ssc->rx_ptr++ = tmp.bytes[0];
			}
			st_ssc->rx_bytes_pending -= 2;
		} else {
			if (st_ssc->rx_ptr)
				*st_ssc->rx_ptr++ = tmp.bytes[0];
			st_ssc->rx_bytes_pending--;
		}
	} else {
		dgb_print("should only be one word in RX_FIFO"
			  "(rx_fifo_status = %d)\n", rx_fifo_status);
	}

	return 0;
}


static int spi_stmssc_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
{
	struct spi_stm_ssc *st_ssc;

	dgb_print("\n");

	st_ssc = spi_master_get_devdata(spi->master);

	st_ssc->tx_ptr = t->tx_buf;
	st_ssc->rx_ptr = t->rx_buf;
	st_ssc->tx_bytes_pending = t->len;
	st_ssc->rx_bytes_pending = t->len;
	INIT_COMPLETION(st_ssc->done);

	/* fill TX_FIFO */
	spi_stmssc_fill_tx_fifo(st_ssc);

	/* enable TX_FIFO_EMPTY interrupts */
	ssc_store32(st_ssc, SSC_IEN, SSC_IEN_TIEN);

	/* wait for all bytes to be transmitted*/
	wait_for_completion(&st_ssc->done);

	/* check 'last' byte has been received */
	/* NOTE: need to read rxbuf, even if ignoring the result! */
	if (st_ssc->rx_bytes_pending)
		spi_stmssc_rx_mopup(st_ssc);

	/* disable ints */
	ssc_store32(st_ssc, SSC_IEN, 0x0);

	return t->len - st_ssc->tx_bytes_pending;
}



static irqreturn_t spi_stmssc_irq(int irq, void *dev_id)
{
	struct spi_stm_ssc *st_ssc = (struct spi_stm_ssc *)dev_id;
	unsigned int rx_fifo_status;
	u32 ssc_status;

	union {
		u8 bytes[4];
		u32 dword;
	} tmp = {.dword = 0,};

	ssc_status = ssc_load32(st_ssc, SSC_STA);

	/* FIFO_TX_EMPTY */
	if (ssc_status & SSC_STA_TIR) {
		/* Find number of words available in RX_FIFO: 8 if RX_FIFO_FULL,
		   else SSC_RX_FSTAT (0-7)
		*/
		rx_fifo_status = (ssc_status & SSC_STA_RIR) ? 8 :
			ssc_load32(st_ssc, SSC_RX_FSTAT);

		/* Read all available words from RX_FIFO */
		while (rx_fifo_status) {
			tmp.dword = ssc_load32(st_ssc, SSC_RBUF);

			if (st_ssc->bits_per_word > 8) {
				if (st_ssc->rx_ptr) {
					*st_ssc->rx_ptr++ = tmp.bytes[1];
					*st_ssc->rx_ptr++ = tmp.bytes[0];
				}
				st_ssc->rx_bytes_pending -= 2;
			} else {
				if (st_ssc->rx_ptr)
					*st_ssc->rx_ptr++ = tmp.bytes[0];
				st_ssc->rx_bytes_pending--;
			}

			rx_fifo_status = ssc_load32(st_ssc, SSC_RX_FSTAT);
		}

		/* See if there is more data to send */
		if (st_ssc->tx_bytes_pending > 0)
			spi_stmssc_fill_tx_fifo(st_ssc);
		else {
			/* No more data to send */
			ssc_store32(st_ssc, SSC_IEN, 0x0);
			complete(&st_ssc->done);
		}
	}

	return IRQ_HANDLED;
}


static int __init spi_stm_probe(struct platform_device *pdev)
{
	struct ssc_pio_t *pio_info =
			(struct ssc_pio_t *)pdev->dev.platform_data;
	struct spi_master *master;
	struct resource *res;
	struct spi_stm_ssc *st_ssc;

	u32 reg;

	master = spi_alloc_master(&pdev->dev, sizeof(struct spi_stm_ssc));
	if (!master)
		return -ENOMEM;

	platform_set_drvdata(pdev, master);

	st_ssc = spi_master_get_devdata(master);
	st_ssc->bitbang.master     = spi_master_get(master);
	st_ssc->bitbang.setup_transfer = spi_stmssc_setup_transfer;
	st_ssc->bitbang.txrx_bufs  = spi_stmssc_txrx_bufs;
	st_ssc->bitbang.master->setup = spi_stmssc_setup;

	if (pio_info->chipselect)
		st_ssc->bitbang.chipselect = (void (*)
					      (struct spi_device *, int))
			pio_info->chipselect;
	else
		st_ssc->bitbang.chipselect = spi_stpio_chipselect;

	master->num_chipselect = SPI_NO_CHIPSELECT + 1;
	master->bus_num = pdev->id;
	init_completion(&st_ssc->done);

	/* Get resources */
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res)
		return -ENODEV;

	if (!devm_request_mem_region(&pdev->dev, res->start,
				     res->end - res->start, "spi")) {
		printk(KERN_ERR NAME " Request mem 0x%x region failed\n",
		       res->start);
		return -ENOMEM;
	}

	st_ssc->base =
		(unsigned long) devm_ioremap_nocache(&pdev->dev, res->start,
						     res->end - res->start);
	if (!st_ssc->base) {
		printk(KERN_ERR NAME " Request iomem 0x%x region failed\n",
		       res->start);
		return -ENOMEM;
	}

	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
	if (!res) {
		printk(KERN_ERR NAME " Request irq %d failed\n", res->start);
		return -ENODEV;
	}

	if (devm_request_irq(&pdev->dev, res->start, spi_stmssc_irq,
		IRQF_DISABLED, "stspi", st_ssc) < 0) {
		printk(KERN_ERR NAME " Request irq failed\n");
		return -ENODEV;
	}

	/* Check for hard wired SSC which doesn't use PIO pins */
	if (pio_info->pio[0].pio_port == SSC_NO_PIO)
		goto ssc_hard_wired;

	/* Get PIO pins */
	pio_info->clk = stpio_request_set_pin(pio_info->pio[0].pio_port,
					  pio_info->pio[0].pio_pin,
					      "SPI Clock", STPIO_BIDIR, 0);
	if (!pio_info->clk) {
		printk(KERN_ERR NAME
		       " Failed to allocate clk pin (PIO%d[%d])\n",
		       pio_info->pio[0].pio_port, pio_info->pio[0].pio_pin);
		return -ENODEV;
	}
	pio_info->sdout = stpio_request_set_pin(pio_info->pio[1].pio_port,
					    pio_info->pio[1].pio_pin,
						"SPI Data out", STPIO_BIDIR, 0);
	if (!pio_info->sdout) {
		printk(KERN_ERR NAME
		       " Failed to allocate sdo pin (PIO%d[%d])\n",
		       pio_info->pio[1].pio_port, pio_info->pio[1].pio_pin);
		return -ENODEV;
	}
	pio_info->sdin = stpio_request_pin(pio_info->pio[2].pio_port,
					   pio_info->pio[2].pio_pin,
					   "SPI Data in", STPIO_IN);
	if (!pio_info->sdin) {
		printk(KERN_ERR NAME
		       " Failed to allocate sdi pin (PIO%d[%d])\n",
		       pio_info->pio[2].pio_port, pio_info->pio[2].pio_pin);
		return -ENODEV;
	}

ssc_hard_wired:

	/* Disable I2C and Reset SSC */
	ssc_store32(st_ssc, SSC_I2C, 0x0);
	reg = ssc_load16(st_ssc, SSC_CTL);
	reg |= SSC_CTL_SR;
	ssc_store32(st_ssc, SSC_CTL, reg);

	udelay(1);
	reg = ssc_load32(st_ssc, SSC_CTL);
	reg &= ~SSC_CTL_SR;
	ssc_store32(st_ssc, SSC_CTL, reg);

	/* Set SSC into slave mode before reconfiguring PIO pins */
	reg = ssc_load32(st_ssc, SSC_CTL);
	reg &= ~SSC_CTL_MS;
	ssc_store32(st_ssc, SSC_CTL, reg);

	if (pio_info->pio[0].pio_port == SSC_NO_PIO)
		goto ssc_hard_wired2;

#ifdef CONFIG_CPU_SUBTYPE_STX7141
	stpio_configure_pin(pio_info->clk, STPIO_OUT);
	stpio_configure_pin(pio_info->sdout, STPIO_OUT);
	stpio_configure_pin(pio_info->sdin, STPIO_IN);
#else
	stpio_configure_pin(pio_info->clk, STPIO_ALT_OUT);
	stpio_configure_pin(pio_info->sdout, STPIO_ALT_OUT);
	stpio_configure_pin(pio_info->sdin, STPIO_IN);
#endif

ssc_hard_wired2:

	st_ssc->fcomms = clk_get_rate(clk_get(NULL, "comms_clk"));;

	/* Start bitbang worker */
	if (spi_bitbang_start(&st_ssc->bitbang)) {
		printk(KERN_ERR NAME
		       " The SPI Core refuses the spi_stm_ssc adapter\n");
		return -1;
	}

	printk(KERN_INFO NAME ": Registered SPI Bus %d: "
	       "CLK[%d,%d] SDOUT[%d, %d] SDIN[%d, %d]\n", master->bus_num,
	       pio_info->pio[0].pio_port, pio_info->pio[0].pio_pin,
	       pio_info->pio[1].pio_port, pio_info->pio[1].pio_pin,
	       pio_info->pio[2].pio_port, pio_info->pio[2].pio_pin);

	return 0;
}

static int  spi_stm_remove(struct platform_device *pdev)
{
	struct spi_stm_ssc *st_ssc;
	struct spi_master *master;
	struct ssc_pio_t *pio_info =
		(struct ssc_pio_t *)pdev->dev.platform_data;

	master = platform_get_drvdata(pdev);
	st_ssc = spi_master_get_devdata(master);

	spi_bitbang_stop(&st_ssc->bitbang);

	if (pio_info->sdin) {
		stpio_free_pin(pio_info->sdin);
		stpio_free_pin(pio_info->clk);
		stpio_free_pin(pio_info->sdout);
	}

	return 0;
}

static struct platform_driver spi_hw_driver = {
	.driver.name = "spi_st_ssc",
	.driver.owner = THIS_MODULE,
	.probe = spi_stm_probe,
	.remove = spi_stm_remove,
};


static int __init spi_stm_ssc_init(void)
{
	printk(KERN_INFO NAME ": SSC SPI Driver\n");
	return platform_driver_register(&spi_hw_driver);
}

static void __exit spi_stm_ssc_exit(void)
{
	dgb_print("\n");
	platform_driver_unregister(&spi_hw_driver);
}

module_init(spi_stm_ssc_init);
module_exit(spi_stm_ssc_exit);

MODULE_AUTHOR("STMicroelectronics <www.st.com>");
MODULE_DESCRIPTION("STM SSC SPI driver");
MODULE_LICENSE("GPL");