/* 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 #include #define SPI_CONFIG (0x00000000) #define SPI_IO_CONTROL (0x00000004) #define SPI_OPERATIONAL (0x00000030) #define SPI_ERROR_FLAGS_EN (0x00000038) #define SPI_ERROR_FLAGS (0x00000034) #define SPI_OUTPUT_FIFO (0x00000100) #ifdef CONFIG_ARCH_MSM7X30 struct spi_device *spidev; extern int samsung_oled_panel_init(struct msm_lcdc_panel_ops *ops); int qspi_send_16bit(unsigned char id, unsigned data) { unsigned char buffer[4]; int tmp; tmp = (id<<13 | data)<<16; buffer[0] = tmp >> 24; buffer[1] = (tmp & 0x00FF0000) >> 16; buffer[2] = (tmp & 0x0000FF00) >> 8; buffer[3] = tmp & 0x000000FF; spi_write(spidev,buffer,4); return 0; } int qspi_send_9bit(struct spi_msg *msg) { int tmp = 0; spidev->bits_per_word = 9; tmp = (0x0 <<8 | msg->cmd)<<23; msg->buffer[0] = tmp >> 24; msg->buffer[1] = (tmp & 0x00FF0000) >> 16; if(msg->len != 0) { int i = 0, j; for(j = 2; i < msg->len; i++, j+=2){ tmp &= 0x00000000; tmp = (0x1<<8 | *(msg->data+i))<<23; msg->buffer[j] = tmp >> 24; msg->buffer[j+1] = (tmp & 0x00FF0000) >> 16; } } spi_read_write_lock(spidev, msg, NULL, 2, 1); return 0; } int qspi_send(unsigned char id, unsigned data) { unsigned char buffer[2]; int tmp; tmp = (0x7000 | id<<9 | data)<<16; spidev->bits_per_word = 16; buffer[0] = tmp >> 24; buffer[1] = (tmp & 0x00FF0000) >> 16; spi_write(spidev,buffer,2); return 0; } static int msm_spi_probe(struct spi_device *spi) { printk(" %s \n", __func__); spidev = spi; return 0 ; } static int msm_spi_remove(struct platform_device *pdev) { spidev = NULL; return 0; } static struct spi_driver spi_qsd = { .driver = { .name = "spi_qsd", .owner = THIS_MODULE, }, .probe = msm_spi_probe, .remove = __devexit_p(msm_spi_remove), }; static int __init spi_qsd_init(void) { int rc; rc = spi_register_driver(&spi_qsd); return rc; } module_init(spi_qsd_init); static void __exit spi_qsd_exit(void) { spi_unregister_driver(&spi_qsd); } module_exit(spi_qsd_exit); #else void __iomem *spi_base; struct clk *spi_clk ; int qspi_send_16bit(unsigned char id, unsigned data) { unsigned err ; /* bit-5: OUTPUT_FIFO_NOT_EMPTY */ clk_enable(spi_clk); 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); clk_disable(spi_clk); return 0; } int qspi_send_9bit(unsigned char id, unsigned data) { unsigned err ; /* bit-5: OUTPUT_FIFO_NOT_EMPTY */ clk_enable(spi_clk); 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); clk_disable(spi_clk); return 0; } int qspi_send(unsigned char id, unsigned data) { unsigned err ; /* bit-5: OUTPUT_FIFO_NOT_EMPTY */ clk_enable(spi_clk); 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); clk_disable(spi_clk); return 0; } static int __init msm_spi_probe(struct platform_device *pdev) { int rc ; struct spi_platform_data *pdata = pdev->dev.platform_data; 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; } 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); #endif