// SPDX-License-Identifier: (GPL-2.0+ OR MIT) /* * Copyright (c) 2019 Amlogic, Inc. All rights reserved. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../phy/phy-aml-new-usb-v2.h" struct amlogic_usb_v2 *g_phy_com_v2; BLOCKING_NOTIFIER_HEAD(aml_new_usb_v2_notifier_list); int aml_new_usb_v2_register_notifier(struct notifier_block *nb) { int ret; ret = blocking_notifier_chain_register (&aml_new_usb_v2_notifier_list, nb); return ret; } EXPORT_SYMBOL(aml_new_usb_v2_register_notifier); int aml_new_usb_v2_unregister_notifier(struct notifier_block *nb) { int ret; ret = blocking_notifier_chain_unregister (&aml_new_usb_v2_notifier_list, nb); return ret; } EXPORT_SYMBOL(aml_new_usb_v2_unregister_notifier); void aml_new_usb3_get_phy(struct amlogic_usb_v2 *phy) { g_phy_com_v2 = phy; } EXPORT_SYMBOL(aml_new_usb3_get_phy); void aml_new_usb_notifier_call(unsigned long is_device_on) { blocking_notifier_call_chain (&aml_new_usb_v2_notifier_list, is_device_on, NULL); } EXPORT_SYMBOL(aml_new_usb_notifier_call); void resume_xhci_port_a(void) { if (!g_phy_com_v2) return; if (g_phy_com_v2->resume_xhci_p_a) g_phy_com_v2->resume_xhci_p_a(); } void force_disable_xhci_port_a(void) { if (!g_phy_com_v2) return; if (g_phy_com_v2->disable_port_a) g_phy_com_v2->disable_port_a(); } void aml_new_usb_v2_init(void) { if (!g_phy_com_v2) return; if (g_phy_com_v2->usb2_phy_init) g_phy_com_v2->usb2_phy_init(); } EXPORT_SYMBOL(aml_new_usb_v2_init); int aml_new_usb_get_mode(void) { if (!g_phy_com_v2) return -1; if (g_phy_com_v2->usb2_get_mode) return g_phy_com_v2->usb2_get_mode(); } EXPORT_SYMBOL(aml_new_usb_get_mode); void cr_bus_addr(unsigned int addr) { union phy3_r4 phy_r4 = {.d32 = 0}; union phy3_r5 phy_r5 = {.d32 = 0}; unsigned long timeout_jiffies; phy_r4.b.phy_cr_data_in = addr; writel(phy_r4.d32, g_phy_com_v2->phy3_cfg_r4); phy_r4.b.phy_cr_cap_addr = 0; writel(phy_r4.d32, g_phy_com_v2->phy3_cfg_r4); phy_r4.b.phy_cr_cap_addr = 1; writel(phy_r4.d32, g_phy_com_v2->phy3_cfg_r4); timeout_jiffies = jiffies + msecs_to_jiffies(1000); do { phy_r5.d32 = readl(g_phy_com_v2->phy3_cfg_r5); } while (phy_r5.b.phy_cr_ack == 0 && time_is_after_jiffies(timeout_jiffies)); phy_r4.b.phy_cr_cap_addr = 0; writel(phy_r4.d32, g_phy_com_v2->phy3_cfg_r4); timeout_jiffies = jiffies + msecs_to_jiffies(1000); do { phy_r5.d32 = readl(g_phy_com_v2->phy3_cfg_r5); } while (phy_r5.b.phy_cr_ack == 1 && time_is_after_jiffies(timeout_jiffies)); } EXPORT_SYMBOL(cr_bus_addr); int cr_bus_read(unsigned int addr) { int data; union phy3_r4 phy_r4 = {.d32 = 0}; union phy3_r5 phy_r5 = {.d32 = 0}; unsigned long timeout_jiffies; cr_bus_addr(addr); phy_r4.b.phy_cr_read = 0; writel(phy_r4.d32, g_phy_com_v2->phy3_cfg_r4); phy_r4.b.phy_cr_read = 1; writel(phy_r4.d32, g_phy_com_v2->phy3_cfg_r4); timeout_jiffies = jiffies + msecs_to_jiffies(1000); do { phy_r5.d32 = readl(g_phy_com_v2->phy3_cfg_r5); } while (phy_r5.b.phy_cr_ack == 0 && time_is_after_jiffies(timeout_jiffies)); data = phy_r5.b.phy_cr_data_out; phy_r4.b.phy_cr_read = 0; writel(phy_r4.d32, g_phy_com_v2->phy3_cfg_r4); timeout_jiffies = jiffies + msecs_to_jiffies(1000); do { phy_r5.d32 = readl(g_phy_com_v2->phy3_cfg_r5); } while (phy_r5.b.phy_cr_ack == 1 && time_is_after_jiffies(timeout_jiffies)); return data; } EXPORT_SYMBOL(cr_bus_read); void cr_bus_write(unsigned int addr, unsigned int data) { union phy3_r4 phy_r4 = {.d32 = 0}; union phy3_r5 phy_r5 = {.d32 = 0}; unsigned long timeout_jiffies; cr_bus_addr(addr); phy_r4.b.phy_cr_data_in = data; writel(phy_r4.d32, g_phy_com_v2->phy3_cfg_r4); phy_r4.b.phy_cr_cap_data = 0; writel(phy_r4.d32, g_phy_com_v2->phy3_cfg_r4); phy_r4.b.phy_cr_cap_data = 1; writel(phy_r4.d32, g_phy_com_v2->phy3_cfg_r4); timeout_jiffies = jiffies + msecs_to_jiffies(1000); do { phy_r5.d32 = readl(g_phy_com_v2->phy3_cfg_r5); } while (phy_r5.b.phy_cr_ack == 0 && time_is_after_jiffies(timeout_jiffies)); phy_r4.b.phy_cr_cap_data = 0; writel(phy_r4.d32, g_phy_com_v2->phy3_cfg_r4); timeout_jiffies = jiffies + msecs_to_jiffies(1000); do { phy_r5.d32 = readl(g_phy_com_v2->phy3_cfg_r5); } while (phy_r5.b.phy_cr_ack == 1 && time_is_after_jiffies(timeout_jiffies)); phy_r4.b.phy_cr_write = 0; writel(phy_r4.d32, g_phy_com_v2->phy3_cfg_r4); phy_r4.b.phy_cr_write = 1; writel(phy_r4.d32, g_phy_com_v2->phy3_cfg_r4); timeout_jiffies = jiffies + msecs_to_jiffies(1000); do { phy_r5.d32 = readl(g_phy_com_v2->phy3_cfg_r5); } while (phy_r5.b.phy_cr_ack == 0 && time_is_after_jiffies(timeout_jiffies)); phy_r4.b.phy_cr_write = 0; writel(phy_r4.d32, g_phy_com_v2->phy3_cfg_r4); timeout_jiffies = jiffies + msecs_to_jiffies(1000); do { phy_r5.d32 = readl(g_phy_com_v2->phy3_cfg_r5); } while (phy_r5.b.phy_cr_ack == 1 && time_is_after_jiffies(timeout_jiffies)); } EXPORT_SYMBOL(cr_bus_write);