2006-12-08 01:03:49 +03:00
/*
* linux / arch / arm / mach - omap2 / usb - tusb6010 . c
*
* Copyright ( C ) 2006 Nokia Corporation
*
* 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 .
*/
2013-02-21 23:01:47 +04:00
# include <linux/err.h>
2011-07-31 18:52:44 +04:00
# include <linux/string.h>
2006-12-08 01:03:49 +03:00
# include <linux/types.h>
# include <linux/errno.h>
# include <linux/delay.h>
# include <linux/platform_device.h>
2008-12-11 04:35:30 +03:00
# include <linux/gpio.h>
2011-08-01 00:17:29 +04:00
# include <linux/export.h>
2012-10-25 01:26:19 +04:00
# include <linux/platform_data/usb-omap.h>
2006-12-08 01:03:49 +03:00
# include <linux/usb/musb.h>
2012-10-05 09:07:27 +04:00
# include "gpmc.h"
2006-12-08 01:03:49 +03:00
static u8 async_cs , sync_cs ;
static unsigned refclk_psec ;
2013-02-21 23:46:22 +04:00
static struct gpmc_settings tusb_async = {
2013-02-21 23:01:47 +04:00
. wait_on_read = true ,
. wait_on_write = true ,
. device_width = GPMC_DEVWIDTH_16BIT ,
2013-02-21 23:46:22 +04:00
. mux_add_data = GPMC_MUX_AD ,
} ;
static struct gpmc_settings tusb_sync = {
2013-02-21 23:01:47 +04:00
. burst_read = true ,
. burst_write = true ,
2013-02-21 23:46:22 +04:00
. sync_read = true ,
. sync_write = true ,
2013-02-21 23:01:47 +04:00
. wait_on_read = true ,
. wait_on_write = true ,
. burst_len = GPMC_BURST_16 ,
. device_width = GPMC_DEVWIDTH_16BIT ,
2013-02-21 23:46:22 +04:00
. mux_add_data = GPMC_MUX_AD ,
} ;
2006-12-08 01:03:49 +03:00
/* NOTE: timings are from tusb 6010 datasheet Rev 1.8, 12-Sept 2006 */
2012-08-17 10:46:14 +04:00
static int tusb_set_async_mode ( unsigned sysclk_ps )
2006-12-08 01:03:49 +03:00
{
2012-08-17 10:46:14 +04:00
struct gpmc_device_timings dev_t ;
2006-12-08 01:03:49 +03:00
struct gpmc_timings t ;
unsigned t_acsnh_advnh = sysclk_ps + 3000 ;
2012-08-17 10:46:14 +04:00
memset ( & dev_t , 0 , sizeof ( dev_t ) ) ;
2006-12-08 01:03:49 +03:00
2012-08-17 10:46:14 +04:00
dev_t . t_ceasu = 8 * 1000 ;
dev_t . t_avdasu = t_acsnh_advnh - 7000 ;
dev_t . t_ce_avd = 1000 ;
dev_t . t_avdp_r = t_acsnh_advnh ;
dev_t . t_oeasu = t_acsnh_advnh + 1000 ;
dev_t . t_oe = 300 ;
dev_t . t_cez_r = 7000 ;
dev_t . t_cez_w = dev_t . t_cez_r ;
dev_t . t_avdp_w = t_acsnh_advnh ;
dev_t . t_weasu = t_acsnh_advnh + 1000 ;
dev_t . t_wpl = 300 ;
dev_t . cyc_aavdh_we = 1 ;
2006-12-08 01:03:49 +03:00
2013-02-21 23:46:22 +04:00
gpmc_calc_timings ( & t , & tusb_async , & dev_t ) ;
2006-12-08 01:03:49 +03:00
2015-02-27 18:56:53 +03:00
return gpmc_cs_set_timings ( async_cs , & t , & tusb_async ) ;
2006-12-08 01:03:49 +03:00
}
2012-08-17 10:46:14 +04:00
static int tusb_set_sync_mode ( unsigned sysclk_ps )
2006-12-08 01:03:49 +03:00
{
2012-08-17 10:46:14 +04:00
struct gpmc_device_timings dev_t ;
2006-12-08 01:03:49 +03:00
struct gpmc_timings t ;
unsigned t_scsnh_advnh = sysclk_ps + 3000 ;
2012-08-17 10:46:14 +04:00
memset ( & dev_t , 0 , sizeof ( dev_t ) ) ;
dev_t . clk = 11100 ;
dev_t . t_bacc = 1000 ;
dev_t . t_ces = 1000 ;
dev_t . t_ceasu = 8 * 1000 ;
dev_t . t_avdasu = t_scsnh_advnh - 7000 ;
dev_t . t_ce_avd = 1000 ;
dev_t . t_avdp_r = t_scsnh_advnh ;
dev_t . cyc_aavdh_oe = 3 ;
dev_t . cyc_oe = 5 ;
dev_t . t_ce_rdyz = 7000 ;
dev_t . t_avdp_w = t_scsnh_advnh ;
dev_t . cyc_aavdh_we = 3 ;
dev_t . cyc_wpl = 6 ;
2013-02-21 23:46:22 +04:00
gpmc_calc_timings ( & t , & tusb_sync , & dev_t ) ;
2012-05-28 16:21:37 +04:00
2015-02-27 18:56:53 +03:00
return gpmc_cs_set_timings ( sync_cs , & t , & tusb_sync ) ;
2006-12-08 01:03:49 +03:00
}
/* tusb driver calls this when it changes the chip's clocking */
int tusb6010_platform_retime ( unsigned is_refclk )
{
static const char error [ ] =
KERN_ERR " tusb6010 %s retime error %d \n " ;
unsigned sysclk_ps ;
int status ;
2012-08-17 10:46:14 +04:00
if ( ! refclk_psec )
2006-12-08 01:03:49 +03:00
return - ENODEV ;
sysclk_ps = is_refclk ? refclk_psec : TUSB6010_OSCCLK_60 ;
2012-08-17 10:46:14 +04:00
status = tusb_set_async_mode ( sysclk_ps ) ;
2006-12-08 01:03:49 +03:00
if ( status < 0 ) {
printk ( error , " async " , status ) ;
goto done ;
}
2012-08-17 10:46:14 +04:00
status = tusb_set_sync_mode ( sysclk_ps ) ;
2006-12-08 01:03:49 +03:00
if ( status < 0 )
printk ( error , " sync " , status ) ;
done :
return status ;
}
EXPORT_SYMBOL_GPL ( tusb6010_platform_retime ) ;
static struct resource tusb_resources [ ] = {
/* Order is significant! The start/end fields
* are updated during setup . .
*/
{ /* Asynchronous access */
. flags = IORESOURCE_MEM ,
} ,
{ /* Synchronous access */
. flags = IORESOURCE_MEM ,
} ,
{ /* IRQ */
2010-12-23 23:17:49 +03:00
. name = " mc " ,
2006-12-08 01:03:49 +03:00
. flags = IORESOURCE_IRQ ,
} ,
} ;
static u64 tusb_dmamask = ~ ( u32 ) 0 ;
static struct platform_device tusb_device = {
2010-12-02 10:13:54 +03:00
. name = " musb-tusb " ,
2006-12-08 01:03:49 +03:00
. id = - 1 ,
. dev = {
. dma_mask = & tusb_dmamask ,
. coherent_dma_mask = 0xffffffff ,
} ,
. num_resources = ARRAY_SIZE ( tusb_resources ) ,
. resource = tusb_resources ,
} ;
/* this may be called only from board-*.c setup code */
int __init
tusb6010_setup_interface ( struct musb_hdrc_platform_data * data ,
unsigned ps_refclk , unsigned waitpin ,
unsigned async , unsigned sync ,
unsigned irq , unsigned dmachan )
{
int status ;
static char error [ ] __initdata =
KERN_ERR " tusb6010 init error %d, %d \n " ;
/* ASYNC region, primarily for PIO */
status = gpmc_cs_request ( async , SZ_16M , ( unsigned long * )
& tusb_resources [ 0 ] . start ) ;
if ( status < 0 ) {
printk ( error , 1 , status ) ;
return status ;
}
tusb_resources [ 0 ] . end = tusb_resources [ 0 ] . start + 0x9ff ;
2013-02-21 23:01:47 +04:00
tusb_async . wait_pin = waitpin ;
2006-12-08 01:03:49 +03:00
async_cs = async ;
2013-02-21 23:01:47 +04:00
status = gpmc_cs_program_settings ( async_cs , & tusb_async ) ;
if ( status < 0 )
return status ;
2006-12-08 01:03:49 +03:00
/* SYNC region, primarily for DMA */
status = gpmc_cs_request ( sync , SZ_16M , ( unsigned long * )
& tusb_resources [ 1 ] . start ) ;
if ( status < 0 ) {
printk ( error , 2 , status ) ;
return status ;
}
tusb_resources [ 1 ] . end = tusb_resources [ 1 ] . start + 0x9ff ;
2013-02-21 23:01:47 +04:00
tusb_sync . wait_pin = waitpin ;
2006-12-08 01:03:49 +03:00
sync_cs = sync ;
2013-02-21 23:01:47 +04:00
status = gpmc_cs_program_settings ( sync_cs , & tusb_sync ) ;
if ( status < 0 )
return status ;
2006-12-08 01:03:49 +03:00
/* IRQ */
2011-05-03 19:22:09 +04:00
status = gpio_request_one ( irq , GPIOF_IN , " TUSB6010 irq " ) ;
2006-12-08 01:03:49 +03:00
if ( status < 0 ) {
printk ( error , 3 , status ) ;
return status ;
}
2012-06-20 18:18:15 +04:00
tusb_resources [ 2 ] . start = gpio_to_irq ( irq ) ;
2006-12-08 01:03:49 +03:00
/* set up memory timings ... can speed them up later */
if ( ! ps_refclk ) {
printk ( error , 4 , status ) ;
return - ENODEV ;
}
refclk_psec = ps_refclk ;
status = tusb6010_platform_retime ( 1 ) ;
if ( status < 0 ) {
printk ( error , 5 , status ) ;
return status ;
}
/* finish device setup ... */
if ( ! data ) {
printk ( error , 6 , status ) ;
return - ENODEV ;
}
tusb_device . dev . platform_data = data ;
/* so far so good ... register the device */
status = platform_device_register ( & tusb_device ) ;
if ( status < 0 ) {
printk ( error , 7 , status ) ;
return status ;
}
return 0 ;
}