From 4d382b4e9595ec0b7eb6e179832567d8e87852d0 Mon Sep 17 00:00:00 2001 From: Markinus Date: Fri, 27 Aug 2010 20:18:05 +0200 Subject: [PATCH] htcleo: add spi interface --- arch/arm/mach-msm/Makefile | 2 +- arch/arm/mach-msm/board-htcleo-spi.c | 201 +++++++++++++++++++++++++++ arch/arm/mach-msm/board-htcleo.c | 12 ++ 3 files changed, 214 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-msm/board-htcleo-spi.c diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 986f5b18..9a1d5161 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -100,7 +100,7 @@ obj-$(CONFIG_MACH_BRAVOC) += board-bravoc-rfkill.o board-bravoc-audio.o obj-$(CONFIG_MACH_BRAVOC) += board-bravoc-wifi.o htc_awb_cal.o obj-$(CONFIG_MACH_BRAVOC) += board-bravoc-microp.o -obj-$(CONFIG_MACH_HTCLEO) += board-htcleo.o +obj-$(CONFIG_MACH_HTCLEO) += board-htcleo.o board-htcleo-spi.o # MSM7x30 boards obj-$(CONFIG_ARCH_MSM7X30) += panel-samsungwvga-tl2796a.o panel-samsungwvga-s6e63m0.o panel-sonywvga-s6d16a0x21-7x30.o diff --git a/arch/arm/mach-msm/board-htcleo-spi.c b/arch/arm/mach-msm/board-htcleo-spi.c new file mode 100644 index 00000000..48eb0959 --- /dev/null +++ b/arch/arm/mach-msm/board-htcleo-spi.c @@ -0,0 +1,201 @@ +/* linux/driver/spi/spi_qsd.c +* +* Copyright (C) 2009 Solomon Chiu +* +* This is a temporary solution to substitute Qualcomm's SPI. +* Should be replaced by formal SPI driver in the future. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SPI_CONFIG (0x00000000) +#define SPI_IO_CONTROL (0x00000004) +#define SPI_OPERATIONAL (0x00000030) +#define SPI_ERROR_FLAGS_EN (0x00000038) +#define SPI_ERROR_FLAGS (0x00000038) +#define SPI_OUTPUT_FIFO (0x00000100) + +static void __iomem *spi_base; +static struct clk *spi_clk ; +static int clock_state; + +void qspi_enable() +{ + clk_enable(spi_clk); + clock_state = 1; +} + +void qspi_disable() +{ + clock_state = 0; + clk_disable(spi_clk); +} + +int qspi_send_16bit(unsigned char id, unsigned data) +{ + unsigned err ; + + if (!clock_state) + return -1; + + /* bit-5: OUTPUT_FIFO_NOT_EMPTY */ + while( readl(spi_base+SPI_OPERATIONAL) & (1<<5) ) + { + if( (err=readl(spi_base+SPI_ERROR_FLAGS)) ) + { + printk("\rERROR: SPI_ERROR_FLAGS=%d\r", err); + return -1; + } + } + + writel( (id<<13 | data)<<16, spi_base+SPI_OUTPUT_FIFO );/*AUO*/ + udelay(1000); + + return 0; +} + +int qspi_send_9bit(unsigned char id, unsigned data) +{ + unsigned err ; + + if (!clock_state) + return -1; + + /* bit-5: OUTPUT_FIFO_NOT_EMPTY */ + + while( readl(spi_base+SPI_OPERATIONAL) & (1<<5) ) + { + if( (err=readl(spi_base+SPI_ERROR_FLAGS)) ) + { + printk("\rERROR: SPI_ERROR_FLAGS=%d\r", err); + return -1; + } + } + + writel( ((id<<8) | data)<<23, spi_base+SPI_OUTPUT_FIFO);/*sharp*/ + + udelay(1000); + + return 0; +} + + +int qspi_send(unsigned char id, unsigned data) +{ + unsigned err ; + + if (!clock_state) + return -1; + + /* bit-5: OUTPUT_FIFO_NOT_EMPTY */ + + while( readl(spi_base+SPI_OPERATIONAL) & (1<<5) ) + { + if( (err=readl(spi_base+SPI_ERROR_FLAGS)) ) + { + printk("\rERROR: SPI_ERROR_FLAGS=%d\r", err); + return -1; + } + } + + writel( (0x7000 | id<<9 | data)<<16, spi_base+SPI_OUTPUT_FIFO ); + udelay(100); + + return 0; +} + +static int __init msm_spi_probe(struct platform_device *pdev) +{ + int rc ; + + spi_base=ioremap(0xA1200000, 4096); + if(!spi_base) + return -1; + + spi_clk = clk_get(&pdev->dev, "spi_clk"); + if (IS_ERR(spi_clk)) { + dev_err(&pdev->dev, "%s: unable to get spi_clk\n", __func__); + rc = PTR_ERR(spi_clk); + goto err_probe_clk_get; + } + rc = clk_enable(spi_clk); + if (rc) { + dev_err(&pdev->dev, "%s: unable to enable spi_clk\n", + __func__); + goto err_probe_clk_enable; + } + +// CotullaTODO: set same speed as in CE + // if(pdata == NULL) + clk_set_rate(spi_clk, 4800000); + // else + // clk_set_rate(spi_clk, pdata->clk_rate); + + printk(KERN_DEBUG "spi clk = 0x%ld\n", clk_get_rate(spi_clk)); + printk("spi: SPI_CONFIG=%x\n", readl(spi_base+SPI_CONFIG)); + printk("spi: SPI_IO_CONTROL=%x\n", readl(spi_base+SPI_IO_CONTROL)); + printk("spi: SPI_OPERATIONAL=%x\n", readl(spi_base+SPI_OPERATIONAL)); + printk("spi: SPI_ERROR_FLAGS_EN=%x\n", readl(spi_base+SPI_ERROR_FLAGS_EN)); + printk("spi: SPI_ERROR_FLAGS=%x\n", readl(spi_base+SPI_ERROR_FLAGS)); + printk("-%s()\n", __FUNCTION__); + clk_disable(spi_clk); + + return 0 ; + +err_probe_clk_get: +err_probe_clk_enable: + return -1 ; +} + +static int __devexit msm_spi_remove(struct platform_device *pdev) +{ + return 0; +} + +static int msm_spi_suspend(struct platform_device *pdev, pm_message_t state) +{ + printk("+%s()\n", __FUNCTION__); + clk_disable(spi_clk); + return 0 ; +} + +static int msm_spi_resume(struct platform_device *pdev) +{ + printk("+%s()\n", __FUNCTION__); + clk_enable(spi_clk); + return 0 ; +} + +static struct platform_driver msm_spi_driver = { + .probe = msm_spi_probe, + .driver = { + .name = "spi_qsd", + .owner = THIS_MODULE, + }, +#if 0 + .suspend = msm_spi_suspend, + .resume = msm_spi_resume, +#endif + .remove = __exit_p(msm_spi_remove), +}; + +static int __init msm_spi_init(void) +{ + return platform_driver_register(&msm_spi_driver); +} + +fs_initcall(msm_spi_init); diff --git a/arch/arm/mach-msm/board-htcleo.c b/arch/arm/mach-msm/board-htcleo.c index 54c8fabe..d06cab6c 100644 --- a/arch/arm/mach-msm/board-htcleo.c +++ b/arch/arm/mach-msm/board-htcleo.c @@ -39,6 +39,16 @@ #include "board-htcleo.h" #include "devices.h" +/////////////////////////////////////////////////////////////////////// +// SPI +/////////////////////////////////////////////////////////////////////// + +static struct platform_device qsd_device_spi = +{ + .name = "spi_qsd", + .id = 0, +}; + /* Vibrator */ static struct timed_gpio timed_gpios[] = { { @@ -68,6 +78,8 @@ static struct i2c_board_info base_i2c_devices[] = static struct platform_device *devices[] __initdata = { &msm_device_i2c, + &qsd_device_spi, + }; static struct msm_acpu_clock_platform_data htcleo_clock_data = {