2012-05-11 17:25:54 +03:00
/*
* host . c - ChipIdea USB host controller driver
*
* Copyright ( c ) 2012 Intel Corporation
*
* Author : Alexander Shishkin
*
* 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 .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include <linux/kernel.h>
2012-11-03 12:39:27 -04:00
# include <linux/io.h>
2012-05-11 17:25:54 +03:00
# include <linux/usb.h>
# include <linux/usb/hcd.h>
# include <linux/usb/chipidea.h>
2012-11-02 12:34:41 -04:00
# include "../host/ehci.h"
2012-05-11 17:25:54 +03:00
# include "ci.h"
# include "bits.h"
# include "host.h"
2012-11-02 12:34:41 -04:00
static struct hc_driver __read_mostly ci_ehci_hc_driver ;
2012-05-11 17:25:54 +03:00
static irqreturn_t host_irq ( struct ci13xxx * ci )
{
return usb_hcd_irq ( ci - > irq , ci - > hcd ) ;
}
static int host_start ( struct ci13xxx * ci )
{
struct usb_hcd * hcd ;
struct ehci_hcd * ehci ;
int ret ;
if ( usb_disabled ( ) )
return - ENODEV ;
hcd = usb_create_hcd ( & ci_ehci_hc_driver , ci - > dev , dev_name ( ci - > dev ) ) ;
if ( ! hcd )
return - ENOMEM ;
dev_set_drvdata ( ci - > dev , ci ) ;
hcd - > rsrc_start = ci - > hw_bank . phys ;
hcd - > rsrc_len = ci - > hw_bank . size ;
hcd - > regs = ci - > hw_bank . abs ;
hcd - > has_tt = 1 ;
2012-06-29 17:48:53 +08:00
hcd - > power_budget = ci - > platdata - > power_budget ;
2012-07-07 22:56:46 +08:00
hcd - > phy = ci - > transceiver ;
2012-05-11 17:25:55 +03:00
2012-05-11 17:25:54 +03:00
ehci = hcd_to_ehci ( hcd ) ;
ehci - > caps = ci - > hw_bank . cap ;
ehci - > has_hostpc = ci - > hw_bank . lpm ;
ret = usb_add_hcd ( hcd , 0 , 0 ) ;
if ( ret )
2012-05-15 06:10:21 +02:00
usb_put_hcd ( hcd ) ;
2012-05-11 17:25:54 +03:00
else
ci - > hcd = hcd ;
2012-12-22 09:24:11 -02:00
if ( ci - > platdata - > flags & CI13XXX_DISABLE_STREAMING )
hw_write ( ci , OP_USBMODE , USBMODE_CI_SDIS , USBMODE_CI_SDIS ) ;
2012-05-11 17:25:54 +03:00
return ret ;
}
static void host_stop ( struct ci13xxx * ci )
{
struct usb_hcd * hcd = ci - > hcd ;
usb_remove_hcd ( hcd ) ;
usb_put_hcd ( hcd ) ;
}
int ci_hdrc_host_init ( struct ci13xxx * ci )
{
struct ci_role_driver * rdrv ;
if ( ! hw_read ( ci , CAP_DCCPARAMS , DCCPARAMS_HC ) )
return - ENXIO ;
rdrv = devm_kzalloc ( ci - > dev , sizeof ( struct ci_role_driver ) , GFP_KERNEL ) ;
if ( ! rdrv )
return - ENOMEM ;
rdrv - > start = host_start ;
rdrv - > stop = host_stop ;
rdrv - > irq = host_irq ;
rdrv - > name = " host " ;
ci - > roles [ CI_ROLE_HOST ] = rdrv ;
2012-11-07 16:12:47 -05:00
ehci_init_driver ( & ci_ehci_hc_driver , NULL ) ;
2012-11-02 12:34:41 -04:00
2012-05-11 17:25:54 +03:00
return 0 ;
}