/*
 *  ------------------------------------------------------------------------
 *  spi_stm.c SPI/SSC driver for STMicroelectronics platforms
 *  ------------------------------------------------------------------------
 *
 *  Copyright (c) 2008 STMicroelectronics Limited
 *  Author: Angus Clark <Angus.Clark@st.com>
 *
 *  May be copied or modified under the terms of the GNU General Public
 *  License Version 2.0 only.  See linux/COPYING for more information.
 *
 *  ------------------------------------------------------------------------
 *  Changelog:
 *  2008-01-24 (angus.clark@st.com)
 *    - Initial version
 *  2008-08-28 (angus.clark@st.com)
 *    - Updates to fit with changes to 'ssc_pio_t'
 *    - SSC accesses now all 32-bit, for compatibility with 7141 Comms block
 *    - Updated to handle 7141 PIO ALT configuration
 *    - Support for user-defined, per-bus, chip_select function.  Specified
 *      in board setup
 *    - Bug fix for rx_bytes_pending updates
 *
 *  ------------------------------------------------------------------------
 */

#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/wait.h>
#include <linux/workqueue.h>
#include <linux/completion.h>
#include <linux/uaccess.h>
#include <linux/param.h>
#include <linux/gpio.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
#include <linux/stm/platform.h>
#include <linux/stm/ssc.h>

#define NAME "spi-stm"

struct spi_stm {
	/* SSC SPI Controller */
	struct spi_bitbang	bitbang;
	void __iomem		*base;
	struct clk		*clk;
	struct platform_device  *pdev;

	/* Resources */
	struct resource r_mem;
	struct resource r_irq;
	struct stm_pad_state *pad_state;

	/* SSC SPI current transaction */
	const u8		*tx_ptr;
	u8			*rx_ptr;
	u16			bits_per_word;
	u16			bytes_per_word;
	unsigned int		baud;
	unsigned int		words_remaining;
	struct completion	done;
};

static void spi_stm_gpio_chipselect(struct spi_device *spi, int value)
{
	unsigned int out;

	if (spi->chip_select == (typeof(spi->chip_select))(STM_GPIO_INVALID))
		return;

	if (!spi->controller_data) {
		if (gpio_request(spi->chip_select, "spi_stm cs")) {
			dev_err(&spi->dev, "failed to allocate CS pin\n");
			return;
		}
		spi->controller_data = (void *)1;
		gpio_direction_output(spi->chip_select,
				      spi->mode & SPI_CS_HIGH);
	}

	if (value == BITBANG_CS_ACTIVE)
		out = spi->mode & SPI_CS_HIGH ? 1 : 0;
	else
		out = spi->mode & SPI_CS_HIGH ? 0 : 1;

	gpio_set_value(spi->chip_select, out);

	dev_dbg(&spi->dev, "%s PIO%d[%d] -> %d \n",
		value == BITBANG_CS_ACTIVE ? "select" : "deselect",
		stm_gpio_port(spi->chip_select),
		stm_gpio_pin(spi->chip_select), out);

	return;
}

static int spi_stm_setup_transfer(struct spi_device *spi,
				     struct spi_transfer *t)
{
	struct spi_stm *spi_stm;
	u32 hz;
	u8 bits_per_word;
	u32 reg;
	u32 sscbrg;

	spi_stm = spi_master_get_devdata(spi->master);
	bits_per_word = (t) ? t->bits_per_word : 0;
	hz = (t) ? t->speed_hz : 0;

	/* If not specified, use defaults */
	if (!bits_per_word)
		bits_per_word = spi->bits_per_word;
	if (!hz)
		hz = spi->max_speed_hz;

	/* Actually, can probably support 2-16 without any other change!!! */
	if (bits_per_word != 8 && bits_per_word != 16) {
		dev_err(&spi->dev, "unsupported bits_per_word=%d\n",
			bits_per_word);
		return -EINVAL;
	}
	spi_stm->bits_per_word = bits_per_word;

	/* Set SSC_BRF */
	sscbrg = clk_get_rate(spi_stm->clk) / (2*hz);
	if (sscbrg < 0x07 || sscbrg > (0x1 << 16)) {
		dev_err(&spi->dev, "baudrate outside valid range"
			" %d (sscbrg = %d)\n", hz, sscbrg);
		return -EINVAL;
	}
	spi_stm->baud = clk_get_rate(spi_stm->clk) / (2 * sscbrg);
	if (sscbrg == (0x1 << 16)) /* 16-bit counter wraps */
		sscbrg = 0x0;
	ssc_store32(spi_stm, SSC_BRG, sscbrg);

	dev_dbg(&spi->dev, "setting baudrate: target = %u hz, "
		"actual = %u hz, sscbrg = %u\n",
		hz, spi_stm->baud, sscbrg);

	 /* Set SSC_CTL and enable SSC */
	 reg = ssc_load32(spi_stm, SSC_CTL);
	 reg |= SSC_CTL_MS;

	 if (spi->mode & SPI_CPOL)
		 reg |= SSC_CTL_PO;
	 else
		 reg &= ~SSC_CTL_PO;

	 if (spi->mode & SPI_CPHA)
		 reg |= SSC_CTL_PH;
	 else
		 reg &= ~SSC_CTL_PH;

	 if ((spi->mode & SPI_LSB_FIRST) == 0)
		 reg |= SSC_CTL_HB;
	 else
		 reg &= ~SSC_CTL_HB;

	 if (spi->mode & SPI_LOOP)
		 reg |= SSC_CTL_LPB;
	 else
		 reg &= ~SSC_CTL_LPB;

	 reg &= 0xfffffff0;
	 reg |= (bits_per_word - 1);

	 reg |= SSC_CTL_EN_TX_FIFO | SSC_CTL_EN_RX_FIFO;
	 reg |= SSC_CTL_EN;

	 dev_dbg(&spi->dev, "ssc_ctl = 0x%04x\n", reg);
	 ssc_store32(spi_stm, SSC_CTL, reg);

	 /* Clear the status register */
	 ssc_load32(spi_stm, SSC_RBUF);

	 return 0;
}

static void spi_stm_cleanup(struct spi_device *spi)
{
	if (spi->controller_data) {
		gpio_free(spi->chip_select);
		spi->controller_data = (void *)0;
	}
}

/* the spi->mode bits understood by this driver: */
#define MODEBITS  (SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_LOOP | SPI_CS_HIGH)
static int spi_stm_setup(struct spi_device *spi)
{
	struct spi_stm *spi_stm;

	spi_stm = spi_master_get_devdata(spi->master);

	if (spi->mode & ~MODEBITS) {
		dev_err(&spi->dev, "unsupported mode bits %x\n",
			spi->mode & ~MODEBITS);
		return -EINVAL;
	}

	if (!spi->max_speed_hz)  {
		dev_err(&spi->dev, "max_speed_hz unspecified\n");
		return -EINVAL;
	}

	if (!spi->bits_per_word)
		spi->bits_per_word = 8;

	return spi_stm_setup_transfer(spi, NULL);
}

/* Load the TX FIFO */
static void ssc_write_tx_fifo(struct spi_stm *spi_stm)
{

	uint32_t count;
	uint32_t word = 0;
	int i;

	if (spi_stm->words_remaining > 8)
		count = 8;
	else
		count = spi_stm->words_remaining;

	for (i = 0; i < count; i++) {
		if (spi_stm->tx_ptr) {
			if (spi_stm->bytes_per_word == 1) {
				word = *spi_stm->tx_ptr++;
			} else {
				word = *spi_stm->tx_ptr++;
				word = *spi_stm->tx_ptr++ | (word << 8);
			}
		}
		ssc_store32(spi_stm, SSC_TBUF, word);
	}
}

/* Read the RX FIFO */
static void ssc_read_rx_fifo(struct spi_stm *spi_stm)
{

	uint32_t count;
	uint32_t word = 0;
	int i;

	if (spi_stm->words_remaining > 8)
		count = 8;
	else
		count = spi_stm->words_remaining;

	for (i = 0; i < count; i++) {
		word = ssc_load32(spi_stm, SSC_RBUF);
		if (spi_stm->rx_ptr) {
			if (spi_stm->bytes_per_word == 1) {
				*spi_stm->rx_ptr++ = (uint8_t)word;
			} else {
				*spi_stm->rx_ptr++ = (word >> 8);
				*spi_stm->rx_ptr++ = word & 0xff;
			}
		}
	}

	spi_stm->words_remaining -= count;
}

/* Interrupt fired when TX shift register becomes empty */
static irqreturn_t spi_stm_irq(int irq, void *dev_id)
{
	struct spi_stm *spi_stm = (struct spi_stm *)dev_id;

	/* Read RX FIFO */
	ssc_read_rx_fifo(spi_stm);

	/* Fill TX FIFO */
	if (spi_stm->words_remaining) {
		ssc_write_tx_fifo(spi_stm);
	} else {
		/* TX/RX complete */
		ssc_store32(spi_stm, SSC_IEN, 0x0);
		complete(&spi_stm->done);
	}

	return IRQ_HANDLED;
}


static int spi_stm_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
{
	struct spi_stm *spi_stm;
	uint32_t ctl = 0;

	spi_stm = spi_master_get_devdata(spi->master);

	/* Setup transfer */
	spi_stm->tx_ptr = t->tx_buf;
	spi_stm->rx_ptr = t->rx_buf;

	if (spi_stm->bits_per_word > 8) {
		/* Anything greater than 8 bits-per-word requires 2
		 * bytes-per-word in the RX/TX buffers */
		spi_stm->bytes_per_word = 2;
		spi_stm->words_remaining = t->len/2;
	} else if (spi_stm->bits_per_word == 8 &&
		   ((t->len & 0x1) == 0)) {
		/* If transfer is even-length, and 8 bits-per-word, then
		 * implement as half-length 16 bits-per-word transfer */
		spi_stm->bytes_per_word = 2;
		spi_stm->words_remaining = t->len/2;

		/* Set SSC_CTL to 16 bits-per-word */
		ctl = ssc_load32(spi_stm, SSC_CTL);
		ssc_store32(spi_stm, SSC_CTL, (ctl | 0xf));

		ssc_load32(spi_stm, SSC_RBUF);

	} else {
		spi_stm->bytes_per_word = 1;
		spi_stm->words_remaining = t->len;
	}

	INIT_COMPLETION(spi_stm->done);

	/* Start transfer by writing to the TX FIFO */
	ssc_write_tx_fifo(spi_stm);
	ssc_store32(spi_stm, SSC_IEN, SSC_IEN_TEEN);

	/* Wait for transfer to complete */
	wait_for_completion(&spi_stm->done);

	/* Restore SSC_CTL if necessary */
	if (ctl)
		ssc_store32(spi_stm, SSC_CTL, ctl);

	return t->len;

}

static int __init spi_stm_probe(struct platform_device *pdev)
{
	struct stm_plat_ssc_data *plat_data = pdev->dev.platform_data;
	struct spi_master *master;
	struct resource *res;
	struct spi_stm *spi_stm;
	u32 reg;
	int status = 0;

	master = spi_alloc_master(&pdev->dev, sizeof(struct spi_stm));
	if (!master) {
		dev_err(&pdev->dev, "failed to allocate spi master\n");
		status = -ENOMEM;
		goto err0;
	}

	platform_set_drvdata(pdev, master);

	spi_stm = spi_master_get_devdata(master);
	spi_stm->bitbang.master = spi_master_get(master);
	spi_stm->bitbang.setup_transfer = spi_stm_setup_transfer;
	spi_stm->bitbang.txrx_bufs = spi_stm_txrx_bufs;
	spi_stm->bitbang.master->setup = spi_stm_setup;
	spi_stm->bitbang.master->cleanup = spi_stm_cleanup;

	if (plat_data->spi_chipselect)
		spi_stm->bitbang.chipselect = plat_data->spi_chipselect;
	else
		spi_stm->bitbang.chipselect = spi_stm_gpio_chipselect;

	/* the spi->mode bits understood by this driver: */
	master->mode_bits = MODEBITS;

	/* chip_select field of spi_device is declared as u8 and therefore
	 * limits number of GPIOs that can be used as a CS line. Sorry. */
	master->num_chipselect =
		sizeof(((struct spi_device *)0)->chip_select) * 256;
	master->bus_num = pdev->id;
	init_completion(&spi_stm->done);

	/* Get resources */
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res) {
		dev_err(&pdev->dev, "failed to find IOMEM resource\n");
		status = -ENOENT;
		goto err1;
	}
	spi_stm->r_mem = *res;

	if (!request_mem_region(res->start,
				res->end - res->start + 1, NAME)) {
		dev_err(&pdev->dev, "request memory region failed [0x%x]\n",
			res->start);
		status = -EBUSY;
		goto err1;
	}

	spi_stm->base = ioremap_nocache(res->start, res->end - res->start + 1);
	if (!spi_stm->base) {
		dev_err(&pdev->dev, "ioremap memory failed [0x%x]\n",
			res->start);
		status = -ENXIO;
		goto err2;
	}

	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
	if (!res) {
		dev_err(&pdev->dev, "failed to find IRQ resource\n");
		status = -ENOENT;
		goto err3;
	}
	spi_stm->r_irq = *res;

	if (request_irq(res->start, spi_stm_irq,
			IRQF_DISABLED, dev_name(&pdev->dev), spi_stm)) {
		dev_err(&pdev->dev, "irq request failed\n");
		status = -EBUSY;
		goto err3;
	}

	spi_stm->pad_state = stm_pad_claim(plat_data->pad_config,
					   dev_name(&pdev->dev));
	if (!spi_stm->pad_state) {
		dev_err(&pdev->dev, "pads request failed\n");
		status = -EBUSY;
		goto err4;
	}

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

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

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

	spi_stm->clk = clk_get(&pdev->dev, "comms_clk");
	if (!spi_stm->clk) {
		dev_err(&pdev->dev, "Comms clock not found!\n");
		goto err5;
	}

	clk_enable(spi_stm->clk);
	/* Start "bitbang" worker */
	status = spi_bitbang_start(&spi_stm->bitbang);
	if (status) {
		dev_err(&pdev->dev, "bitbang start failed [%d]\n", status);
		goto err5;
	}

	dev_info(&pdev->dev, "registered SPI Bus %d\n", master->bus_num);

	return status;

 err5:
	stm_pad_release(spi_stm->pad_state);
 err4:
	free_irq(spi_stm->r_irq.start, spi_stm);
 err3:
	iounmap(spi_stm->base);
 err2:
	release_mem_region(spi_stm->r_mem.start,
			   resource_size(&spi_stm->r_mem));
 err1:
	spi_master_put(spi_stm->bitbang.master);
	platform_set_drvdata(pdev, NULL);
 err0:
	return status;
}

static int spi_stm_remove(struct platform_device *pdev)
{
	struct spi_stm *spi_stm;
	struct spi_master *master;

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

	spi_bitbang_stop(&spi_stm->bitbang);

	clk_disable(spi_stm->clk);

	stm_pad_release(spi_stm->pad_state);
	free_irq(spi_stm->r_irq.start, spi_stm);
	iounmap(spi_stm->base);
	release_mem_region(spi_stm->r_mem.start,
			   resource_size(&spi_stm->r_mem));

	spi_master_put(spi_stm->bitbang.master);
	platform_set_drvdata(pdev, NULL);

	return 0;
}
#ifdef CONFIG_PM
static int spi_stm_suspend(struct device *dev)
{
	struct spi_master *master = dev_get_drvdata(dev);
	struct spi_stm *spi_stm;

	spi_stm = spi_master_get_devdata(master);

	ssc_store32(spi_stm, SSC_IEN, 0);

	clk_disable(spi_stm->clk);
	return 0;
}

static int spi_stm_resume(struct device *dev)
{
	struct spi_master *master = dev_get_drvdata(dev);
	struct spi_stm *spi_stm;

	spi_stm = spi_master_get_devdata(master);

	clk_enable(spi_stm->clk);
	return 0;
}

static struct dev_pm_ops spi_stm_pm = {
	.suspend = spi_stm_suspend,
	.resume = spi_stm_resume,
	.freeze = spi_stm_suspend,
	.restore = spi_stm_resume,
	.runtime_suspend = spi_stm_suspend,
	.runtime_resume = spi_stm_resume,
};
#else
static struct dev_pm_ops spi_stm_pm;
#endif

static struct platform_driver spi_stm_driver = {
	.driver.name = NAME,
	.driver.owner = THIS_MODULE,
	.driver.pm = &spi_stm_pm,
	.probe = spi_stm_probe,
	.remove = spi_stm_remove,
};


static int __init spi_stm_init(void)
{
	return platform_driver_register(&spi_stm_driver);
}

static void __exit spi_stm_exit(void)
{
	platform_driver_unregister(&spi_stm_driver);
}

module_init(spi_stm_init);
module_exit(spi_stm_exit);

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