18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/arch/arm/mach-omap2/usb-tusb6010.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2006 Nokia Corporation 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/err.h> 98c2ecf20Sopenharmony_ci#include <linux/string.h> 108c2ecf20Sopenharmony_ci#include <linux/types.h> 118c2ecf20Sopenharmony_ci#include <linux/errno.h> 128c2ecf20Sopenharmony_ci#include <linux/delay.h> 138c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 148c2ecf20Sopenharmony_ci#include <linux/gpio.h> 158c2ecf20Sopenharmony_ci#include <linux/export.h> 168c2ecf20Sopenharmony_ci#include <linux/platform_data/usb-omap.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <linux/usb/musb.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include "gpmc.h" 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistatic u8 async_cs, sync_cs; 238c2ecf20Sopenharmony_cistatic unsigned refclk_psec; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic struct gpmc_settings tusb_async = { 268c2ecf20Sopenharmony_ci .wait_on_read = true, 278c2ecf20Sopenharmony_ci .wait_on_write = true, 288c2ecf20Sopenharmony_ci .device_width = GPMC_DEVWIDTH_16BIT, 298c2ecf20Sopenharmony_ci .mux_add_data = GPMC_MUX_AD, 308c2ecf20Sopenharmony_ci}; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic struct gpmc_settings tusb_sync = { 338c2ecf20Sopenharmony_ci .burst_read = true, 348c2ecf20Sopenharmony_ci .burst_write = true, 358c2ecf20Sopenharmony_ci .sync_read = true, 368c2ecf20Sopenharmony_ci .sync_write = true, 378c2ecf20Sopenharmony_ci .wait_on_read = true, 388c2ecf20Sopenharmony_ci .wait_on_write = true, 398c2ecf20Sopenharmony_ci .burst_len = GPMC_BURST_16, 408c2ecf20Sopenharmony_ci .device_width = GPMC_DEVWIDTH_16BIT, 418c2ecf20Sopenharmony_ci .mux_add_data = GPMC_MUX_AD, 428c2ecf20Sopenharmony_ci}; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci/* NOTE: timings are from tusb 6010 datasheet Rev 1.8, 12-Sept 2006 */ 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic int tusb_set_async_mode(unsigned sysclk_ps) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci struct gpmc_device_timings dev_t; 498c2ecf20Sopenharmony_ci struct gpmc_timings t; 508c2ecf20Sopenharmony_ci unsigned t_acsnh_advnh = sysclk_ps + 3000; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci memset(&dev_t, 0, sizeof(dev_t)); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci dev_t.t_ceasu = 8 * 1000; 558c2ecf20Sopenharmony_ci dev_t.t_avdasu = t_acsnh_advnh - 7000; 568c2ecf20Sopenharmony_ci dev_t.t_ce_avd = 1000; 578c2ecf20Sopenharmony_ci dev_t.t_avdp_r = t_acsnh_advnh; 588c2ecf20Sopenharmony_ci dev_t.t_oeasu = t_acsnh_advnh + 1000; 598c2ecf20Sopenharmony_ci dev_t.t_oe = 300; 608c2ecf20Sopenharmony_ci dev_t.t_cez_r = 7000; 618c2ecf20Sopenharmony_ci dev_t.t_cez_w = dev_t.t_cez_r; 628c2ecf20Sopenharmony_ci dev_t.t_avdp_w = t_acsnh_advnh; 638c2ecf20Sopenharmony_ci dev_t.t_weasu = t_acsnh_advnh + 1000; 648c2ecf20Sopenharmony_ci dev_t.t_wpl = 300; 658c2ecf20Sopenharmony_ci dev_t.cyc_aavdh_we = 1; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci gpmc_calc_timings(&t, &tusb_async, &dev_t); 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci return gpmc_cs_set_timings(async_cs, &t, &tusb_async); 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic int tusb_set_sync_mode(unsigned sysclk_ps) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci struct gpmc_device_timings dev_t; 758c2ecf20Sopenharmony_ci struct gpmc_timings t; 768c2ecf20Sopenharmony_ci unsigned t_scsnh_advnh = sysclk_ps + 3000; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci memset(&dev_t, 0, sizeof(dev_t)); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci dev_t.clk = 11100; 818c2ecf20Sopenharmony_ci dev_t.t_bacc = 1000; 828c2ecf20Sopenharmony_ci dev_t.t_ces = 1000; 838c2ecf20Sopenharmony_ci dev_t.t_ceasu = 8 * 1000; 848c2ecf20Sopenharmony_ci dev_t.t_avdasu = t_scsnh_advnh - 7000; 858c2ecf20Sopenharmony_ci dev_t.t_ce_avd = 1000; 868c2ecf20Sopenharmony_ci dev_t.t_avdp_r = t_scsnh_advnh; 878c2ecf20Sopenharmony_ci dev_t.cyc_aavdh_oe = 3; 888c2ecf20Sopenharmony_ci dev_t.cyc_oe = 5; 898c2ecf20Sopenharmony_ci dev_t.t_ce_rdyz = 7000; 908c2ecf20Sopenharmony_ci dev_t.t_avdp_w = t_scsnh_advnh; 918c2ecf20Sopenharmony_ci dev_t.cyc_aavdh_we = 3; 928c2ecf20Sopenharmony_ci dev_t.cyc_wpl = 6; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci gpmc_calc_timings(&t, &tusb_sync, &dev_t); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci return gpmc_cs_set_timings(sync_cs, &t, &tusb_sync); 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci/* tusb driver calls this when it changes the chip's clocking */ 1008c2ecf20Sopenharmony_ciint tusb6010_platform_retime(unsigned is_refclk) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci static const char error[] = 1038c2ecf20Sopenharmony_ci KERN_ERR "tusb6010 %s retime error %d\n"; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci unsigned sysclk_ps; 1068c2ecf20Sopenharmony_ci int status; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci if (!refclk_psec) 1098c2ecf20Sopenharmony_ci return -ENODEV; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci sysclk_ps = is_refclk ? refclk_psec : TUSB6010_OSCCLK_60; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci status = tusb_set_async_mode(sysclk_ps); 1148c2ecf20Sopenharmony_ci if (status < 0) { 1158c2ecf20Sopenharmony_ci printk(error, "async", status); 1168c2ecf20Sopenharmony_ci goto done; 1178c2ecf20Sopenharmony_ci } 1188c2ecf20Sopenharmony_ci status = tusb_set_sync_mode(sysclk_ps); 1198c2ecf20Sopenharmony_ci if (status < 0) 1208c2ecf20Sopenharmony_ci printk(error, "sync", status); 1218c2ecf20Sopenharmony_cidone: 1228c2ecf20Sopenharmony_ci return status; 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(tusb6010_platform_retime); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic struct resource tusb_resources[] = { 1278c2ecf20Sopenharmony_ci /* Order is significant! The start/end fields 1288c2ecf20Sopenharmony_ci * are updated during setup.. 1298c2ecf20Sopenharmony_ci */ 1308c2ecf20Sopenharmony_ci { /* Asynchronous access */ 1318c2ecf20Sopenharmony_ci .flags = IORESOURCE_MEM, 1328c2ecf20Sopenharmony_ci }, 1338c2ecf20Sopenharmony_ci { /* Synchronous access */ 1348c2ecf20Sopenharmony_ci .flags = IORESOURCE_MEM, 1358c2ecf20Sopenharmony_ci }, 1368c2ecf20Sopenharmony_ci { /* IRQ */ 1378c2ecf20Sopenharmony_ci .name = "mc", 1388c2ecf20Sopenharmony_ci .flags = IORESOURCE_IRQ, 1398c2ecf20Sopenharmony_ci }, 1408c2ecf20Sopenharmony_ci}; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic u64 tusb_dmamask = ~(u32)0; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cistatic struct platform_device tusb_device = { 1458c2ecf20Sopenharmony_ci .name = "musb-tusb", 1468c2ecf20Sopenharmony_ci .id = -1, 1478c2ecf20Sopenharmony_ci .dev = { 1488c2ecf20Sopenharmony_ci .dma_mask = &tusb_dmamask, 1498c2ecf20Sopenharmony_ci .coherent_dma_mask = 0xffffffff, 1508c2ecf20Sopenharmony_ci }, 1518c2ecf20Sopenharmony_ci .num_resources = ARRAY_SIZE(tusb_resources), 1528c2ecf20Sopenharmony_ci .resource = tusb_resources, 1538c2ecf20Sopenharmony_ci}; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci/* this may be called only from board-*.c setup code */ 1578c2ecf20Sopenharmony_ciint __init 1588c2ecf20Sopenharmony_citusb6010_setup_interface(struct musb_hdrc_platform_data *data, 1598c2ecf20Sopenharmony_ci unsigned ps_refclk, unsigned waitpin, 1608c2ecf20Sopenharmony_ci unsigned async, unsigned sync, 1618c2ecf20Sopenharmony_ci unsigned irq, unsigned dmachan) 1628c2ecf20Sopenharmony_ci{ 1638c2ecf20Sopenharmony_ci int status; 1648c2ecf20Sopenharmony_ci static char error[] __initdata = 1658c2ecf20Sopenharmony_ci KERN_ERR "tusb6010 init error %d, %d\n"; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci /* ASYNC region, primarily for PIO */ 1688c2ecf20Sopenharmony_ci status = gpmc_cs_request(async, SZ_16M, (unsigned long *) 1698c2ecf20Sopenharmony_ci &tusb_resources[0].start); 1708c2ecf20Sopenharmony_ci if (status < 0) { 1718c2ecf20Sopenharmony_ci printk(error, 1, status); 1728c2ecf20Sopenharmony_ci return status; 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci tusb_resources[0].end = tusb_resources[0].start + 0x9ff; 1758c2ecf20Sopenharmony_ci tusb_async.wait_pin = waitpin; 1768c2ecf20Sopenharmony_ci async_cs = async; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci status = gpmc_cs_program_settings(async_cs, &tusb_async); 1798c2ecf20Sopenharmony_ci if (status < 0) 1808c2ecf20Sopenharmony_ci return status; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci /* SYNC region, primarily for DMA */ 1838c2ecf20Sopenharmony_ci status = gpmc_cs_request(sync, SZ_16M, (unsigned long *) 1848c2ecf20Sopenharmony_ci &tusb_resources[1].start); 1858c2ecf20Sopenharmony_ci if (status < 0) { 1868c2ecf20Sopenharmony_ci printk(error, 2, status); 1878c2ecf20Sopenharmony_ci return status; 1888c2ecf20Sopenharmony_ci } 1898c2ecf20Sopenharmony_ci tusb_resources[1].end = tusb_resources[1].start + 0x9ff; 1908c2ecf20Sopenharmony_ci tusb_sync.wait_pin = waitpin; 1918c2ecf20Sopenharmony_ci sync_cs = sync; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci status = gpmc_cs_program_settings(sync_cs, &tusb_sync); 1948c2ecf20Sopenharmony_ci if (status < 0) 1958c2ecf20Sopenharmony_ci return status; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci /* IRQ */ 1988c2ecf20Sopenharmony_ci status = gpio_request_one(irq, GPIOF_IN, "TUSB6010 irq"); 1998c2ecf20Sopenharmony_ci if (status < 0) { 2008c2ecf20Sopenharmony_ci printk(error, 3, status); 2018c2ecf20Sopenharmony_ci return status; 2028c2ecf20Sopenharmony_ci } 2038c2ecf20Sopenharmony_ci tusb_resources[2].start = gpio_to_irq(irq); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci /* set up memory timings ... can speed them up later */ 2068c2ecf20Sopenharmony_ci if (!ps_refclk) { 2078c2ecf20Sopenharmony_ci printk(error, 4, status); 2088c2ecf20Sopenharmony_ci return -ENODEV; 2098c2ecf20Sopenharmony_ci } 2108c2ecf20Sopenharmony_ci refclk_psec = ps_refclk; 2118c2ecf20Sopenharmony_ci status = tusb6010_platform_retime(1); 2128c2ecf20Sopenharmony_ci if (status < 0) { 2138c2ecf20Sopenharmony_ci printk(error, 5, status); 2148c2ecf20Sopenharmony_ci return status; 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci /* finish device setup ... */ 2188c2ecf20Sopenharmony_ci if (!data) { 2198c2ecf20Sopenharmony_ci printk(error, 6, status); 2208c2ecf20Sopenharmony_ci return -ENODEV; 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci tusb_device.dev.platform_data = data; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci /* so far so good ... register the device */ 2258c2ecf20Sopenharmony_ci status = platform_device_register(&tusb_device); 2268c2ecf20Sopenharmony_ci if (status < 0) { 2278c2ecf20Sopenharmony_ci printk(error, 7, status); 2288c2ecf20Sopenharmony_ci return status; 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci return 0; 2318c2ecf20Sopenharmony_ci} 232