2005-04-16 15:20:36 -07:00
/*
* SSP control code for Sharp Corgi devices
*
2005-09-13 01:25:30 -07:00
* Copyright ( c ) 2004 - 2005 Richard Purdie
2005-04-16 15:20:36 -07:00
*
* 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 .
*
*/
# include <linux/module.h>
# include <linux/init.h>
# include <linux/kernel.h>
# include <linux/sched.h>
# include <linux/slab.h>
# include <linux/delay.h>
2005-10-29 19:07:23 +01:00
# include <linux/platform_device.h>
2005-04-16 15:20:36 -07:00
# include <asm/hardware.h>
2005-09-13 01:25:30 -07:00
# include <asm/mach-types.h>
2005-04-16 15:20:36 -07:00
# include <asm/arch/ssp.h>
# include <asm/arch/pxa-regs.h>
2005-09-13 01:25:30 -07:00
# include "sharpsl.h"
2005-04-16 15:20:36 -07:00
2005-09-09 13:10:41 -07:00
static DEFINE_SPINLOCK ( corgi_ssp_lock ) ;
2005-04-16 15:20:36 -07:00
static struct ssp_dev corgi_ssp_dev ;
static struct ssp_state corgi_ssp_state ;
2005-09-13 01:25:30 -07:00
static struct corgissp_machinfo * ssp_machinfo ;
2005-04-16 15:20:36 -07:00
/*
* There are three devices connected to the SSP interface :
* 1. A touchscreen controller ( TI ADS7846 compatible )
* 2. An LCD contoller ( with some Backlight functionality )
* 3. A battery moinitoring IC ( Maxim MAX1111 )
*
* Each device uses a different speed / mode of communication .
*
* The touchscreen is very sensitive and the most frequently used
* so the port is left configured for this .
*
* Devices are selected using Chip Selects on GPIOs .
*/
/*
* ADS7846 Routines
*/
unsigned long corgi_ssp_ads7846_putget ( ulong data )
{
unsigned long ret , flag ;
spin_lock_irqsave ( & corgi_ssp_lock , flag ) ;
2005-09-13 01:25:30 -07:00
GPCR ( ssp_machinfo - > cs_ads7846 ) = GPIO_bit ( ssp_machinfo - > cs_ads7846 ) ;
2005-04-16 15:20:36 -07:00
ssp_write_word ( & corgi_ssp_dev , data ) ;
ret = ssp_read_word ( & corgi_ssp_dev ) ;
2005-09-13 01:25:30 -07:00
GPSR ( ssp_machinfo - > cs_ads7846 ) = GPIO_bit ( ssp_machinfo - > cs_ads7846 ) ;
2005-04-16 15:20:36 -07:00
spin_unlock_irqrestore ( & corgi_ssp_lock , flag ) ;
return ret ;
}
/*
* NOTE : These functions should always be called in interrupt context
* and use the _lock and _unlock functions . They are very time sensitive .
*/
void corgi_ssp_ads7846_lock ( void )
{
spin_lock ( & corgi_ssp_lock ) ;
2005-09-13 01:25:30 -07:00
GPCR ( ssp_machinfo - > cs_ads7846 ) = GPIO_bit ( ssp_machinfo - > cs_ads7846 ) ;
2005-04-16 15:20:36 -07:00
}
void corgi_ssp_ads7846_unlock ( void )
{
2005-09-13 01:25:30 -07:00
GPSR ( ssp_machinfo - > cs_ads7846 ) = GPIO_bit ( ssp_machinfo - > cs_ads7846 ) ;
2005-04-16 15:20:36 -07:00
spin_unlock ( & corgi_ssp_lock ) ;
}
void corgi_ssp_ads7846_put ( ulong data )
{
ssp_write_word ( & corgi_ssp_dev , data ) ;
}
unsigned long corgi_ssp_ads7846_get ( void )
{
return ssp_read_word ( & corgi_ssp_dev ) ;
}
EXPORT_SYMBOL ( corgi_ssp_ads7846_putget ) ;
EXPORT_SYMBOL ( corgi_ssp_ads7846_lock ) ;
EXPORT_SYMBOL ( corgi_ssp_ads7846_unlock ) ;
EXPORT_SYMBOL ( corgi_ssp_ads7846_put ) ;
EXPORT_SYMBOL ( corgi_ssp_ads7846_get ) ;
/*
* LCD / Backlight Routines
*/
unsigned long corgi_ssp_dac_put ( ulong data )
{
2005-09-13 01:25:30 -07:00
unsigned long flag , sscr1 = SSCR1_SPH ;
2005-04-16 15:20:36 -07:00
spin_lock_irqsave ( & corgi_ssp_lock , flag ) ;
2005-09-13 01:25:30 -07:00
if ( machine_is_spitz ( ) | | machine_is_akita ( ) | | machine_is_borzoi ( ) )
sscr1 = 0 ;
2005-04-16 15:20:36 -07:00
ssp_disable ( & corgi_ssp_dev ) ;
2005-09-13 01:25:30 -07:00
ssp_config ( & corgi_ssp_dev , ( SSCR0_Motorola | ( SSCR0_DSS & 0x07 ) ) , sscr1 , 0 , SSCR0_SerClkDiv ( ssp_machinfo - > clk_lcdcon ) ) ;
2005-04-16 15:20:36 -07:00
ssp_enable ( & corgi_ssp_dev ) ;
2005-09-13 01:25:30 -07:00
GPCR ( ssp_machinfo - > cs_lcdcon ) = GPIO_bit ( ssp_machinfo - > cs_lcdcon ) ;
2005-04-16 15:20:36 -07:00
ssp_write_word ( & corgi_ssp_dev , data ) ;
/* Read null data back from device to prevent SSP overflow */
ssp_read_word ( & corgi_ssp_dev ) ;
2005-09-13 01:25:30 -07:00
GPSR ( ssp_machinfo - > cs_lcdcon ) = GPIO_bit ( ssp_machinfo - > cs_lcdcon ) ;
2005-04-16 15:20:36 -07:00
ssp_disable ( & corgi_ssp_dev ) ;
2005-09-13 01:25:30 -07:00
ssp_config ( & corgi_ssp_dev , ( SSCR0_National | ( SSCR0_DSS & 0x0b ) ) , 0 , 0 , SSCR0_SerClkDiv ( ssp_machinfo - > clk_ads7846 ) ) ;
2005-04-16 15:20:36 -07:00
ssp_enable ( & corgi_ssp_dev ) ;
2005-09-13 01:25:30 -07:00
2005-04-16 15:20:36 -07:00
spin_unlock_irqrestore ( & corgi_ssp_lock , flag ) ;
return 0 ;
}
void corgi_ssp_lcdtg_send ( u8 adrs , u8 data )
{
corgi_ssp_dac_put ( ( ( adrs & 0x07 ) < < 5 ) | ( data & 0x1f ) ) ;
}
void corgi_ssp_blduty_set ( int duty )
{
corgi_ssp_lcdtg_send ( 0x02 , duty ) ;
}
EXPORT_SYMBOL ( corgi_ssp_lcdtg_send ) ;
EXPORT_SYMBOL ( corgi_ssp_blduty_set ) ;
/*
* Max1111 Routines
*/
int corgi_ssp_max1111_get ( ulong data )
{
unsigned long flag ;
int voltage , voltage1 , voltage2 ;
spin_lock_irqsave ( & corgi_ssp_lock , flag ) ;
2005-09-13 01:25:30 -07:00
GPCR ( ssp_machinfo - > cs_max1111 ) = GPIO_bit ( ssp_machinfo - > cs_max1111 ) ;
2005-04-16 15:20:36 -07:00
ssp_disable ( & corgi_ssp_dev ) ;
2005-09-13 01:25:30 -07:00
ssp_config ( & corgi_ssp_dev , ( SSCR0_Motorola | ( SSCR0_DSS & 0x07 ) ) , 0 , 0 , SSCR0_SerClkDiv ( ssp_machinfo - > clk_max1111 ) ) ;
2005-04-16 15:20:36 -07:00
ssp_enable ( & corgi_ssp_dev ) ;
udelay ( 1 ) ;
/* TB1/RB1 */
ssp_write_word ( & corgi_ssp_dev , data ) ;
ssp_read_word ( & corgi_ssp_dev ) ; /* null read */
/* TB12/RB2 */
ssp_write_word ( & corgi_ssp_dev , 0 ) ;
voltage1 = ssp_read_word ( & corgi_ssp_dev ) ;
/* TB13/RB3*/
ssp_write_word ( & corgi_ssp_dev , 0 ) ;
voltage2 = ssp_read_word ( & corgi_ssp_dev ) ;
ssp_disable ( & corgi_ssp_dev ) ;
2005-09-13 01:25:30 -07:00
ssp_config ( & corgi_ssp_dev , ( SSCR0_National | ( SSCR0_DSS & 0x0b ) ) , 0 , 0 , SSCR0_SerClkDiv ( ssp_machinfo - > clk_ads7846 ) ) ;
2005-04-16 15:20:36 -07:00
ssp_enable ( & corgi_ssp_dev ) ;
2005-09-13 01:25:30 -07:00
GPSR ( ssp_machinfo - > cs_max1111 ) = GPIO_bit ( ssp_machinfo - > cs_max1111 ) ;
2005-04-16 15:20:36 -07:00
spin_unlock_irqrestore ( & corgi_ssp_lock , flag ) ;
if ( voltage1 & 0xc0 | | voltage2 & 0x3f )
voltage = - 1 ;
else
voltage = ( ( voltage1 < < 2 ) & 0xfc ) | ( ( voltage2 > > 6 ) & 0x03 ) ;
return voltage ;
}
EXPORT_SYMBOL ( corgi_ssp_max1111_get ) ;
/*
* Support Routines
*/
2005-09-13 01:25:30 -07:00
void __init corgi_ssp_set_machinfo ( struct corgissp_machinfo * machinfo )
{
ssp_machinfo = machinfo ;
}
static int __init corgi_ssp_probe ( struct device * dev )
2005-04-16 15:20:36 -07:00
{
int ret ;
/* Chip Select - Disable All */
2005-09-13 01:25:30 -07:00
GPDR ( ssp_machinfo - > cs_lcdcon ) | = GPIO_bit ( ssp_machinfo - > cs_lcdcon ) ; /* output */
GPSR ( ssp_machinfo - > cs_lcdcon ) = GPIO_bit ( ssp_machinfo - > cs_lcdcon ) ; /* High - Disable LCD Control/Timing Gen */
GPDR ( ssp_machinfo - > cs_max1111 ) | = GPIO_bit ( ssp_machinfo - > cs_max1111 ) ; /* output */
GPSR ( ssp_machinfo - > cs_max1111 ) = GPIO_bit ( ssp_machinfo - > cs_max1111 ) ; /* High - Disable MAX1111*/
GPDR ( ssp_machinfo - > cs_ads7846 ) | = GPIO_bit ( ssp_machinfo - > cs_ads7846 ) ; /* output */
GPSR ( ssp_machinfo - > cs_ads7846 ) = GPIO_bit ( ssp_machinfo - > cs_ads7846 ) ; /* High - Disable ADS7846*/
2005-04-16 15:20:36 -07:00
2005-09-13 01:25:30 -07:00
ret = ssp_init ( & corgi_ssp_dev , ssp_machinfo - > port ) ;
2005-04-16 15:20:36 -07:00
if ( ret )
printk ( KERN_ERR " Unable to register SSP handler! \n " ) ;
else {
ssp_disable ( & corgi_ssp_dev ) ;
2005-09-13 01:25:30 -07:00
ssp_config ( & corgi_ssp_dev , ( SSCR0_National | ( SSCR0_DSS & 0x0b ) ) , 0 , 0 , SSCR0_SerClkDiv ( ssp_machinfo - > clk_ads7846 ) ) ;
2005-04-16 15:20:36 -07:00
ssp_enable ( & corgi_ssp_dev ) ;
}
return ret ;
}
static int corgi_ssp_remove ( struct device * dev )
{
ssp_exit ( & corgi_ssp_dev ) ;
return 0 ;
}
2005-10-28 09:52:56 -07:00
static int corgi_ssp_suspend ( struct device * dev , pm_message_t state )
2005-04-16 15:20:36 -07:00
{
2005-10-28 09:52:56 -07:00
ssp_flush ( & corgi_ssp_dev ) ;
ssp_save_state ( & corgi_ssp_dev , & corgi_ssp_state ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2005-10-28 09:52:56 -07:00
static int corgi_ssp_resume ( struct device * dev )
2005-04-16 15:20:36 -07:00
{
2005-10-28 09:52:56 -07:00
GPSR ( ssp_machinfo - > cs_lcdcon ) = GPIO_bit ( ssp_machinfo - > cs_lcdcon ) ; /* High - Disable LCD Control/Timing Gen */
GPSR ( ssp_machinfo - > cs_max1111 ) = GPIO_bit ( ssp_machinfo - > cs_max1111 ) ; /* High - Disable MAX1111*/
GPSR ( ssp_machinfo - > cs_ads7846 ) = GPIO_bit ( ssp_machinfo - > cs_ads7846 ) ; /* High - Disable ADS7846*/
ssp_restore_state ( & corgi_ssp_dev , & corgi_ssp_state ) ;
ssp_enable ( & corgi_ssp_dev ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
static struct device_driver corgissp_driver = {
. name = " corgi-ssp " ,
. bus = & platform_bus_type ,
. probe = corgi_ssp_probe ,
. remove = corgi_ssp_remove ,
. suspend = corgi_ssp_suspend ,
. resume = corgi_ssp_resume ,
} ;
int __init corgi_ssp_init ( void )
{
return driver_register ( & corgissp_driver ) ;
}
arch_initcall ( corgi_ssp_init ) ;