1eb70e5abSAlexander Shishkin /* 2eb70e5abSAlexander Shishkin * host.c - ChipIdea USB host controller driver 3eb70e5abSAlexander Shishkin * 4eb70e5abSAlexander Shishkin * Copyright (c) 2012 Intel Corporation 5eb70e5abSAlexander Shishkin * 6eb70e5abSAlexander Shishkin * Author: Alexander Shishkin 7eb70e5abSAlexander Shishkin * 8eb70e5abSAlexander Shishkin * This program is free software; you can redistribute it and/or modify 9eb70e5abSAlexander Shishkin * it under the terms of the GNU General Public License version 2 as 10eb70e5abSAlexander Shishkin * published by the Free Software Foundation. 11eb70e5abSAlexander Shishkin * 12eb70e5abSAlexander Shishkin * This program is distributed in the hope that it will be useful, 13eb70e5abSAlexander Shishkin * but WITHOUT ANY WARRANTY; without even the implied warranty of 14eb70e5abSAlexander Shishkin * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15eb70e5abSAlexander Shishkin * GNU General Public License for more details. 16eb70e5abSAlexander Shishkin * 17eb70e5abSAlexander Shishkin * You should have received a copy of the GNU General Public License 18eb70e5abSAlexander Shishkin * along with this program; if not, write to the Free Software 19eb70e5abSAlexander Shishkin * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20eb70e5abSAlexander Shishkin */ 21eb70e5abSAlexander Shishkin 22eb70e5abSAlexander Shishkin #include <linux/kernel.h> 23cdb2fac7SAlan Stern #include <linux/io.h> 24eb70e5abSAlexander Shishkin #include <linux/usb.h> 25eb70e5abSAlexander Shishkin #include <linux/usb/hcd.h> 26eb70e5abSAlexander Shishkin #include <linux/usb/chipidea.h> 2740ed51a4SPeter Chen #include <linux/regulator/consumer.h> 28eb70e5abSAlexander Shishkin 2909f6ffdeSAlan Stern #include "../host/ehci.h" 30eb70e5abSAlexander Shishkin 31eb70e5abSAlexander Shishkin #include "ci.h" 32eb70e5abSAlexander Shishkin #include "bits.h" 33eb70e5abSAlexander Shishkin #include "host.h" 34eb70e5abSAlexander Shishkin 3509f6ffdeSAlan Stern static struct hc_driver __read_mostly ci_ehci_hc_driver; 3609f6ffdeSAlan Stern 378e22978cSAlexander Shishkin static irqreturn_t host_irq(struct ci_hdrc *ci) 38eb70e5abSAlexander Shishkin { 39eb70e5abSAlexander Shishkin return usb_hcd_irq(ci->irq, ci->hcd); 40eb70e5abSAlexander Shishkin } 41eb70e5abSAlexander Shishkin 428e22978cSAlexander Shishkin static int host_start(struct ci_hdrc *ci) 43eb70e5abSAlexander Shishkin { 44eb70e5abSAlexander Shishkin struct usb_hcd *hcd; 45eb70e5abSAlexander Shishkin struct ehci_hcd *ehci; 46eb70e5abSAlexander Shishkin int ret; 47eb70e5abSAlexander Shishkin 48eb70e5abSAlexander Shishkin if (usb_disabled()) 49eb70e5abSAlexander Shishkin return -ENODEV; 50eb70e5abSAlexander Shishkin 51eb70e5abSAlexander Shishkin hcd = usb_create_hcd(&ci_ehci_hc_driver, ci->dev, dev_name(ci->dev)); 52eb70e5abSAlexander Shishkin if (!hcd) 53eb70e5abSAlexander Shishkin return -ENOMEM; 54eb70e5abSAlexander Shishkin 55eb70e5abSAlexander Shishkin dev_set_drvdata(ci->dev, ci); 56eb70e5abSAlexander Shishkin hcd->rsrc_start = ci->hw_bank.phys; 57eb70e5abSAlexander Shishkin hcd->rsrc_len = ci->hw_bank.size; 58eb70e5abSAlexander Shishkin hcd->regs = ci->hw_bank.abs; 59eb70e5abSAlexander Shishkin hcd->has_tt = 1; 60eb70e5abSAlexander Shishkin 6177c4400fSRichard Zhao hcd->power_budget = ci->platdata->power_budget; 62a2c3d690SRichard Zhao hcd->phy = ci->transceiver; 63bd841986SAlexander Shishkin 64eb70e5abSAlexander Shishkin ehci = hcd_to_ehci(hcd); 65eb70e5abSAlexander Shishkin ehci->caps = ci->hw_bank.cap; 66eb70e5abSAlexander Shishkin ehci->has_hostpc = ci->hw_bank.lpm; 672cdcec4fSTuomas Tynkkynen ehci->has_tdi_phy_lpm = ci->hw_bank.lpm; 68ed8f8318SPeter Chen ehci->imx28_write_fix = ci->imx28_write_fix; 69eb70e5abSAlexander Shishkin 7040ed51a4SPeter Chen if (ci->platdata->reg_vbus) { 7140ed51a4SPeter Chen ret = regulator_enable(ci->platdata->reg_vbus); 7240ed51a4SPeter Chen if (ret) { 7340ed51a4SPeter Chen dev_err(ci->dev, 7440ed51a4SPeter Chen "Failed to enable vbus regulator, ret=%d\n", 7540ed51a4SPeter Chen ret); 7640ed51a4SPeter Chen goto put_hcd; 7740ed51a4SPeter Chen } 7840ed51a4SPeter Chen } 7940ed51a4SPeter Chen 80eb70e5abSAlexander Shishkin ret = usb_add_hcd(hcd, 0, 0); 81eb70e5abSAlexander Shishkin if (ret) 8240ed51a4SPeter Chen goto disable_reg; 83eb70e5abSAlexander Shishkin else 84eb70e5abSAlexander Shishkin ci->hcd = hcd; 85eb70e5abSAlexander Shishkin 868e22978cSAlexander Shishkin if (ci->platdata->flags & CI_HDRC_DISABLE_STREAMING) 87929473eaSFabio Estevam hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS); 88929473eaSFabio Estevam 89eb70e5abSAlexander Shishkin return ret; 9040ed51a4SPeter Chen 9140ed51a4SPeter Chen disable_reg: 9246adcf3dSFabio Estevam if (ci->platdata->reg_vbus) 9340ed51a4SPeter Chen regulator_disable(ci->platdata->reg_vbus); 9440ed51a4SPeter Chen 9540ed51a4SPeter Chen put_hcd: 9640ed51a4SPeter Chen usb_put_hcd(hcd); 9740ed51a4SPeter Chen 9840ed51a4SPeter Chen return ret; 99eb70e5abSAlexander Shishkin } 100eb70e5abSAlexander Shishkin 1018e22978cSAlexander Shishkin static void host_stop(struct ci_hdrc *ci) 102eb70e5abSAlexander Shishkin { 103eb70e5abSAlexander Shishkin struct usb_hcd *hcd = ci->hcd; 104eb70e5abSAlexander Shishkin 10541314feaSRussell King - ARM Linux if (hcd) { 106eb70e5abSAlexander Shishkin usb_remove_hcd(hcd); 107eb70e5abSAlexander Shishkin usb_put_hcd(hcd); 10840ed51a4SPeter Chen if (ci->platdata->reg_vbus) 10940ed51a4SPeter Chen regulator_disable(ci->platdata->reg_vbus); 110eb70e5abSAlexander Shishkin } 111df101c53SPeter Chen } 112eb70e5abSAlexander Shishkin 1133f124d23SPeter Chen 1143f124d23SPeter Chen void ci_hdrc_host_destroy(struct ci_hdrc *ci) 1153f124d23SPeter Chen { 116df101c53SPeter Chen if (ci->role == CI_ROLE_HOST && ci->hcd) 1173f124d23SPeter Chen host_stop(ci); 1183f124d23SPeter Chen } 1193f124d23SPeter Chen 1208e22978cSAlexander Shishkin int ci_hdrc_host_init(struct ci_hdrc *ci) 121eb70e5abSAlexander Shishkin { 122eb70e5abSAlexander Shishkin struct ci_role_driver *rdrv; 123eb70e5abSAlexander Shishkin 124eb70e5abSAlexander Shishkin if (!hw_read(ci, CAP_DCCPARAMS, DCCPARAMS_HC)) 125eb70e5abSAlexander Shishkin return -ENXIO; 126eb70e5abSAlexander Shishkin 127eb70e5abSAlexander Shishkin rdrv = devm_kzalloc(ci->dev, sizeof(struct ci_role_driver), GFP_KERNEL); 128eb70e5abSAlexander Shishkin if (!rdrv) 129eb70e5abSAlexander Shishkin return -ENOMEM; 130eb70e5abSAlexander Shishkin 131eb70e5abSAlexander Shishkin rdrv->start = host_start; 132eb70e5abSAlexander Shishkin rdrv->stop = host_stop; 133eb70e5abSAlexander Shishkin rdrv->irq = host_irq; 134eb70e5abSAlexander Shishkin rdrv->name = "host"; 135eb70e5abSAlexander Shishkin ci->roles[CI_ROLE_HOST] = rdrv; 136eb70e5abSAlexander Shishkin 1371b36810eSAlan Stern ehci_init_driver(&ci_ehci_hc_driver, NULL); 13809f6ffdeSAlan Stern 139eb70e5abSAlexander Shishkin return 0; 140eb70e5abSAlexander Shishkin } 141