diff options
Diffstat (limited to 'drivers/usb/host/r8a66597-hcd.c')
-rw-r--r-- | drivers/usb/host/r8a66597-hcd.c | 330 |
1 files changed, 183 insertions, 147 deletions
diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index 3c263e51c1..a37696d83f 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -7,9 +7,11 @@ #include <common.h> #include <console.h> +#include <dm.h> #include <usb.h> #include <asm/io.h> #include <linux/iopoll.h> +#include <power/regulator.h> #include "r8a66597.h" @@ -19,33 +21,53 @@ #define R8A66597_DPRINT(...) #endif -static struct r8a66597 gr8a66597; +static inline struct usb_device *usb_dev_get_parent(struct usb_device *udev) +{ + struct udevice *parent = udev->dev->parent; + + /* + * When called from usb-uclass.c: usb_scan_device() udev->dev points + * to the parent udevice, not the actual udevice belonging to the + * udev as the device is not instantiated yet. + * + * If dev is an usb-bus, then we are called from usb_scan_device() for + * an usb-device plugged directly into the root port, return NULL. + */ + if (device_get_uclass_id(udev->dev) == UCLASS_USB) + return NULL; + + /* + * If these 2 are not the same we are being called from + * usb_scan_device() and udev itself is the parent. + */ + if (dev_get_parent_priv(udev->dev) != udev) + return udev; + + /* We are being called normally, use the parent pointer */ + if (device_get_uclass_id(parent) == UCLASS_USB_HUB) + return dev_get_parent_priv(parent); + + return NULL; +} static void get_hub_data(struct usb_device *dev, u16 *hub_devnum, u16 *hubport) { - int i; + struct usb_device *parent = usb_dev_get_parent(dev); *hub_devnum = 0; *hubport = 0; /* check a device connected to root_hub */ - if ((dev->parent && dev->parent->devnum == 1) || - (dev->devnum == 1)) + if ((parent && parent->devnum == 1) || + dev->devnum == 1) return; - for (i = 0; i < USB_MAXCHILDREN; i++) { - if (dev->parent->children[i] == dev) { - *hub_devnum = (u8)dev->parent->devnum; - *hubport = i; - return; - } - } - - printf("get_hub_data error.\n"); + *hub_devnum = (u8)parent->devnum; + *hubport = parent->portnr - 1; } static void set_devadd(struct r8a66597 *r8a66597, u8 r8a66597_address, - struct usb_device *dev, int port) + struct usb_device *dev, int port) { u16 val, usbspd, upphub, hubport; unsigned long devadd_reg = get_devadd_addr(r8a66597_address); @@ -61,17 +83,6 @@ static int r8a66597_clock_enable(struct r8a66597 *r8a66597) u16 tmp; int i = 0; -#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) - do { - r8a66597_write(r8a66597, SCKE, SYSCFG0); - tmp = r8a66597_read(r8a66597, SYSCFG0); - if (i++ > 1000) { - printf("register access fail.\n"); - return -1; - } - } while ((tmp & SCKE) != SCKE); - r8a66597_write(r8a66597, 0x04, 0x02); -#else do { r8a66597_write(r8a66597, USBE, SYSCFG0); tmp = r8a66597_read(r8a66597, SYSCFG0); @@ -81,57 +92,30 @@ static int r8a66597_clock_enable(struct r8a66597 *r8a66597) } } while ((tmp & USBE) != USBE); r8a66597_bclr(r8a66597, USBE, SYSCFG0); -#if !defined(CONFIG_RZA_USB) - r8a66597_mdfy(r8a66597, CONFIG_R8A66597_XTAL, XTAL, SYSCFG0); - - i = 0; - r8a66597_bset(r8a66597, XCKE, SYSCFG0); - do { - udelay(1000); - tmp = r8a66597_read(r8a66597, SYSCFG0); - if (i++ > 500) { - printf("register access fail.\n"); - return -1; - } - } while ((tmp & SCKE) != SCKE); -#else /* * RZ/A Only: * Bits XTAL(UCKSEL) and UPLLE in SYSCFG0 for USB0 controls both USB0 * and USB1, so we must always set the USB0 register */ #if (CONFIG_R8A66597_XTAL == 1) - setbits(le16, R8A66597_BASE0, XTAL); + r8a66597_bset(r8a66597, XTAL, SYSCFG0); #endif mdelay(1); - setbits(le16, R8A66597_BASE0, UPLLE); + r8a66597_bset(r8a66597, UPLLE, SYSCFG0); mdelay(1); r8a66597_bset(r8a66597, SUSPM, SUSPMODE0); -#endif /* CONFIG_RZA_USB */ -#endif /* #if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) */ return 0; } static void r8a66597_clock_disable(struct r8a66597 *r8a66597) { -#if !defined(CONFIG_RZA_USB) - r8a66597_bclr(r8a66597, SCKE, SYSCFG0); - udelay(1); -#if !defined(CONFIG_SUPERH_ON_CHIP_R8A66597) - r8a66597_bclr(r8a66597, PLLC, SYSCFG0); - r8a66597_bclr(r8a66597, XCKE, SYSCFG0); - r8a66597_bclr(r8a66597, USBE, SYSCFG0); -#endif -#else r8a66597_bclr(r8a66597, SUSPM, SUSPMODE0); - clrbits(le16, R8A66597_BASE0, UPLLE); + r8a66597_bclr(r8a66597, UPLLE, SYSCFG0); mdelay(1); r8a66597_bclr(r8a66597, USBE, SYSCFG0); mdelay(1); - -#endif } static void r8a66597_enable_port(struct r8a66597 *r8a66597, int port) @@ -141,10 +125,6 @@ static void r8a66597_enable_port(struct r8a66597 *r8a66597, int port) val = port ? DRPD : DCFM | DRPD; r8a66597_bset(r8a66597, val, get_syscfg_reg(port)); r8a66597_bset(r8a66597, HSE, get_syscfg_reg(port)); - -#if !defined(CONFIG_RZA_USB) - r8a66597_write(r8a66597, BURST | CPU_ADR_RD_WR, get_dmacfg_reg(port)); -#endif } static void r8a66597_disable_port(struct r8a66597 *r8a66597, int port) @@ -174,9 +154,6 @@ static int enable_controller(struct r8a66597 *r8a66597) if (ret < 0) return ret; -#if !defined(CONFIG_RZA_USB) - r8a66597_bset(r8a66597, CONFIG_R8A66597_LDRV & LDRV, PINCFG); -#endif r8a66597_bset(r8a66597, USBE, SYSCFG0); r8a66597_bset(r8a66597, INTL, SOFCFG); @@ -184,9 +161,9 @@ static int enable_controller(struct r8a66597 *r8a66597) for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++) r8a66597_write(r8a66597, 0, get_intenb_reg(port)); - r8a66597_bset(r8a66597, CONFIG_R8A66597_ENDIAN & BIGEND, CFIFOSEL); - r8a66597_bset(r8a66597, CONFIG_R8A66597_ENDIAN & BIGEND, D0FIFOSEL); - r8a66597_bset(r8a66597, CONFIG_R8A66597_ENDIAN & BIGEND, D1FIFOSEL); + r8a66597_bclr(r8a66597, BIGEND, CFIFOSEL); + r8a66597_bclr(r8a66597, BIGEND, D0FIFOSEL); + r8a66597_bclr(r8a66597, BIGEND, D1FIFOSEL); r8a66597_bset(r8a66597, TRNENSEL, SOFCFG); for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++) @@ -294,16 +271,13 @@ static int send_setup_packet(struct r8a66597 *r8a66597, struct usb_device *dev, unsigned long setup_addr = USBREQ; u16 intsts1; int timeout = 3000; -#if defined(CONFIG_RZA_USB) u16 dcpctr; -#endif u16 devsel = setup->request == USB_REQ_SET_ADDRESS ? 0 : dev->devnum; r8a66597_write(r8a66597, make_devsel(devsel) | (8 << dev->maxpacketsize), DCPMAXP); r8a66597_write(r8a66597, ~(SIGN | SACK), INTSTS1); -#if defined(CONFIG_RZA_USB) dcpctr = r8a66597_read(r8a66597, DCPCTR); if ((dcpctr & PID) == PID_BUF) { if (readw_poll_timeout(r8a66597->reg + DCPCTR, dcpctr, @@ -312,7 +286,6 @@ static int send_setup_packet(struct r8a66597 *r8a66597, struct usb_device *dev, return -ETIMEDOUT; } } -#endif for (i = 0; i < 4; i++) { r8a66597_write(r8a66597, le16_to_cpu(p[i]), setup_addr); @@ -349,7 +322,7 @@ static int send_bulk_packet(struct r8a66597 *r8a66597, struct usb_device *dev, R8A66597_DPRINT("%s\n", __func__); r8a66597_mdfy(r8a66597, MBW | BULK_OUT_PIPENUM, - MBW | CURPIPE, CFIFOSEL); + MBW | CURPIPE, CFIFOSEL); r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, BULK_OUT_PIPENUM); tmp = r8a66597_read(r8a66597, CFIFOCTR); if ((tmp & FRDY) == 0) { @@ -373,7 +346,7 @@ static int send_bulk_packet(struct r8a66597 *r8a66597, struct usb_device *dev, dev->act_len += size; r8a66597_mdfy(r8a66597, PID_BUF, PID, - get_pipectr_addr(BULK_OUT_PIPENUM)); + get_pipectr_addr(BULK_OUT_PIPENUM)); while (!(r8a66597_read(r8a66597, BEMPSTS) & (1 << BULK_OUT_PIPENUM))) if (ctrlc()) @@ -382,7 +355,7 @@ static int send_bulk_packet(struct r8a66597 *r8a66597, struct usb_device *dev, if (dev->act_len >= transfer_len) r8a66597_mdfy(r8a66597, PID_NAK, PID, - get_pipectr_addr(BULK_OUT_PIPENUM)); + get_pipectr_addr(BULK_OUT_PIPENUM)); return 0; } @@ -403,17 +376,17 @@ static int receive_bulk_packet(struct r8a66597 *r8a66597, /* prepare */ if (dev->act_len == 0) { r8a66597_mdfy(r8a66597, PID_NAK, PID, - get_pipectr_addr(pipenum)); + get_pipectr_addr(pipenum)); r8a66597_write(r8a66597, ~(1 << pipenum), BRDYSTS); r8a66597_write(r8a66597, TRCLR, get_pipetre_addr(pipenum)); r8a66597_write(r8a66597, - (transfer_len + maxpacket - 1) / maxpacket, + (transfer_len + maxpacket - 1) / maxpacket, get_pipetrn_addr(pipenum)); r8a66597_bset(r8a66597, TRENB, get_pipetre_addr(pipenum)); r8a66597_mdfy(r8a66597, PID_BUF, PID, - get_pipectr_addr(pipenum)); + get_pipectr_addr(pipenum)); } r8a66597_mdfy(r8a66597, MBW | pipenum, MBW | CURPIPE, CFIFOSEL); @@ -490,7 +463,7 @@ static int receive_control_packet(struct r8a66597 *r8a66597, } static int send_status_packet(struct r8a66597 *r8a66597, - unsigned long pipe) + unsigned long pipe) { r8a66597_bset(r8a66597, SQSET, DCPCTR); r8a66597_mdfy(r8a66597, PID_NAK, PID, DCPCTR); @@ -581,16 +554,15 @@ static int check_usb_device_connecting(struct r8a66597 *r8a66597) return -1; /* fail */ } -/*-------------------------------------------------------------------------* - * Virtual Root Hub - *-------------------------------------------------------------------------*/ +/* Virtual Root Hub */ #include <usbroothubdes.h> -static int r8a66597_submit_rh_msg(struct usb_device *dev, unsigned long pipe, - void *buffer, int transfer_len, struct devrequest *cmd) +static int r8a66597_submit_rh_msg(struct udevice *udev, struct usb_device *dev, + unsigned long pipe, void *buffer, + int transfer_len, struct devrequest *cmd) { - struct r8a66597 *r8a66597 = &gr8a66597; + struct r8a66597 *r8a66597 = dev_get_priv(udev); int leni = transfer_len; int len = 0; int stat = 0; @@ -658,40 +630,40 @@ static int r8a66597_submit_rh_msg(struct usb_device *dev, unsigned long pipe, } break; case RH_SET_ADDRESS: - gr8a66597.rh_devnum = wValue; + r8a66597->rh_devnum = wValue; break; case RH_GET_DESCRIPTOR: switch ((wValue & 0xff00) >> 8) { case (0x01): /* device descriptor */ len = min_t(unsigned int, - leni, + leni, min_t(unsigned int, - sizeof(root_hub_dev_des), + sizeof(root_hub_dev_des), wLength)); memcpy(buffer, root_hub_dev_des, len); break; case (0x02): /* configuration descriptor */ len = min_t(unsigned int, - leni, + leni, min_t(unsigned int, - sizeof(root_hub_config_des), + sizeof(root_hub_config_des), wLength)); memcpy(buffer, root_hub_config_des, len); break; case (0x03): /* string descriptors */ if (wValue == 0x0300) { len = min_t(unsigned int, - leni, + leni, min_t(unsigned int, - sizeof(root_hub_str_index0), + sizeof(root_hub_str_index0), wLength)); memcpy(buffer, root_hub_str_index0, len); } if (wValue == 0x0301) { len = min_t(unsigned int, - leni, + leni, min_t(unsigned int, - sizeof(root_hub_str_index1), + sizeof(root_hub_str_index1), wLength)); memcpy(buffer, root_hub_str_index1, len); } @@ -724,7 +696,8 @@ static int r8a66597_submit_rh_msg(struct usb_device *dev, unsigned long pipe, } else { data[0] += 2; data[8] = (temp & RH_B_DR) >> 8; - data[10] = data[9] = 0xff; + data[9] = 0xff; + data[10] = 0xff; } len = min_t(unsigned int, leni, @@ -734,7 +707,7 @@ static int r8a66597_submit_rh_msg(struct usb_device *dev, unsigned long pipe, } case RH_GET_CONFIGURATION: - *(__u8 *) buffer = 0x01; + *(__u8 *)buffer = 0x01; len = 1; break; case RH_SET_CONFIGURATION: @@ -754,50 +727,22 @@ static int r8a66597_submit_rh_msg(struct usb_device *dev, unsigned long pipe, return stat; } -int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer, - int transfer_len) +static int r8a66597_submit_control_msg(struct udevice *udev, + struct usb_device *dev, + unsigned long pipe, void *buffer, + int length, struct devrequest *setup) { - struct r8a66597 *r8a66597 = &gr8a66597; - int ret = 0; - - R8A66597_DPRINT("%s\n", __func__); - R8A66597_DPRINT("pipe = %08x, buffer = %p, len = %d, devnum = %d\n", - pipe, buffer, transfer_len, dev->devnum); - - set_devadd(r8a66597, dev->devnum, dev, 0); - - pipe_buffer_setting(r8a66597, dev, pipe); - - dev->act_len = 0; - while (dev->act_len < transfer_len && ret == 0) { - if (ctrlc()) - return -1; - - if (usb_pipein(pipe)) - ret = receive_bulk_packet(r8a66597, dev, pipe, buffer, - transfer_len); - else - ret = send_bulk_packet(r8a66597, dev, pipe, buffer, - transfer_len); - } - - if (ret == 0) - dev->status = 0; - - return ret; -} - -int submit_control_msg(struct usb_device *dev, unsigned long pipe, - void *buffer, int transfer_len, struct devrequest *setup) -{ - struct r8a66597 *r8a66597 = &gr8a66597; + struct r8a66597 *r8a66597 = dev_get_priv(udev); u16 r8a66597_address = setup->request == USB_REQ_SET_ADDRESS ? 0 : dev->devnum; + debug("%s: dev='%s', udev=%p, udev->dev='%s', portnr=%d\n", __func__, + udev->name, dev, dev->dev->name, dev->portnr); + R8A66597_DPRINT("%s\n", __func__); if (usb_pipedevice(pipe) == r8a66597->rh_devnum) - return r8a66597_submit_rh_msg(dev, pipe, buffer, transfer_len, - setup); + return r8a66597_submit_rh_msg(udev, dev, pipe, buffer, + length, setup); R8A66597_DPRINT("%s: setup\n", __func__); set_devadd(r8a66597, r8a66597_address, dev, 0); @@ -810,7 +755,7 @@ int submit_control_msg(struct usb_device *dev, unsigned long pipe, dev->act_len = 0; if (usb_pipein(pipe)) if (receive_control_packet(r8a66597, dev, buffer, - transfer_len) < 0) + length) < 0) return -1; if (send_status_packet(r8a66597, pipe) < 0) @@ -821,40 +766,131 @@ int submit_control_msg(struct usb_device *dev, unsigned long pipe, return 0; } -int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer, - int transfer_len, int interval) +static int r8a66597_submit_bulk_msg(struct udevice *udev, + struct usb_device *dev, unsigned long pipe, + void *buffer, int length) { - /* no implement */ + struct r8a66597 *r8a66597 = dev_get_priv(udev); + int ret = 0; + + debug("%s: dev='%s', udev=%p\n", __func__, udev->name, dev); + R8A66597_DPRINT("%s\n", __func__); - return 0; + R8A66597_DPRINT("pipe = %08x, buffer = %p, len = %d, devnum = %d\n", + pipe, buffer, length, dev->devnum); + + set_devadd(r8a66597, dev->devnum, dev, 0); + + pipe_buffer_setting(r8a66597, dev, pipe); + + dev->act_len = 0; + while (dev->act_len < length && ret == 0) { + if (ctrlc()) + return -1; + + if (usb_pipein(pipe)) + ret = receive_bulk_packet(r8a66597, dev, pipe, buffer, + length); + else + ret = send_bulk_packet(r8a66597, dev, pipe, buffer, + length); + } + + if (ret == 0) + dev->status = 0; + + return ret; } -int usb_lowlevel_init(int index, enum usb_init_type init, void **controller) +static int r8a66597_usb_ofdata_to_platdata(struct udevice *dev) { - struct r8a66597 *r8a66597 = &gr8a66597; + struct r8a66597 *priv = dev_get_priv(dev); + fdt_addr_t addr; - R8A66597_DPRINT("%s\n", __func__); + addr = dev_read_addr(dev); + if (addr == FDT_ADDR_T_NONE) + return -EINVAL; + priv->reg = addr; - memset(r8a66597, 0, sizeof(*r8a66597)); - r8a66597->reg = CONFIG_R8A66597_BASE_ADDR; + return 0; +} + +static int r8a66597_usb_probe(struct udevice *dev) +{ + struct r8a66597 *priv = dev_get_priv(dev); + struct usb_bus_priv *bus_priv = dev_get_uclass_priv(dev); + int ret; + + bus_priv->desc_before_addr = true; + + if (CONFIG_IS_ENABLED(DM_REGULATOR)) { + ret = device_get_supply_regulator(dev, "vbus-supply", + &priv->vbus_supply); + if (ret) { + dev_err(dev, + "can't get VBUS supply\n"); + return ret; + } + + ret = regulator_set_enable(priv->vbus_supply, true); + if (ret) { + dev_err(dev, + "can't enable VBUS supply\n"); + return ret; + } + } - disable_controller(r8a66597); + disable_controller(priv); mdelay(100); - enable_controller(r8a66597); - r8a66597_port_power(r8a66597, 0 , 1); + enable_controller(priv); + r8a66597_port_power(priv, 0, 1); /* check usb device */ - check_usb_device_connecting(r8a66597); + check_usb_device_connecting(priv); mdelay(50); return 0; } -int usb_lowlevel_stop(int index) +static int r8a66597_usb_remove(struct udevice *dev) { - disable_controller(&gr8a66597); + struct r8a66597 *priv = dev_get_priv(dev); + int ret; + + disable_controller(priv); + + if (CONFIG_IS_ENABLED(DM_REGULATOR)) { + ret = regulator_set_enable(priv->vbus_supply, false); + if (ret) { + dev_err(dev, + "can't disable VBUS supply\n"); + return ret; + } + } return 0; } + +struct dm_usb_ops r8a66597_usb_ops = { + .control = r8a66597_submit_control_msg, + .bulk = r8a66597_submit_bulk_msg, +}; + +static const struct udevice_id r8a66597_usb_ids[] = { + { .compatible = "renesas,rza1-usbhs" }, + { } +}; + +U_BOOT_DRIVER(usb_r8a66597) = { + .name = "r8a66597_usb", + .id = UCLASS_USB, + .of_match = r8a66597_usb_ids, + .ofdata_to_platdata = r8a66597_usb_ofdata_to_platdata, + .probe = r8a66597_usb_probe, + .remove = r8a66597_usb_remove, + .ops = &r8a66597_usb_ops, + .priv_auto_alloc_size = sizeof(struct r8a66597), + .flags = DM_FLAG_ALLOC_PRIV_DMA, +}; |