/* * Media5200 touchscreen driver * * Copyright (c) 2006 Freescale * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published by * the Free Software Foundation. */ /* File : mpc5200_ts_spi.c Summary : touchscreen spi driver */ #include "mpc5200_ts_spi.h" #include "asm/io.h" /**************** Public functions ****************/ /* Initialize and configure spi - configure mux port on psc3 - configure spi mode - configure spi baud rate */ int spi_init (void) { struct mpc52xx_gpio __iomem *gpio; struct mpc52xx_intr __iomem *intr; /* Map zones */ gpio = ioremap(MPC52xx_PA(MPC52xx_GPIO_OFFSET), MPC52xx_GPIO_SIZE); intr = ioremap(MPC52xx_PA(MPC52xx_INTR_OFFSET), MPC52xx_INTR_SIZE); if (!gpio || !intr) { printk(KERN_ERR __FILE__ ": " "Error while mapping GPIO/INTR during " "spi_init\n"); goto unmap_regs; } SPI_Config_T spi_config; /* spi configuration */ PDEBUG3("spin_init: initializing SPI in spi_init()\n"); /* enable interrupt */ intr->per_mask &= INTR_PER_MASK_SPI_OFF; /* initialize mux port PSC3 to SPI */ gpio->port_config |= GPIO_CONFIG_PORT_SPI_MASK; /* initialze data structure */ SPI_Regs = (SPI_Regs_T *)(SPI_BASE_ADDRESS); memset(&spi_config, 0, sizeof(SPI_Config_T)); /* set spi config attributes */ spi_config.SPI_Master = SPI_MASTER_DEFAULT; spi_config.ClockPolarity = SPI_CPOL_DEFAULT; spi_config.ClockPhase = SPI_CPHA_DEFAULT; spi_config.WiredOR = SPI_WOR_DEFAULT; spi_config.SSoutput = SPI_SSOE_DEFAULT; spi_config.SPI_Enable = SPI_SPE_DEFAULT; spi_config.BaudRate = SPI_BAUD_DEFAULT; /* modify according to touchscreen driver spi config */ spi_config.ClockPolarity = 0; spi_config.ClockPhase = 0 ; spi_config.WiredOR = 0; /*Set the SS pin to low by set SPIPORT register*/ SPI_Regs->SPIPORT = 0x00; /* now initialize the spi hardware */ SPI_SetConfig(&spi_config); /* Unmap reg zone */ unmap_regs: if (gpio) iounmap(gpio); if (intr) iounmap(intr); return (TS_OK); } /* assume *buffer already alocated to be at least nbytes long */ int read_spi(u8 *buffer, u32 nbytes) { int i; for (i = 0; i < nbytes; i++) { buffer[i] = ReadRegister(SPI_Regs->SPIDR); } /* for */ return (nbytes); } /* read_spi */ int write_spi( u8 *buffer, u32 nbytes) { u32 len; u8 reg_value; // Move this to one devctl command // SPI_Regs->SPIPORT = 0x00; for ( len = 0; len < nbytes; len++ ) { PDEBUG9("in write_spi: buffer = %x\n", *buffer); WriteRegister(SPI_Regs->SPIDR,*buffer); /* Wait several nanoseconds and then check the WCOL flag in status * register. WeiWei systest replace it with the for-loop directly */ // WAIT(NANOSECS_PER_WRITE); while(1) { reg_value = ReadRegister(SPI_Regs->SPISR); if (reg_value & SPI_WCOL) { WriteRegister(SPI_Regs->SPIDR,*buffer); continue; } if ( reg_value & SPI_SPIF ) break; } //SPI_Isr(); buffer++; } /* WeiWei add : hardware team suggestion, but it is optional */ // SPI_Regs->SPIPORT = 0x08; return len; } /*************** Private functions ********************/ static int SPI_SetConfig(SPI_Config_T * Config_Ptr ) { u8 control_reg = 0x00; /* initialize direction register for SPI */ WriteRegister ( SPI_Regs->SPIDDR, 0x0e ); /* Set Baud Rate */ if(SPI_SetBaudrate( Config_Ptr -> BaudRate) == TS_ERROR ) { PDEBUG3("SPI_SetConfig: Error in Set baudrate \n"); WriteRegister(SPI_Regs->SPICR1, control_reg | SPI_SPE); return TS_ERROR; } /* aways master */ control_reg |= SPI_MASTER_MODE; /* The SSOE for master mode */ control_reg &= ~SPI_SSOE; if(Config_Ptr -> ClockPolarity) control_reg |= SPI_CPOL; else control_reg &= ~SPI_CPOL; if(Config_Ptr -> ClockPhase) control_reg |= SPI_CPHA; else control_reg &= ~SPI_CPHA; if(Config_Ptr -> WiredOR) control_reg |= SPI_SPWOM; else control_reg &= ~SPI_SPWOM; /* always enable SPI */ control_reg |= SPI_SPE; /* Enable the interrupt and set the register : WeiWei systest */ WriteRegister(SPI_Regs->SPICR1, control_reg | SPI_SPIE ); PDEBUG3("SPI_SetCconfig : SPICR1 =%x \n",SPI_Regs->SPICR1); return TS_OK ; } static int SPI_SetBaudrate(u32 BaudRate) { int i; u16 clockdivisor; /* Compute the Clock Divisor from module clock divided by BaudRate */ clockdivisor = SPI_MODULE_CLOCK/BaudRate; /* Find the value of the Baud Rate Register from the array. * If no accurate value can be found, select the closest one */ for (i = 0; i < SPI_DIVISOR_NUM-1; i++) { if(( clockdivisor >= Clock_Divisor[i].clockdivisor ) && \ ( clockdivisor < Clock_Divisor[i+1].clockdivisor)) { u16 middle; middle = (Clock_Divisor[i].clockdivisor + \ Clock_Divisor[i+1].clockdivisor)/2; if ( clockdivisor <= middle ) { WriteRegister(SPI_Regs->SPIBR, \ Clock_Divisor[i].reg_value); PDEBUG3("SPI_SetBaudrate: Baudrate %d\n", SPI_MODULE_CLOCK/Clock_Divisor[i].clockdivisor); } else { WriteRegister(SPI_Regs->SPIBR, \ Clock_Divisor[i+1].reg_value); PDEBUG3("SPI_SetBaudrate: Baudrate %d\n", SPI_MODULE_CLOCK/Clock_Divisor[i+1].clockdivisor); } return TS_OK; } } if ( clockdivisor == Clock_Divisor[i].clockdivisor ) { WriteRegister(SPI_Regs->SPIBR, Clock_Divisor[i].reg_value); PDEBUG3("SPI_SetBaudrate: Exact Baudrate %d\n", SPI_MODULE_CLOCK/clockdivisor); return TS_OK; } else return TS_ERROR; }