123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241 |
- /* linux/drivers/usb/phy/phy-samsung-usb.c
- *
- * Copyright (c) 2012 Samsung Electronics Co., Ltd.
- * http://www.samsung.com
- *
- * Author: Praveen Paneri <p.paneri@samsung.com>
- *
- * Samsung USB-PHY helper driver with common function calls;
- * interacts with Samsung USB 2.0 PHY controller driver and later
- * with Samsung USB 3.0 PHY driver.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
- #include <linux/module.h>
- #include <linux/platform_device.h>
- #include <linux/clk.h>
- #include <linux/device.h>
- #include <linux/err.h>
- #include <linux/io.h>
- #include <linux/of.h>
- #include <linux/of_address.h>
- #include <linux/usb/samsung_usb_phy.h>
- #include "phy-samsung-usb.h"
- int samsung_usbphy_parse_dt(struct samsung_usbphy *sphy)
- {
- struct device_node *usbphy_sys;
- /* Getting node for system controller interface for usb-phy */
- usbphy_sys = of_get_child_by_name(sphy->dev->of_node, "usbphy-sys");
- if (!usbphy_sys) {
- dev_err(sphy->dev, "No sys-controller interface for usb-phy\n");
- return -ENODEV;
- }
- sphy->pmuregs = of_iomap(usbphy_sys, 0);
- if (sphy->pmuregs == NULL) {
- dev_err(sphy->dev, "Can't get usb-phy pmu control register\n");
- goto err0;
- }
- sphy->sysreg = of_iomap(usbphy_sys, 1);
- /*
- * Not returning error code here, since this situation is not fatal.
- * Few SoCs may not have this switch available
- */
- if (sphy->sysreg == NULL)
- dev_warn(sphy->dev, "Can't get usb-phy sysreg cfg register\n");
- of_node_put(usbphy_sys);
- return 0;
- err0:
- of_node_put(usbphy_sys);
- return -ENXIO;
- }
- EXPORT_SYMBOL_GPL(samsung_usbphy_parse_dt);
- /*
- * Set isolation here for phy.
- * Here 'on = true' would mean USB PHY block is isolated, hence
- * de-activated and vice-versa.
- */
- void samsung_usbphy_set_isolation_4210(struct samsung_usbphy *sphy, bool on)
- {
- void __iomem *reg = NULL;
- u32 reg_val;
- u32 en_mask = 0;
- if (!sphy->pmuregs) {
- dev_warn(sphy->dev, "Can't set pmu isolation\n");
- return;
- }
- if (sphy->phy_type == USB_PHY_TYPE_DEVICE) {
- reg = sphy->pmuregs + sphy->drv_data->devphy_reg_offset;
- en_mask = sphy->drv_data->devphy_en_mask;
- } else if (sphy->phy_type == USB_PHY_TYPE_HOST) {
- reg = sphy->pmuregs + sphy->drv_data->hostphy_reg_offset;
- en_mask = sphy->drv_data->hostphy_en_mask;
- }
- reg_val = readl(reg);
- if (on)
- reg_val &= ~en_mask;
- else
- reg_val |= en_mask;
- writel(reg_val, reg);
- if (sphy->drv_data->cpu_type == TYPE_EXYNOS4X12) {
- writel(reg_val, sphy->pmuregs + EXYNOS4X12_PHY_HSIC_CTRL0);
- writel(reg_val, sphy->pmuregs + EXYNOS4X12_PHY_HSIC_CTRL1);
- }
- }
- EXPORT_SYMBOL_GPL(samsung_usbphy_set_isolation_4210);
- /*
- * Configure the mode of working of usb-phy here: HOST/DEVICE.
- */
- void samsung_usbphy_cfg_sel(struct samsung_usbphy *sphy)
- {
- u32 reg;
- if (!sphy->sysreg) {
- dev_warn(sphy->dev, "Can't configure specified phy mode\n");
- return;
- }
- reg = readl(sphy->sysreg);
- if (sphy->phy_type == USB_PHY_TYPE_DEVICE)
- reg &= ~EXYNOS_USB20PHY_CFG_HOST_LINK;
- else if (sphy->phy_type == USB_PHY_TYPE_HOST)
- reg |= EXYNOS_USB20PHY_CFG_HOST_LINK;
- writel(reg, sphy->sysreg);
- }
- EXPORT_SYMBOL_GPL(samsung_usbphy_cfg_sel);
- /*
- * PHYs are different for USB Device and USB Host.
- * This make sure that correct PHY type is selected before
- * any operation on PHY.
- */
- int samsung_usbphy_set_type(struct usb_phy *phy,
- enum samsung_usb_phy_type phy_type)
- {
- struct samsung_usbphy *sphy = phy_to_sphy(phy);
- sphy->phy_type = phy_type;
- return 0;
- }
- EXPORT_SYMBOL_GPL(samsung_usbphy_set_type);
- int samsung_usbphy_rate_to_clksel_64xx(struct samsung_usbphy *sphy,
- unsigned long rate)
- {
- unsigned int clksel;
- switch (rate) {
- case 12 * MHZ:
- clksel = PHYCLK_CLKSEL_12M;
- break;
- case 24 * MHZ:
- clksel = PHYCLK_CLKSEL_24M;
- break;
- case 48 * MHZ:
- clksel = PHYCLK_CLKSEL_48M;
- break;
- default:
- dev_err(sphy->dev,
- "Invalid reference clock frequency: %lu\n", rate);
- return -EINVAL;
- }
- return clksel;
- }
- EXPORT_SYMBOL_GPL(samsung_usbphy_rate_to_clksel_64xx);
- int samsung_usbphy_rate_to_clksel_4x12(struct samsung_usbphy *sphy,
- unsigned long rate)
- {
- unsigned int clksel;
- switch (rate) {
- case 9600 * KHZ:
- clksel = FSEL_CLKSEL_9600K;
- break;
- case 10 * MHZ:
- clksel = FSEL_CLKSEL_10M;
- break;
- case 12 * MHZ:
- clksel = FSEL_CLKSEL_12M;
- break;
- case 19200 * KHZ:
- clksel = FSEL_CLKSEL_19200K;
- break;
- case 20 * MHZ:
- clksel = FSEL_CLKSEL_20M;
- break;
- case 24 * MHZ:
- clksel = FSEL_CLKSEL_24M;
- break;
- case 50 * MHZ:
- clksel = FSEL_CLKSEL_50M;
- break;
- default:
- dev_err(sphy->dev,
- "Invalid reference clock frequency: %lu\n", rate);
- return -EINVAL;
- }
- return clksel;
- }
- EXPORT_SYMBOL_GPL(samsung_usbphy_rate_to_clksel_4x12);
- /*
- * Returns reference clock frequency selection value
- */
- int samsung_usbphy_get_refclk_freq(struct samsung_usbphy *sphy)
- {
- struct clk *ref_clk;
- unsigned long rate;
- int refclk_freq;
- /*
- * In exynos5250 USB host and device PHY use
- * external crystal clock XXTI
- */
- if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250)
- ref_clk = clk_get(sphy->dev, "ext_xtal");
- else
- ref_clk = clk_get(sphy->dev, "xusbxti");
- if (IS_ERR(ref_clk)) {
- dev_err(sphy->dev, "Failed to get reference clock\n");
- return PTR_ERR(ref_clk);
- }
- rate = clk_get_rate(ref_clk);
- refclk_freq = sphy->drv_data->rate_to_clksel(sphy, rate);
- clk_put(ref_clk);
- return refclk_freq;
- }
- EXPORT_SYMBOL_GPL(samsung_usbphy_get_refclk_freq);
|