2006-06-29 18:28:18 +04:00
/*
2012-03-12 22:54:50 +01:00
* driver for NXP USB Host devices
2006-06-29 18:28:18 +04:00
*
2012-03-12 22:54:50 +01:00
* Currently supported OHCI host devices :
2012-03-12 22:54:51 +01:00
* - NXP LPC32xx
2006-06-29 18:28:18 +04:00
*
* Authors : Dmitry Chigirev < source @ mvista . com >
2006-12-05 03:18:31 -08:00
* Vitaly Wool < vitalywool @ gmail . com >
2006-06-29 18:28:18 +04:00
*
* register initialization is based on code examples provided by Philips
* Copyright ( c ) 2005 Koninklijke Philips Electronics N . V .
*
* NOTE : This driver does not have suspend / resume functionality
* This driver is intended for engineering development purposes only
*
* 2005 - 2006 ( c ) MontaVista Software , Inc . This file is licensed under
* the terms of the GNU General Public License version 2. This program
* is licensed " as is " without any warranty of any kind , whether express
* or implied .
*/
# include <linux/clk.h>
2013-09-21 16:38:44 +05:30
# include <linux/dma-mapping.h>
# include <linux/io.h>
2006-06-29 18:28:18 +04:00
# include <linux/i2c.h>
2013-09-21 16:38:44 +05:30
# include <linux/kernel.h>
# include <linux/module.h>
2012-04-29 16:47:03 +02:00
# include <linux/of.h>
2013-09-21 16:38:44 +05:30
# include <linux/platform_device.h>
2012-04-29 16:47:06 +02:00
# include <linux/usb/isp1301.h>
2013-09-21 16:38:44 +05:30
# include <linux/usb.h>
# include <linux/usb/hcd.h>
# include "ohci.h"
2006-06-29 18:28:18 +04:00
2008-08-05 16:14:15 +01:00
# include <mach/hardware.h>
2012-03-12 22:54:51 +01:00
# include <asm/mach-types.h>
2006-06-29 18:28:18 +04:00
# include <asm/io.h>
2008-08-05 16:14:15 +01:00
# include <mach/platform.h>
# include <mach/irqs.h>
2006-06-29 18:28:18 +04:00
2012-03-12 22:54:51 +01:00
# define USB_CONFIG_BASE 0x31020000
# define PWRMAN_BASE 0x40004000
# define USB_CTRL IO_ADDRESS(PWRMAN_BASE + 0x64)
2006-06-29 18:28:18 +04:00
/* USB_CTRL bit defines */
# define USB_SLAVE_HCLK_EN (1 << 24)
2012-04-29 16:47:02 +02:00
# define USB_DEV_NEED_CLK_EN (1 << 22)
2006-06-29 18:28:18 +04:00
# define USB_HOST_NEED_CLK_EN (1 << 21)
2012-04-29 16:47:02 +02:00
# define PAD_CONTROL_LAST_DRIVEN (1 << 19)
2006-06-29 18:28:18 +04:00
2012-03-12 22:54:51 +01:00
# define USB_OTG_STAT_CONTROL IO_ADDRESS(USB_CONFIG_BASE + 0x110)
2006-06-29 18:28:18 +04:00
/* USB_OTG_STAT_CONTROL bit defines */
# define TRANSPARENT_I2C_EN (1 << 7)
# define HOST_EN (1 << 0)
2012-03-12 22:54:51 +01:00
/* On LPC32xx, those are undefined */
# ifndef start_int_set_falling_edge
# define start_int_set_falling_edge(irq)
# define start_int_set_rising_edge(irq)
# define start_int_ack(irq)
# define start_int_mask(irq)
# define start_int_umask(irq)
# endif
2013-09-21 16:38:44 +05:30
# define DRIVER_DESC "OHCI NXP driver"
static const char hcd_name [ ] = " ohci-nxp " ;
static struct hc_driver __read_mostly ohci_nxp_hc_driver ;
2009-10-01 19:03:13 +02:00
static struct i2c_client * isp1301_i2c_client ;
2006-06-29 18:28:18 +04:00
extern int usb_disabled ( void ) ;
2012-06-20 09:02:23 -03:00
static struct clk * usb_pll_clk ;
static struct clk * usb_dev_clk ;
static struct clk * usb_otg_clk ;
2006-06-29 18:28:18 +04:00
2012-03-12 22:54:51 +01:00
static void isp1301_configure_lpc32xx ( void )
{
/* LPC32XX only supports DAT_SE0 USB mode */
/* This sequence is important */
/* Disable transparent UART mode first */
i2c_smbus_write_byte_data ( isp1301_i2c_client ,
( ISP1301_I2C_MODE_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR ) ,
MC1_UART_EN ) ;
i2c_smbus_write_byte_data ( isp1301_i2c_client ,
( ISP1301_I2C_MODE_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR ) ,
~ MC1_SPEED_REG ) ;
i2c_smbus_write_byte_data ( isp1301_i2c_client ,
ISP1301_I2C_MODE_CONTROL_1 , MC1_SPEED_REG ) ;
i2c_smbus_write_byte_data ( isp1301_i2c_client ,
( ISP1301_I2C_MODE_CONTROL_2 | ISP1301_I2C_REG_CLEAR_ADDR ) ,
~ 0 ) ;
i2c_smbus_write_byte_data ( isp1301_i2c_client ,
ISP1301_I2C_MODE_CONTROL_2 ,
( MC2_BI_DI | MC2_PSW_EN | MC2_SPD_SUSP_CTRL ) ) ;
i2c_smbus_write_byte_data ( isp1301_i2c_client ,
( ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR ) , ~ 0 ) ;
i2c_smbus_write_byte_data ( isp1301_i2c_client ,
ISP1301_I2C_MODE_CONTROL_1 , MC1_DAT_SE0 ) ;
i2c_smbus_write_byte_data ( isp1301_i2c_client ,
ISP1301_I2C_OTG_CONTROL_1 ,
( OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN ) ) ;
i2c_smbus_write_byte_data ( isp1301_i2c_client ,
( ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR ) ,
( OTG1_DM_PULLUP | OTG1_DP_PULLUP ) ) ;
i2c_smbus_write_byte_data ( isp1301_i2c_client ,
ISP1301_I2C_INTERRUPT_LATCH | ISP1301_I2C_REG_CLEAR_ADDR , ~ 0 ) ;
i2c_smbus_write_byte_data ( isp1301_i2c_client ,
ISP1301_I2C_INTERRUPT_FALLING | ISP1301_I2C_REG_CLEAR_ADDR ,
~ 0 ) ;
i2c_smbus_write_byte_data ( isp1301_i2c_client ,
ISP1301_I2C_INTERRUPT_RISING | ISP1301_I2C_REG_CLEAR_ADDR , ~ 0 ) ;
/* Enable usb_need_clk clock after transceiver is initialized */
2012-04-29 16:47:02 +02:00
__raw_writel ( __raw_readl ( USB_CTRL ) | USB_HOST_NEED_CLK_EN , USB_CTRL ) ;
2012-03-12 22:54:51 +01:00
printk ( KERN_INFO " ISP1301 Vendor ID : 0x%04x \n " ,
i2c_smbus_read_word_data ( isp1301_i2c_client , 0x00 ) ) ;
printk ( KERN_INFO " ISP1301 Product ID : 0x%04x \n " ,
i2c_smbus_read_word_data ( isp1301_i2c_client , 0x02 ) ) ;
printk ( KERN_INFO " ISP1301 Version ID : 0x%04x \n " ,
i2c_smbus_read_word_data ( isp1301_i2c_client , 0x14 ) ) ;
}
static void isp1301_configure ( void )
{
2012-08-26 16:30:37 +02:00
isp1301_configure_lpc32xx ( ) ;
2006-06-29 18:28:18 +04:00
}
static inline void isp1301_vbus_on ( void )
{
2012-03-12 22:54:52 +01:00
i2c_smbus_write_byte_data ( isp1301_i2c_client , ISP1301_I2C_OTG_CONTROL_1 ,
OTG1_VBUS_DRV ) ;
2006-06-29 18:28:18 +04:00
}
static inline void isp1301_vbus_off ( void )
{
2012-03-12 22:54:52 +01:00
i2c_smbus_write_byte_data ( isp1301_i2c_client ,
ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR ,
OTG1_VBUS_DRV ) ;
2006-06-29 18:28:18 +04:00
}
2013-09-21 16:38:44 +05:30
static void ohci_nxp_start_hc ( void )
2006-06-29 18:28:18 +04:00
{
unsigned long tmp = __raw_readl ( USB_OTG_STAT_CONTROL ) | HOST_EN ;
__raw_writel ( tmp , USB_OTG_STAT_CONTROL ) ;
isp1301_vbus_on ( ) ;
}
2013-09-21 16:38:44 +05:30
static void ohci_nxp_stop_hc ( void )
2006-06-29 18:28:18 +04:00
{
unsigned long tmp ;
isp1301_vbus_off ( ) ;
tmp = __raw_readl ( USB_OTG_STAT_CONTROL ) & ~ HOST_EN ;
__raw_writel ( tmp , USB_OTG_STAT_CONTROL ) ;
}
2013-09-21 16:38:44 +05:30
static int ohci_hcd_nxp_probe ( struct platform_device * pdev )
2006-06-29 18:28:18 +04:00
{
struct usb_hcd * hcd = 0 ;
2012-03-12 22:54:50 +01:00
const struct hc_driver * driver = & ohci_nxp_hc_driver ;
2012-04-29 16:47:02 +02:00
struct resource * res ;
2006-06-29 18:28:18 +04:00
int ret = 0 , irq ;
2012-04-29 16:47:06 +02:00
struct device_node * isp1301_node ;
if ( pdev - > dev . of_node ) {
isp1301_node = of_parse_phandle ( pdev - > dev . of_node ,
" transceiver " , 0 ) ;
} else {
isp1301_node = NULL ;
}
isp1301_i2c_client = isp1301_get_client ( isp1301_node ) ;
if ( ! isp1301_i2c_client ) {
2013-05-10 14:22:42 +08:00
return - EPROBE_DEFER ;
2012-04-29 16:47:06 +02:00
}
2006-06-29 18:28:18 +04:00
2013-06-27 12:36:37 +01:00
ret = dma_coerce_mask_and_coherent ( & pdev - > dev , DMA_BIT_MASK ( 32 ) ) ;
2013-06-10 16:28:49 +01:00
if ( ret )
goto fail_disable ;
2012-04-29 16:47:02 +02:00
2012-03-12 22:54:50 +01:00
dev_dbg ( & pdev - > dev , " %s: " DRIVER_DESC " (nxp) \n " , hcd_name ) ;
2006-06-29 18:28:18 +04:00
if ( usb_disabled ( ) ) {
2012-04-27 11:24:41 -07:00
dev_err ( & pdev - > dev , " USB is disabled \n " ) ;
2006-06-29 18:28:18 +04:00
ret = - ENODEV ;
2013-05-10 14:22:42 +08:00
goto fail_disable ;
2006-06-29 18:28:18 +04:00
}
/* Enable AHB slave USB clock, needed for further USB clock control */
2012-04-29 16:47:02 +02:00
__raw_writel ( USB_SLAVE_HCLK_EN | PAD_CONTROL_LAST_DRIVEN , USB_CTRL ) ;
2006-06-29 18:28:18 +04:00
/* Enable USB PLL */
2013-12-11 16:30:35 +09:00
usb_pll_clk = devm_clk_get ( & pdev - > dev , " ck_pll5 " ) ;
2012-06-20 09:02:23 -03:00
if ( IS_ERR ( usb_pll_clk ) ) {
2012-04-27 11:24:41 -07:00
dev_err ( & pdev - > dev , " failed to acquire USB PLL \n " ) ;
2012-06-20 09:02:23 -03:00
ret = PTR_ERR ( usb_pll_clk ) ;
2013-12-11 16:30:35 +09:00
goto fail_disable ;
2006-06-29 18:28:18 +04:00
}
2012-06-20 09:02:23 -03:00
ret = clk_enable ( usb_pll_clk ) ;
2006-06-29 18:28:18 +04:00
if ( ret < 0 ) {
2012-04-27 11:24:41 -07:00
dev_err ( & pdev - > dev , " failed to start USB PLL \n " ) ;
2013-12-11 16:30:35 +09:00
goto fail_disable ;
2006-06-29 18:28:18 +04:00
}
2012-06-20 09:02:23 -03:00
ret = clk_set_rate ( usb_pll_clk , 48000 ) ;
2006-06-29 18:28:18 +04:00
if ( ret < 0 ) {
2012-04-27 11:24:41 -07:00
dev_err ( & pdev - > dev , " failed to set USB clock rate \n " ) ;
2013-05-10 14:22:42 +08:00
goto fail_rate ;
2006-06-29 18:28:18 +04:00
}
2012-06-20 09:02:23 -03:00
/* Enable USB device clock */
2013-12-11 16:30:35 +09:00
usb_dev_clk = devm_clk_get ( & pdev - > dev , " ck_usbd " ) ;
2012-06-20 09:02:23 -03:00
if ( IS_ERR ( usb_dev_clk ) ) {
dev_err ( & pdev - > dev , " failed to acquire USB DEV Clock \n " ) ;
ret = PTR_ERR ( usb_dev_clk ) ;
2013-12-11 16:30:35 +09:00
goto fail_rate ;
2012-06-20 09:02:23 -03:00
}
ret = clk_enable ( usb_dev_clk ) ;
if ( ret < 0 ) {
dev_err ( & pdev - > dev , " failed to start USB DEV Clock \n " ) ;
2013-12-11 16:30:35 +09:00
goto fail_rate ;
2012-06-20 09:02:23 -03:00
}
/* Enable USB otg clocks */
2013-12-11 16:30:35 +09:00
usb_otg_clk = devm_clk_get ( & pdev - > dev , " ck_usb_otg " ) ;
2012-06-20 09:02:23 -03:00
if ( IS_ERR ( usb_otg_clk ) ) {
dev_err ( & pdev - > dev , " failed to acquire USB DEV Clock \n " ) ;
2012-08-25 21:57:07 +02:00
ret = PTR_ERR ( usb_otg_clk ) ;
2013-05-10 14:22:42 +08:00
goto fail_otg ;
2012-06-20 09:02:23 -03:00
}
2006-06-29 18:28:18 +04:00
__raw_writel ( __raw_readl ( USB_CTRL ) | USB_HOST_NEED_CLK_EN , USB_CTRL ) ;
2012-06-20 09:02:23 -03:00
ret = clk_enable ( usb_otg_clk ) ;
if ( ret < 0 ) {
dev_err ( & pdev - > dev , " failed to start USB DEV Clock \n " ) ;
2013-12-11 16:30:35 +09:00
goto fail_otg ;
2012-06-20 09:02:23 -03:00
}
2006-06-29 18:28:18 +04:00
2012-06-20 09:02:23 -03:00
isp1301_configure ( ) ;
2006-06-29 18:28:18 +04:00
2012-04-29 16:47:02 +02:00
hcd = usb_create_hcd ( driver , & pdev - > dev , dev_name ( & pdev - > dev ) ) ;
2006-06-29 18:28:18 +04:00
if ( ! hcd ) {
2012-04-27 11:24:41 -07:00
dev_err ( & pdev - > dev , " Failed to allocate HC buffer \n " ) ;
2006-06-29 18:28:18 +04:00
ret = - ENOMEM ;
2013-05-10 14:22:42 +08:00
goto fail_hcd ;
2006-06-29 18:28:18 +04:00
}
2012-04-29 16:47:02 +02:00
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
2013-01-21 11:09:22 +01:00
hcd - > regs = devm_ioremap_resource ( & pdev - > dev , res ) ;
if ( IS_ERR ( hcd - > regs ) ) {
ret = PTR_ERR ( hcd - > regs ) ;
2013-05-10 14:22:42 +08:00
goto fail_resource ;
2006-06-29 18:28:18 +04:00
}
2012-04-29 16:47:02 +02:00
hcd - > rsrc_start = res - > start ;
hcd - > rsrc_len = resource_size ( res ) ;
2006-06-29 18:28:18 +04:00
irq = platform_get_irq ( pdev , 0 ) ;
if ( irq < 0 ) {
ret = - ENXIO ;
2013-05-10 14:22:42 +08:00
goto fail_resource ;
2006-06-29 18:28:18 +04:00
}
2013-09-21 16:38:44 +05:30
ohci_nxp_start_hc ( ) ;
2006-06-29 18:28:18 +04:00
platform_set_drvdata ( pdev , hcd ) ;
dev_info ( & pdev - > dev , " at 0x%p, irq %d \n " , hcd - > regs , hcd - > irq ) ;
2011-09-07 16:10:52 +08:00
ret = usb_add_hcd ( hcd , irq , 0 ) ;
2013-11-05 10:46:02 +08:00
if ( ret = = 0 ) {
device_wakeup_enable ( hcd - > self . controller ) ;
2006-06-29 18:28:18 +04:00
return ret ;
2013-11-05 10:46:02 +08:00
}
2006-06-29 18:28:18 +04:00
2013-09-21 16:38:44 +05:30
ohci_nxp_stop_hc ( ) ;
2013-05-10 14:22:42 +08:00
fail_resource :
2006-06-29 18:28:18 +04:00
usb_put_hcd ( hcd ) ;
2013-05-10 14:22:42 +08:00
fail_hcd :
2012-06-20 09:02:23 -03:00
clk_disable ( usb_otg_clk ) ;
2013-05-10 14:22:42 +08:00
fail_otg :
2012-06-20 09:02:23 -03:00
clk_disable ( usb_dev_clk ) ;
2013-05-10 14:22:42 +08:00
fail_rate :
2012-06-20 09:02:23 -03:00
clk_disable ( usb_pll_clk ) ;
2013-05-10 14:22:42 +08:00
fail_disable :
2008-11-13 18:57:53 +01:00
isp1301_i2c_client = NULL ;
2006-06-29 18:28:18 +04:00
return ret ;
}
2013-09-21 16:38:44 +05:30
static int ohci_hcd_nxp_remove ( struct platform_device * pdev )
2006-06-29 18:28:18 +04:00
{
struct usb_hcd * hcd = platform_get_drvdata ( pdev ) ;
usb_remove_hcd ( hcd ) ;
2013-09-21 16:38:44 +05:30
ohci_nxp_stop_hc ( ) ;
2006-06-29 18:28:18 +04:00
usb_put_hcd ( hcd ) ;
2012-06-20 09:02:23 -03:00
clk_disable ( usb_pll_clk ) ;
clk_disable ( usb_dev_clk ) ;
2010-02-19 15:42:00 +01:00
i2c_unregister_device ( isp1301_i2c_client ) ;
2008-11-13 18:57:53 +01:00
isp1301_i2c_client = NULL ;
2006-06-29 18:28:18 +04:00
return 0 ;
}
2008-04-10 21:29:22 -07:00
/* work with hotplug and coldplug */
MODULE_ALIAS ( " platform:usb-ohci " ) ;
2012-04-29 16:47:03 +02:00
# ifdef CONFIG_OF
2013-09-21 16:38:44 +05:30
static const struct of_device_id ohci_hcd_nxp_match [ ] = {
2012-04-29 16:47:03 +02:00
{ . compatible = " nxp,ohci-nxp " } ,
{ } ,
} ;
2013-09-21 16:38:44 +05:30
MODULE_DEVICE_TABLE ( of , ohci_hcd_nxp_match ) ;
2012-04-29 16:47:03 +02:00
# endif
2013-09-21 16:38:44 +05:30
static struct platform_driver ohci_hcd_nxp_driver = {
2006-06-29 18:28:18 +04:00
. driver = {
. name = " usb-ohci " ,
2008-04-10 21:29:22 -07:00
. owner = THIS_MODULE ,
2013-09-21 16:38:44 +05:30
. of_match_table = of_match_ptr ( ohci_hcd_nxp_match ) ,
2006-06-29 18:28:18 +04:00
} ,
2013-09-21 16:38:44 +05:30
. probe = ohci_hcd_nxp_probe ,
. remove = ohci_hcd_nxp_remove ,
2006-06-29 18:28:18 +04:00
} ;
2013-09-21 16:38:44 +05:30
static int __init ohci_nxp_init ( void )
{
if ( usb_disabled ( ) )
return - ENODEV ;
pr_info ( " %s: " DRIVER_DESC " \n " , hcd_name ) ;
ohci_init_driver ( & ohci_nxp_hc_driver , NULL ) ;
return platform_driver_register ( & ohci_hcd_nxp_driver ) ;
}
module_init ( ohci_nxp_init ) ;
static void __exit ohci_nxp_cleanup ( void )
{
platform_driver_unregister ( & ohci_hcd_nxp_driver ) ;
}
module_exit ( ohci_nxp_cleanup ) ;
MODULE_DESCRIPTION ( DRIVER_DESC ) ;
MODULE_LICENSE ( " GPL v2 " ) ;