162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * linux/arch/arm/mach-omap2/usb-tusb6010.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2006 Nokia Corporation
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/err.h>
962306a36Sopenharmony_ci#include <linux/string.h>
1062306a36Sopenharmony_ci#include <linux/types.h>
1162306a36Sopenharmony_ci#include <linux/errno.h>
1262306a36Sopenharmony_ci#include <linux/delay.h>
1362306a36Sopenharmony_ci#include <linux/platform_device.h>
1462306a36Sopenharmony_ci#include <linux/export.h>
1562306a36Sopenharmony_ci#include <linux/platform_data/usb-omap.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include <linux/usb/musb.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include "usb-tusb6010.h"
2062306a36Sopenharmony_ci#include "gpmc.h"
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_cistatic u8		async_cs, sync_cs;
2362306a36Sopenharmony_cistatic unsigned		refclk_psec;
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_cistatic struct gpmc_settings tusb_async = {
2662306a36Sopenharmony_ci	.wait_on_read	= true,
2762306a36Sopenharmony_ci	.wait_on_write	= true,
2862306a36Sopenharmony_ci	.device_width	= GPMC_DEVWIDTH_16BIT,
2962306a36Sopenharmony_ci	.mux_add_data	= GPMC_MUX_AD,
3062306a36Sopenharmony_ci};
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cistatic struct gpmc_settings tusb_sync = {
3362306a36Sopenharmony_ci	.burst_read	= true,
3462306a36Sopenharmony_ci	.burst_write	= true,
3562306a36Sopenharmony_ci	.sync_read	= true,
3662306a36Sopenharmony_ci	.sync_write	= true,
3762306a36Sopenharmony_ci	.wait_on_read	= true,
3862306a36Sopenharmony_ci	.wait_on_write	= true,
3962306a36Sopenharmony_ci	.burst_len	= GPMC_BURST_16,
4062306a36Sopenharmony_ci	.device_width	= GPMC_DEVWIDTH_16BIT,
4162306a36Sopenharmony_ci	.mux_add_data	= GPMC_MUX_AD,
4262306a36Sopenharmony_ci};
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci/* NOTE:  timings are from tusb 6010 datasheet Rev 1.8, 12-Sept 2006 */
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_cistatic int tusb_set_async_mode(unsigned sysclk_ps)
4762306a36Sopenharmony_ci{
4862306a36Sopenharmony_ci	struct gpmc_device_timings dev_t;
4962306a36Sopenharmony_ci	struct gpmc_timings	t;
5062306a36Sopenharmony_ci	unsigned		t_acsnh_advnh = sysclk_ps + 3000;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	memset(&dev_t, 0, sizeof(dev_t));
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	dev_t.t_ceasu = 8 * 1000;
5562306a36Sopenharmony_ci	dev_t.t_avdasu = t_acsnh_advnh - 7000;
5662306a36Sopenharmony_ci	dev_t.t_ce_avd = 1000;
5762306a36Sopenharmony_ci	dev_t.t_avdp_r = t_acsnh_advnh;
5862306a36Sopenharmony_ci	dev_t.t_oeasu = t_acsnh_advnh + 1000;
5962306a36Sopenharmony_ci	dev_t.t_oe = 300;
6062306a36Sopenharmony_ci	dev_t.t_cez_r = 7000;
6162306a36Sopenharmony_ci	dev_t.t_cez_w = dev_t.t_cez_r;
6262306a36Sopenharmony_ci	dev_t.t_avdp_w = t_acsnh_advnh;
6362306a36Sopenharmony_ci	dev_t.t_weasu = t_acsnh_advnh + 1000;
6462306a36Sopenharmony_ci	dev_t.t_wpl = 300;
6562306a36Sopenharmony_ci	dev_t.cyc_aavdh_we = 1;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	gpmc_calc_timings(&t, &tusb_async, &dev_t);
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	return gpmc_cs_set_timings(async_cs, &t, &tusb_async);
7062306a36Sopenharmony_ci}
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_cistatic int tusb_set_sync_mode(unsigned sysclk_ps)
7362306a36Sopenharmony_ci{
7462306a36Sopenharmony_ci	struct gpmc_device_timings dev_t;
7562306a36Sopenharmony_ci	struct gpmc_timings	t;
7662306a36Sopenharmony_ci	unsigned		t_scsnh_advnh = sysclk_ps + 3000;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	memset(&dev_t, 0, sizeof(dev_t));
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	dev_t.clk = 11100;
8162306a36Sopenharmony_ci	dev_t.t_bacc = 1000;
8262306a36Sopenharmony_ci	dev_t.t_ces = 1000;
8362306a36Sopenharmony_ci	dev_t.t_ceasu = 8 * 1000;
8462306a36Sopenharmony_ci	dev_t.t_avdasu = t_scsnh_advnh - 7000;
8562306a36Sopenharmony_ci	dev_t.t_ce_avd = 1000;
8662306a36Sopenharmony_ci	dev_t.t_avdp_r = t_scsnh_advnh;
8762306a36Sopenharmony_ci	dev_t.cyc_aavdh_oe = 3;
8862306a36Sopenharmony_ci	dev_t.cyc_oe = 5;
8962306a36Sopenharmony_ci	dev_t.t_ce_rdyz = 7000;
9062306a36Sopenharmony_ci	dev_t.t_avdp_w = t_scsnh_advnh;
9162306a36Sopenharmony_ci	dev_t.cyc_aavdh_we = 3;
9262306a36Sopenharmony_ci	dev_t.cyc_wpl = 6;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	gpmc_calc_timings(&t, &tusb_sync, &dev_t);
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	return gpmc_cs_set_timings(sync_cs, &t, &tusb_sync);
9762306a36Sopenharmony_ci}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci/* tusb driver calls this when it changes the chip's clocking */
10062306a36Sopenharmony_cistatic int tusb6010_platform_retime(unsigned is_refclk)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	static const char	error[] =
10362306a36Sopenharmony_ci		KERN_ERR "tusb6010 %s retime error %d\n";
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	unsigned	sysclk_ps;
10662306a36Sopenharmony_ci	int		status;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	if (!refclk_psec)
10962306a36Sopenharmony_ci		return -ENODEV;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	sysclk_ps = is_refclk ? refclk_psec : TUSB6010_OSCCLK_60;
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	status = tusb_set_async_mode(sysclk_ps);
11462306a36Sopenharmony_ci	if (status < 0) {
11562306a36Sopenharmony_ci		printk(error, "async", status);
11662306a36Sopenharmony_ci		goto done;
11762306a36Sopenharmony_ci	}
11862306a36Sopenharmony_ci	status = tusb_set_sync_mode(sysclk_ps);
11962306a36Sopenharmony_ci	if (status < 0)
12062306a36Sopenharmony_ci		printk(error, "sync", status);
12162306a36Sopenharmony_cidone:
12262306a36Sopenharmony_ci	return status;
12362306a36Sopenharmony_ci}
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_cistatic struct resource tusb_resources[] = {
12662306a36Sopenharmony_ci	/* Order is significant!  The start/end fields
12762306a36Sopenharmony_ci	 * are updated during setup..
12862306a36Sopenharmony_ci	 */
12962306a36Sopenharmony_ci	{ /* Asynchronous access */
13062306a36Sopenharmony_ci		.flags	= IORESOURCE_MEM,
13162306a36Sopenharmony_ci	},
13262306a36Sopenharmony_ci	{ /* Synchronous access */
13362306a36Sopenharmony_ci		.flags	= IORESOURCE_MEM,
13462306a36Sopenharmony_ci	},
13562306a36Sopenharmony_ci};
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_cistatic u64 tusb_dmamask = ~(u32)0;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_cistatic struct platform_device tusb_device = {
14062306a36Sopenharmony_ci	.name		= "musb-tusb",
14162306a36Sopenharmony_ci	.id		= -1,
14262306a36Sopenharmony_ci	.dev = {
14362306a36Sopenharmony_ci		.dma_mask		= &tusb_dmamask,
14462306a36Sopenharmony_ci		.coherent_dma_mask	= 0xffffffff,
14562306a36Sopenharmony_ci	},
14662306a36Sopenharmony_ci	.num_resources	= ARRAY_SIZE(tusb_resources),
14762306a36Sopenharmony_ci	.resource	= tusb_resources,
14862306a36Sopenharmony_ci};
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci/* this may be called only from board-*.c setup code */
15262306a36Sopenharmony_ciint __init tusb6010_setup_interface(struct musb_hdrc_platform_data *data,
15362306a36Sopenharmony_ci		unsigned int ps_refclk, unsigned int waitpin,
15462306a36Sopenharmony_ci		unsigned int async, unsigned int sync,
15562306a36Sopenharmony_ci		unsigned int dmachan)
15662306a36Sopenharmony_ci{
15762306a36Sopenharmony_ci	int		status;
15862306a36Sopenharmony_ci	static char	error[] __initdata =
15962306a36Sopenharmony_ci		KERN_ERR "tusb6010 init error %d, %d\n";
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	/* ASYNC region, primarily for PIO */
16262306a36Sopenharmony_ci	status = gpmc_cs_request(async, SZ_16M, (unsigned long *)
16362306a36Sopenharmony_ci				&tusb_resources[0].start);
16462306a36Sopenharmony_ci	if (status < 0) {
16562306a36Sopenharmony_ci		printk(error, 1, status);
16662306a36Sopenharmony_ci		return status;
16762306a36Sopenharmony_ci	}
16862306a36Sopenharmony_ci	tusb_resources[0].end = tusb_resources[0].start + 0x9ff;
16962306a36Sopenharmony_ci	tusb_async.wait_pin = waitpin;
17062306a36Sopenharmony_ci	async_cs = async;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	status = gpmc_cs_program_settings(async_cs, &tusb_async);
17362306a36Sopenharmony_ci	if (status < 0)
17462306a36Sopenharmony_ci		return status;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	/* SYNC region, primarily for DMA */
17762306a36Sopenharmony_ci	status = gpmc_cs_request(sync, SZ_16M, (unsigned long *)
17862306a36Sopenharmony_ci				&tusb_resources[1].start);
17962306a36Sopenharmony_ci	if (status < 0) {
18062306a36Sopenharmony_ci		printk(error, 2, status);
18162306a36Sopenharmony_ci		return status;
18262306a36Sopenharmony_ci	}
18362306a36Sopenharmony_ci	tusb_resources[1].end = tusb_resources[1].start + 0x9ff;
18462306a36Sopenharmony_ci	tusb_sync.wait_pin = waitpin;
18562306a36Sopenharmony_ci	sync_cs = sync;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	status = gpmc_cs_program_settings(sync_cs, &tusb_sync);
18862306a36Sopenharmony_ci	if (status < 0)
18962306a36Sopenharmony_ci		return status;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	/* set up memory timings ... can speed them up later */
19262306a36Sopenharmony_ci	if (!ps_refclk) {
19362306a36Sopenharmony_ci		printk(error, 4, status);
19462306a36Sopenharmony_ci		return -ENODEV;
19562306a36Sopenharmony_ci	}
19662306a36Sopenharmony_ci	refclk_psec = ps_refclk;
19762306a36Sopenharmony_ci	status = tusb6010_platform_retime(1);
19862306a36Sopenharmony_ci	if (status < 0) {
19962306a36Sopenharmony_ci		printk(error, 5, status);
20062306a36Sopenharmony_ci		return status;
20162306a36Sopenharmony_ci	}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	/* finish device setup ... */
20462306a36Sopenharmony_ci	if (!data) {
20562306a36Sopenharmony_ci		printk(error, 6, status);
20662306a36Sopenharmony_ci		return -ENODEV;
20762306a36Sopenharmony_ci	}
20862306a36Sopenharmony_ci	tusb_device.dev.platform_data = data;
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	/* so far so good ... register the device */
21162306a36Sopenharmony_ci	status = platform_device_register(&tusb_device);
21262306a36Sopenharmony_ci	if (status < 0) {
21362306a36Sopenharmony_ci		printk(error, 7, status);
21462306a36Sopenharmony_ci		return status;
21562306a36Sopenharmony_ci	}
21662306a36Sopenharmony_ci	return 0;
21762306a36Sopenharmony_ci}
218