/* * Copyright (C) ST-Ericsson AP Pte Ltd 2010 * * ISP1763 Linux HCD Controller driver : hal * * This program is free software; you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation; version * 2 of the License. * * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * This is the main hardware abstraction layer file. Hardware initialization, interupt * processing and read/write routines are handled here. * * Author : wired support * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /*--------------------------------------------------------------* * linux system include files *--------------------------------------------------------------*/ #include "hal_msm.h" #include "../hal/hal_intf.h" #include "../hal/isp1763.h" /*--------------------------------------------------------------* * Local variable Definitions *--------------------------------------------------------------*/ struct isp1763_dev isp1763_loc_dev[ISP1763_LAST_DEV]; /*--------------------------------------------------------------* * Local # Definitions *--------------------------------------------------------------*/ #define PCI_ACCESS_RETRY_COUNT 20 #define ISP1763_DRIVER_NAME "isp1763_usb" /*--------------------------------------------------------------* * Local Function *--------------------------------------------------------------*/ static int __devexit isp1763_remove(struct platform_device *pdev); static int __devinit isp1763_probe(struct platform_device *pdev); /*--------------------------------------------------------------* * Platform Driver Interface Functions *--------------------------------------------------------------*/ static struct platform_driver isp1763_usb_driver = { .remove = __exit_p(isp1763_remove), .driver = { .name = ISP1763_DRIVER_NAME, .owner = THIS_MODULE, }, }; /*--------------------------------------------------------------* * ISP1763 Read write routine *--------------------------------------------------------------*/ /* * EBI2 on 8660 ignores the first bit and shifts the address by * one bit to the right. * Hence, shift left all the register addresses before accessing * them over EBI2. * This logic applies only for the register read/writes, for * read/write from ISP memory this conversion is not needed * as the ISP obtains the memory address from 'memory' register */ /* Write a 32 bit Register of isp1763 */ void isp1763_reg_write32(struct isp1763_dev *dev, u16 reg, u32 data) { /* Write the 32bit to the register address given to us */ reg <<= 1; #ifdef DATABUS_WIDTH_16 writew((u16) data, dev->baseaddress + ((reg))); writew((u16) (data >> 16), dev->baseaddress + (((reg + 4)))); #else writeb((u8) data, dev->baseaddress + (reg)); writeb((u8) (data >> 8), dev->baseaddress + ((reg + 1))); writeb((u8) (data >> 16), dev->baseaddress + ((reg + 2))); writeb((u8) (data >> 24), dev->baseaddress + ((reg + 3))); #endif } EXPORT_SYMBOL(isp1763_reg_write32); /* Read a 32 bit Register of isp1763 */ u32 isp1763_reg_read32(struct isp1763_dev *dev, u16 reg, u32 data) { #ifdef DATABUS_WIDTH_16 u16 wvalue1, wvalue2; #else u8 bval1, bval2, bval3, bval4; #endif data = 0; reg <<= 1; #ifdef DATABUS_WIDTH_16 wvalue1 = readw(dev->baseaddress + ((reg))); wvalue2 = readw(dev->baseaddress + (((reg + 4)))); data |= wvalue2; data <<= 16; data |= wvalue1; #else bval1 = readb(dev->baseaddress + (reg)); bval2 = readb(dev->baseaddress + (reg + 1)); bval3 = readb(dev->baseaddress + (reg + 2)); bval4 = readb(dev->baseaddress + (reg + 3)); data = 0; data |= bval4; data <<= 8; data |= bval3; data <<= 8; data |= bval2; data <<= 8; data |= bval1; #endif return data; } EXPORT_SYMBOL(isp1763_reg_read32); /* Read a 16 bit Register of isp1763 */ u16 isp1763_reg_read16(struct isp1763_dev * dev, u16 reg, u16 data) { reg <<= 1; #ifdef DATABUS_WIDTH_16 data = readw(dev->baseaddress + ((reg))); #else u8 bval1, bval2; bval1 = readb(dev->baseaddress + (reg)); if (reg == HC_DATA_REG){ bval2 = readb(dev->baseaddress + (reg)); } else { bval2 = readb(dev->baseaddress + ((reg + 1))); } data = 0; data |= bval2; data <<= 8; data |= bval1; #endif return data; } EXPORT_SYMBOL(isp1763_reg_read16); /* Write a 16 bit Register of isp1763 */ void isp1763_reg_write16(struct isp1763_dev *dev, u16 reg, u16 data) { reg <<= 1; #ifdef DATABUS_WIDTH_16 writew(data, dev->baseaddress + ((reg))); #else writeb((u8) data, dev->baseaddress + (reg)); if (reg == HC_DATA_REG){ writeb((u8) (data >> 8), dev->baseaddress + (reg)); }else{ writeb((u8) (data >> 8), dev->baseaddress + ((reg + 1))); } #endif } EXPORT_SYMBOL(isp1763_reg_write16); /* Read a 8 bit Register of isp1763 */ u8 isp1763_reg_read8(struct isp1763_dev *dev, u16 reg, u8 data) { reg <<= 1; data = readb((dev->baseaddress + (reg))); return data; } EXPORT_SYMBOL(isp1763_reg_read8); /* Write a 8 bit Register of isp1763 */ void isp1763_reg_write8(struct isp1763_dev *dev, u16 reg, u8 data) { reg <<= 1; writeb(data, (dev->baseaddress + (reg))); } EXPORT_SYMBOL(isp1763_reg_write8); /*--------------------------------------------------------------* * * Module dtatils: isp1763_mem_read * * Memory read using PIO method. * * Input: struct isp1763_driver *drv --> Driver structure. * u32 start_add --> Starting address of memory * u32 end_add ---> End address * * u32 * buffer --> Buffer pointer. * u32 length ---> Length * u16 dir ---> Direction ( Inc or Dec) * * Output int Length ----> Number of bytes read * * Called by: system function * * *--------------------------------------------------------------*/ /* Memory read function PIO */ int isp1763_mem_read(struct isp1763_dev *dev, u32 start_add, u32 end_add, u32 * buffer, u32 length, u16 dir) { u8 *one = (u8 *) buffer; u16 *two = (u16 *) buffer; u32 a = (u32) length; u32 w; u32 w2; if (buffer == 0) { printk("Buffer address zero\n"); return 0; } isp1763_reg_write16(dev, HC_MEM_READ_REG, start_add); /* This delay requirement comes from the ISP1763A programming guide */ ndelay(100); last: w = isp1763_reg_read16(dev, HC_DATA_REG, w); w2 = isp1763_reg_read16(dev, HC_DATA_REG, w); w2 <<= 16; w = w | w2; if (a == 1) { *one = (u8) w; return 0; } if (a == 2) { *two = (u16) w; return 0; } if (a == 3) { *two = (u16) w; two += 1; w >>= 16; *two = (u8) (w); return 0; } while (a > 0) { *buffer = w; a -= 4; if (a <= 0) { break; } if (a < 4) { buffer += 1; one = (u8 *) buffer; two = (u16 *) buffer; goto last; } buffer += 1; w = isp1763_reg_read16(dev, HC_DATA_REG, w); w2 = isp1763_reg_read16(dev, HC_DATA_REG, w); w2 <<= 16; w = w | w2; } return ((a < 0) || (a == 0)) ? 0 : (-1); } EXPORT_SYMBOL(isp1763_mem_read); /*--------------------------------------------------------------* * * Module dtatils: isp1763_mem_write * * Memory write using PIO method. * * Input: struct isp1763_driver *drv --> Driver structure. * u32 start_add --> Starting address of memory * u32 end_add ---> End address * * u32 * buffer --> Buffer pointer. * u32 length ---> Length * u16 dir ---> Direction ( Inc or Dec) * * Output int Length ----> Number of bytes read * * Called by: system function * * *--------------------------------------------------------------*/ /* Memory read function IO */ int isp1763_mem_write(struct isp1763_dev *dev, u32 start_add, u32 end_add, u32 * buffer, u32 length, u16 dir) { int a = length; u8 one = (u8) (*buffer); u16 two = (u16) (*buffer); isp1763_reg_write16(dev, HC_MEM_READ_REG, start_add); /* This delay requirement comes from the ISP1763A programming guide */ ndelay(100); if (a == 1) { isp1763_reg_write16(dev, HC_DATA_REG, one); return 0; } if (a == 2) { isp1763_reg_write16(dev, HC_DATA_REG, two); return 0; } while (a > 0) { isp1763_reg_write16(dev, HC_DATA_REG, (u16) (*buffer)); if (a >= 3) isp1763_reg_write16(dev, HC_DATA_REG, (u16) ((*buffer) >> 16)); start_add += 4; a -= 4; if (a <= 0) break; buffer += 1; } return ((a < 0) || (a == 0)) ? 0 : (-1); } EXPORT_SYMBOL(isp1763_mem_write); /*--------------------------------------------------------------* * * Module dtatils: isp1763_register_driver * * This function is used by top driver (OTG, HCD, DCD) to register * their communication functions (probe, remove, suspend, resume) using * the drv data structure. * This function will call the probe function of the driver if the ISP1763 * corresponding to the driver is enabled * * Input: struct isp1763_driver *drv --> Driver structure. * Output result * 0= complete * 1= error. * * Called by: system function module_init * * *--------------------------------------------------------------*/ int isp1763_register_driver(struct isp1763_driver *drv) { struct isp1763_dev *dev; int result = -EINVAL; hal_entry("%s: Entered\n", __FUNCTION__); info("isp1763_register_driver(drv=%p)\n", drv); if (!drv) { return -EINVAL; } dev = &isp1763_loc_dev[drv->index]; if (!dev->baseaddress) return -EINVAL; dev->active = 1; /* set the driver as active*/ if (drv->probe) { result = drv->probe(dev, drv->id); } else { printk("%s no probe function for indes %d \n", __FUNCTION__, (int)drv->index); } if (result >= 0) { pr_debug(KERN_INFO __FILE__ ": Registered Driver %s\n", drv->name); dev->driver = drv; } hal_entry("%s: Exit\n", __FUNCTION__); return result; } /* End of isp1763_register_driver */ EXPORT_SYMBOL(isp1763_register_driver); /*--------------------------------------------------------------* * * Module dtatils: isp1763_unregister_driver * * This function is used by top driver (OTG, HCD, DCD) to de-register * their communication functions (probe, remove, suspend, resume) using * the drv data structure. * This function will check whether the driver is registered or not and * call the remove function of the driver if registered * * Input: struct isp1763_driver *drv --> Driver structure. * Output result * 0= complete * 1= error. * * Called by: system function module_init * * *--------------------------------------------------------------*/ void isp1763_unregister_driver(struct isp1763_driver *drv) { struct isp1763_dev *dev; hal_entry("%s: Entered\n", __FUNCTION__); info("isp1763_unregister_driver(drv=%p)\n", drv); dev = &isp1763_loc_dev[drv->index]; if (dev->driver == drv) { /* driver registered is same as the requestig driver */ drv->remove(dev); dev->driver = NULL; info(": De-registered Driver %s\n", drv->name); return; } hal_entry("%s: Exit\n", __FUNCTION__); } /* End of isp1763_unregister_driver */ EXPORT_SYMBOL(isp1763_unregister_driver); /*--------------------------------------------------------------* * ISP1763 Platform driver interface routine. *--------------------------------------------------------------*/ /*--------------------------------------------------------------* * * Module dtatils: isp1763_module_init * * This is the module initialization function. It registers to * driver for a isp1763 platform device. And also resets the * internal data structures. * * Input: void * Output result * 0= complete * 1= error. * * Called by: system function module_init * * * -------------------------------------------------------------------*/ static int __init isp1763_module_init(void) { int result = 0; hal_entry("%s: Entered\n", __FUNCTION__); pr_debug(KERN_NOTICE "+isp1763_module_init\n"); memset(isp1763_loc_dev, 0, sizeof(isp1763_loc_dev)); result = platform_driver_probe(&isp1763_usb_driver, isp1763_probe); pr_debug(KERN_NOTICE "-isp1763_module_init\n"); hal_entry("%s: Exit\n", __FUNCTION__); return result; } /*--------------------------------------------------------------* * * Module dtatils: isp1763_module_cleanup * * This is the module cleanup function. It de-registers the * Platform driver and resets the internal data structures. * * Input: void * Output void * * Called by: system function module_cleanup * * * --------------------------------------------------------------*/ static void __exit isp1763_module_cleanup(void) { pr_debug("Hal Module Cleanup\n"); platform_driver_unregister(&isp1763_usb_driver); memset(isp1763_loc_dev, 0, sizeof(isp1763_loc_dev)); } void dummy_mem_read(struct isp1763_dev *dev) { u32 w = 0; isp1763_reg_write16(dev, HC_MEM_READ_REG, 0x0400); w = isp1763_reg_read16(dev, HC_DATA_REG, w); pr_debug("dummy_read DONE: %x\n", w); msleep(10); } /*--------------------------------------------------------------* * * Module dtatils: isp1763_probe * * probe function of ISP1763 * This function is called from module_init if the corresponding platform * device is present. This function initializes the information * for the Host Controller with the assigned resources and tests the register * access to the controller and do a software reset and makes it ready * for the driver to play with. It also calls setup_gpio passed from pdata * to setup GPIOs (e.g. used for IRQ and RST lines). * * Input: * struct platform_device *dev ----> Platform Device structure * Output void * * Called by: system function module_cleanup * * * --------------------------------------------------------------**/ static int __devinit isp1763_probe(struct platform_device *pdev) { u32 reg_data = 0; struct isp1763_dev *loc_dev; int status = 1; u32 hwmodectrl = 0; u16 us_reset_hc = 0; u32 chipid = 0; struct isp1763_platform_data *pdata = pdev->dev.platform_data; hal_entry("%s: Entered\n", __FUNCTION__); hal_init(("isp1763_probe(dev=%p)\n", dev)); loc_dev = &(isp1763_loc_dev[ISP1763_HC]); loc_dev->dev = pdev; /* Get the Host Controller IO and INT resources */ loc_dev->mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!loc_dev->mem_res) { pr_err("%s: failed to get platform resource mem\n", __func__); return -ENODEV; } loc_dev->baseaddress = ioremap_nocache(loc_dev->mem_res->start, resource_size(loc_dev->mem_res)); if (!loc_dev->baseaddress) { pr_err("%s: ioremap failed\n", __func__); status = -ENOMEM; goto put_mem_res; } pr_info("%s: ioremap done at: %x\n", __func__, (int)loc_dev->baseaddress); loc_dev->irq = platform_get_irq(pdev, 0); if (!loc_dev->irq) { pr_err("%s: platform_get_irq failed\n", __func__); status = -ENODEV; goto free_regs; } loc_dev->index = ISP1763_HC; /*zero */ loc_dev->length = resource_size(loc_dev->mem_res); hal_init(("isp1763 HC MEM Base= %p irq = %d\n", loc_dev->baseaddress, loc_dev->irq)); /* Setup GPIOs and isssue RESET_N to Controller */ if (pdata->setup_gpio) if (pdata->setup_gpio(1)) pr_err("%s: Failed to setup GPIOs for isp1763\n", __func__); if (pdata->reset_gpio) { gpio_set_value(pdata->reset_gpio, 0); msleep(10); gpio_set_value(pdata->reset_gpio, 1); } else { pr_err("%s: Failed to issue RESET_N to isp1763\n", __func__); } dummy_mem_read(loc_dev); chipid = isp1763_reg_read32(loc_dev, DC_CHIPID, chipid); pr_info("START: chip id:%x\n", chipid); /*reset the host controller */ pr_debug("RESETTING\n"); us_reset_hc |= 0x1; isp1763_reg_write16(loc_dev, 0xB8, us_reset_hc); msleep(20); us_reset_hc = 0; us_reset_hc |= 0x2; isp1763_reg_write16(loc_dev, 0xB8, us_reset_hc); chipid = isp1763_reg_read32(loc_dev, DC_CHIPID, chipid); pr_info("after HC reset, chipid:%x\n", chipid); msleep(20); hwmodectrl = isp1763_reg_read16(loc_dev, HC_HWMODECTRL_REG, hwmodectrl); pr_debug("Mode Ctrl Value b4 setting buswidth: %x\n", hwmodectrl); #ifdef DATABUS_WIDTH_16 hwmodectrl &= 0xFFEF; /*enable the 16 bit bus */ #else pr_debug("Setting 8-BIT mode\n"); hwmodectrl |= 0x0010; /*enable the 8 bit bus */ #endif isp1763_reg_write16(loc_dev, HC_HWMODECTRL_REG, hwmodectrl); pr_debug("writing 0x%x to hw mode reg\n", hwmodectrl); hwmodectrl = isp1763_reg_read16(loc_dev, HC_HWMODECTRL_REG, hwmodectrl); msleep(100); pr_debug("Mode Ctrl Value after setting buswidth: %x\n", hwmodectrl); chipid = isp1763_reg_read32(loc_dev, DC_CHIPID, chipid); pr_debug("after setting HW MODE to 8bit, chipid:%x\n", chipid); hal_init(("isp1763 DC MEM Base= %lx irq = %d\n", loc_dev->io_base, loc_dev->irq)); reg_data = isp1763_reg_read16(loc_dev, HC_SCRATCH_REG, reg_data); pr_debug("Scratch register is 0x%x\n", reg_data); reg_data = 0xABCD; isp1763_reg_write16(loc_dev, HC_SCRATCH_REG, reg_data); reg_data = isp1763_reg_read16(loc_dev, HC_SCRATCH_REG, reg_data); pr_debug("After write, Scratch register is 0x%x\n", reg_data); if (reg_data != 0xABCD) { pr_err("%s: Scratch register write mismatch!!\n", __func__); status = -ENODEV; goto free_gpios; } memcpy(loc_dev->name, ISP1763_DRIVER_NAME, sizeof(ISP1763_DRIVER_NAME)); loc_dev->name[sizeof(ISP1763_DRIVER_NAME)] = 0; pr_debug(KERN_NOTICE "-isp1763_pci_probe\n"); hal_entry("%s: Exit\n", __FUNCTION__); return 0; free_gpios: if (pdata->setup_gpio) pdata->setup_gpio(0); free_regs: iounmap(loc_dev->baseaddress); put_mem_res: loc_dev->baseaddress = NULL; hal_entry("%s: Exit\n", __FUNCTION__); return status; } /* End of isp1763_probe */ /*--------------------------------------------------------------* * * Module details: isp1763_remove * * cleanup function of ISP1763 * This functions de-initializes the local variables, frees GPIOs * and releases memory resource. * * Input: * struct platform_device *dev ----> Platform Device structure * * Output void * * Called by: system function module_cleanup * * * --------------------------------------------------------------*/ static int __devexit isp1763_remove(struct platform_device *pdev) { struct isp1763_dev *loc_dev; struct isp1763_platform_data *pdata = pdev->dev.platform_data; hal_init(("isp1763_pci_remove(dev=%p)\n", dev)); loc_dev = &isp1763_loc_dev[ISP1763_HC]; iounmap(loc_dev->baseaddress); loc_dev->baseaddress = NULL; if (pdata->setup_gpio) return pdata->setup_gpio(0); return 0; } /* End of isp1763_remove */ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); module_init(isp1763_module_init); module_exit(isp1763_module_cleanup);