mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2024-12-29 17:23:36 +00:00
8e0285ab95
The TUSB6010 (MUSB) device is picking up some GPIO lines
hardcoded by number and passing on to the TUSB6010 device
when registering it.
Instead of nasty workarounds, provide a GPIO descriptor
table and then make the TUSB6010 MUSB glue driver pick up
the GPIO lines directly, convert it to an IRQ and pass down
to the MUSB driver. OMAP2 is the only system using the
TUSB6010.
Stash the GPIO descriptors in the glue layer and use
then to power up and down the TUSB6010 on-demand, instead
of using boardfile callbacks.
Since the OMAP2 boards are the only boards using the
.set_power() and .board_set_power() callbacks, we can
just delete them as the power is now handled directly
in the TUSB6010 glue code.
Cc: Bin Liu <b-liu@ti.com>
Cc: linux-usb@vger.kernel.org
Fixes: 92bf78b33b
("gpio: omap: use dynamic allocation of base")
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
218 lines
5.0 KiB
C
218 lines
5.0 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* linux/arch/arm/mach-omap2/usb-tusb6010.c
|
|
*
|
|
* Copyright (C) 2006 Nokia Corporation
|
|
*/
|
|
|
|
#include <linux/err.h>
|
|
#include <linux/string.h>
|
|
#include <linux/types.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/export.h>
|
|
#include <linux/platform_data/usb-omap.h>
|
|
|
|
#include <linux/usb/musb.h>
|
|
|
|
#include "usb-tusb6010.h"
|
|
#include "gpmc.h"
|
|
|
|
static u8 async_cs, sync_cs;
|
|
static unsigned refclk_psec;
|
|
|
|
static struct gpmc_settings tusb_async = {
|
|
.wait_on_read = true,
|
|
.wait_on_write = true,
|
|
.device_width = GPMC_DEVWIDTH_16BIT,
|
|
.mux_add_data = GPMC_MUX_AD,
|
|
};
|
|
|
|
static struct gpmc_settings tusb_sync = {
|
|
.burst_read = true,
|
|
.burst_write = true,
|
|
.sync_read = true,
|
|
.sync_write = true,
|
|
.wait_on_read = true,
|
|
.wait_on_write = true,
|
|
.burst_len = GPMC_BURST_16,
|
|
.device_width = GPMC_DEVWIDTH_16BIT,
|
|
.mux_add_data = GPMC_MUX_AD,
|
|
};
|
|
|
|
/* NOTE: timings are from tusb 6010 datasheet Rev 1.8, 12-Sept 2006 */
|
|
|
|
static int tusb_set_async_mode(unsigned sysclk_ps)
|
|
{
|
|
struct gpmc_device_timings dev_t;
|
|
struct gpmc_timings t;
|
|
unsigned t_acsnh_advnh = sysclk_ps + 3000;
|
|
|
|
memset(&dev_t, 0, sizeof(dev_t));
|
|
|
|
dev_t.t_ceasu = 8 * 1000;
|
|
dev_t.t_avdasu = t_acsnh_advnh - 7000;
|
|
dev_t.t_ce_avd = 1000;
|
|
dev_t.t_avdp_r = t_acsnh_advnh;
|
|
dev_t.t_oeasu = t_acsnh_advnh + 1000;
|
|
dev_t.t_oe = 300;
|
|
dev_t.t_cez_r = 7000;
|
|
dev_t.t_cez_w = dev_t.t_cez_r;
|
|
dev_t.t_avdp_w = t_acsnh_advnh;
|
|
dev_t.t_weasu = t_acsnh_advnh + 1000;
|
|
dev_t.t_wpl = 300;
|
|
dev_t.cyc_aavdh_we = 1;
|
|
|
|
gpmc_calc_timings(&t, &tusb_async, &dev_t);
|
|
|
|
return gpmc_cs_set_timings(async_cs, &t, &tusb_async);
|
|
}
|
|
|
|
static int tusb_set_sync_mode(unsigned sysclk_ps)
|
|
{
|
|
struct gpmc_device_timings dev_t;
|
|
struct gpmc_timings t;
|
|
unsigned t_scsnh_advnh = sysclk_ps + 3000;
|
|
|
|
memset(&dev_t, 0, sizeof(dev_t));
|
|
|
|
dev_t.clk = 11100;
|
|
dev_t.t_bacc = 1000;
|
|
dev_t.t_ces = 1000;
|
|
dev_t.t_ceasu = 8 * 1000;
|
|
dev_t.t_avdasu = t_scsnh_advnh - 7000;
|
|
dev_t.t_ce_avd = 1000;
|
|
dev_t.t_avdp_r = t_scsnh_advnh;
|
|
dev_t.cyc_aavdh_oe = 3;
|
|
dev_t.cyc_oe = 5;
|
|
dev_t.t_ce_rdyz = 7000;
|
|
dev_t.t_avdp_w = t_scsnh_advnh;
|
|
dev_t.cyc_aavdh_we = 3;
|
|
dev_t.cyc_wpl = 6;
|
|
|
|
gpmc_calc_timings(&t, &tusb_sync, &dev_t);
|
|
|
|
return gpmc_cs_set_timings(sync_cs, &t, &tusb_sync);
|
|
}
|
|
|
|
/* tusb driver calls this when it changes the chip's clocking */
|
|
static int tusb6010_platform_retime(unsigned is_refclk)
|
|
{
|
|
static const char error[] =
|
|
KERN_ERR "tusb6010 %s retime error %d\n";
|
|
|
|
unsigned sysclk_ps;
|
|
int status;
|
|
|
|
if (!refclk_psec)
|
|
return -ENODEV;
|
|
|
|
sysclk_ps = is_refclk ? refclk_psec : TUSB6010_OSCCLK_60;
|
|
|
|
status = tusb_set_async_mode(sysclk_ps);
|
|
if (status < 0) {
|
|
printk(error, "async", status);
|
|
goto done;
|
|
}
|
|
status = tusb_set_sync_mode(sysclk_ps);
|
|
if (status < 0)
|
|
printk(error, "sync", status);
|
|
done:
|
|
return status;
|
|
}
|
|
|
|
static struct resource tusb_resources[] = {
|
|
/* Order is significant! The start/end fields
|
|
* are updated during setup..
|
|
*/
|
|
{ /* Asynchronous access */
|
|
.flags = IORESOURCE_MEM,
|
|
},
|
|
{ /* Synchronous access */
|
|
.flags = IORESOURCE_MEM,
|
|
},
|
|
};
|
|
|
|
static u64 tusb_dmamask = ~(u32)0;
|
|
|
|
static struct platform_device tusb_device = {
|
|
.name = "musb-tusb",
|
|
.id = -1,
|
|
.dev = {
|
|
.dma_mask = &tusb_dmamask,
|
|
.coherent_dma_mask = 0xffffffff,
|
|
},
|
|
.num_resources = ARRAY_SIZE(tusb_resources),
|
|
.resource = tusb_resources,
|
|
};
|
|
|
|
|
|
/* this may be called only from board-*.c setup code */
|
|
int __init tusb6010_setup_interface(struct musb_hdrc_platform_data *data,
|
|
unsigned int ps_refclk, unsigned int waitpin,
|
|
unsigned int async, unsigned int sync,
|
|
unsigned int dmachan)
|
|
{
|
|
int status;
|
|
static char error[] __initdata =
|
|
KERN_ERR "tusb6010 init error %d, %d\n";
|
|
|
|
/* ASYNC region, primarily for PIO */
|
|
status = gpmc_cs_request(async, SZ_16M, (unsigned long *)
|
|
&tusb_resources[0].start);
|
|
if (status < 0) {
|
|
printk(error, 1, status);
|
|
return status;
|
|
}
|
|
tusb_resources[0].end = tusb_resources[0].start + 0x9ff;
|
|
tusb_async.wait_pin = waitpin;
|
|
async_cs = async;
|
|
|
|
status = gpmc_cs_program_settings(async_cs, &tusb_async);
|
|
if (status < 0)
|
|
return status;
|
|
|
|
/* SYNC region, primarily for DMA */
|
|
status = gpmc_cs_request(sync, SZ_16M, (unsigned long *)
|
|
&tusb_resources[1].start);
|
|
if (status < 0) {
|
|
printk(error, 2, status);
|
|
return status;
|
|
}
|
|
tusb_resources[1].end = tusb_resources[1].start + 0x9ff;
|
|
tusb_sync.wait_pin = waitpin;
|
|
sync_cs = sync;
|
|
|
|
status = gpmc_cs_program_settings(sync_cs, &tusb_sync);
|
|
if (status < 0)
|
|
return status;
|
|
|
|
/* set up memory timings ... can speed them up later */
|
|
if (!ps_refclk) {
|
|
printk(error, 4, status);
|
|
return -ENODEV;
|
|
}
|
|
refclk_psec = ps_refclk;
|
|
status = tusb6010_platform_retime(1);
|
|
if (status < 0) {
|
|
printk(error, 5, status);
|
|
return status;
|
|
}
|
|
|
|
/* finish device setup ... */
|
|
if (!data) {
|
|
printk(error, 6, status);
|
|
return -ENODEV;
|
|
}
|
|
tusb_device.dev.platform_data = data;
|
|
|
|
/* so far so good ... register the device */
|
|
status = platform_device_register(&tusb_device);
|
|
if (status < 0) {
|
|
printk(error, 7, status);
|
|
return status;
|
|
}
|
|
return 0;
|
|
}
|