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