aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGiuseppe CAVALLARO <peppe.cavallaro@st.com>2013-11-28 06:24:00 +0100
committerPeter Griffin <peter.griffin@linaro.org>2014-06-25 17:00:22 +0100
commit8892e8d863dec0e3cf885fb323fd81487ba11de3 (patch)
tree0d79f84365c51443461ff0dcee8e463315adcae3
parent68246da9fde29bfec78e4ddf270b30b594a9b296 (diff)
usb: phy: add STiH407 picoPHY for USB2
This patch adds the support for the picoPHY to manage USB2 devices. This is available on STiH407 and used by the DWC3 HC port#2. v2: use devm_reset_control_get Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com> Conflicts: drivers/usb/phy/Kconfig drivers/usb/phy/Makefile
-rw-r--r--drivers/usb/phy/Kconfig9
-rw-r--r--drivers/usb/phy/Makefile2
-rw-r--r--drivers/usb/phy/phy-stih407-usb2.c168
3 files changed, 179 insertions, 0 deletions
diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
index e253fa05be68..a7f4a5a70438 100644
--- a/drivers/usb/phy/Kconfig
+++ b/drivers/usb/phy/Kconfig
@@ -229,4 +229,13 @@ config USB_ULPI_VIEWPORT
Provides read/write operations to the ULPI phy register set for
controllers with a viewport register (e.g. Chipidea/ARC controllers).
+config PHY_STIH407_USB
+ tristate "STMicroelectronics picoPHY/MiPHY driver for STiH407 series"
+ depends on ARCH_STI
+ help
+ Enable this to support the USB transceiver that is part of
+ STMicroelectronics STiH407 SoC series. This will provide the picoPHY
+ that is used to manage USB2 ports and MiPHY HW associated to USB3
+ ports (refer to DWC3 layer).
+
endmenu
diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile
index 24a91332d4ad..b84eff4ee94b 100644
--- a/drivers/usb/phy/Makefile
+++ b/drivers/usb/phy/Makefile
@@ -29,3 +29,5 @@ obj-$(CONFIG_USB_RCAR_GEN2_PHY) += phy-rcar-gen2-usb.o
obj-$(CONFIG_USB_ULPI) += phy-ulpi.o
obj-$(CONFIG_USB_ULPI_VIEWPORT) += phy-ulpi-viewport.o
obj-$(CONFIG_KEYSTONE_USB_PHY) += phy-keystone.o
+obj-$(CONFIG_PHY_STIH407_USB) += phy-stih407-usb2.o
+
diff --git a/drivers/usb/phy/phy-stih407-usb2.c b/drivers/usb/phy/phy-stih407-usb2.c
new file mode 100644
index 000000000000..2cb7751ec93e
--- /dev/null
+++ b/drivers/usb/phy/phy-stih407-usb2.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2013 STMicroelectronics
+ *
+ * STMicroelectronics PHY driver for STiH407 USB2.
+ *
+ * Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
+ *
+ * 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.
+ *
+ */
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/clk.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <linux/mfd/syscon.h>
+#include <linux/usb/phy.h>
+
+#define phy_to_priv(x) container_of((x), struct stih407_usb2_picophy, phy)
+
+/* To program USB2 pico PHY control */
+#define STIH407_USB3_PORT2_PICOPHY 0xf4 /* 5061 */
+/* port #2 parameters overriding */
+#define STIH407_USB3_PORT2_PICOPHY_PARAM 0x100 /* 5064 */
+#define STIH407_USB3_PORT2_PICOPHY_PARAM_DEF 0x39a4dc
+
+/**
+ * struct stih407_usb_cfg - SoC specific PHY register mapping
+ * @syscfg: Offset in syscfg registers bank
+ * @syscfg_param: Offset in syscfg parameter registers bank
+ * @cfg_mask: Bits mask for PHY configuration
+ * @cfg: Static configuration value for PHY
+ * @param_mask: Bits mask for picoPHY parameter register
+ * @param: Static configuration value for picoPHY parameter register
+ */
+struct stih407_usb_cfg {
+ u32 syscfg;
+ u32 syscfg_param;
+ u32 cfg_mask;
+ u32 cfg;
+ u32 param_mask;
+ u32 param;
+};
+
+struct stih407_usb2_picophy {
+ struct usb_phy phy;
+ struct regmap *regmap;
+ const struct stih407_usb_cfg *cfg;
+ struct reset_control *rstc;
+};
+
+static struct stih407_usb_cfg stih407_usb2_picophy_cfg = {
+ .syscfg = STIH407_USB3_PORT2_PICOPHY,
+ .syscfg_param = STIH407_USB3_PORT2_PICOPHY_PARAM,
+ .cfg_mask = 0xff,
+ .cfg = 0x6,
+ .param_mask = 0xffffffff,
+ .param = STIH407_USB3_PORT2_PICOPHY_PARAM_DEF,
+};
+
+static int stih407_usb2_picophy_init(struct usb_phy *phy)
+{
+ struct stih407_usb2_picophy *phy_dev = phy_to_priv(phy);
+ int ret;
+
+ dev_info(phy->dev, "picoPHY init...\n");
+
+ /* USB2 pico PHY control */
+ ret = regmap_update_bits(phy_dev->regmap, phy_dev->cfg->syscfg,
+ phy_dev->cfg->cfg_mask, phy_dev->cfg->cfg);
+ if (ret)
+ return ret;
+
+ /* USB2 pico PHY port2 parameters override */
+ return regmap_update_bits(phy_dev->regmap, phy_dev->cfg->syscfg_param,
+ phy_dev->cfg->param_mask,
+ phy_dev->cfg->param);
+}
+
+static const struct of_device_id stih407_usb2_picophy_of_match[];
+
+static int stih407_usb2_picophy_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ const struct of_device_id *match;
+ struct stih407_usb2_picophy *phy_dev;
+ struct device *dev = &pdev->dev;
+ struct usb_phy *phy;
+
+ phy_dev = devm_kzalloc(dev, sizeof(*phy_dev), GFP_KERNEL);
+ if (!phy_dev)
+ return -ENOMEM;
+
+ match = of_match_device(stih407_usb2_picophy_of_match, &pdev->dev);
+ if (!match)
+ return -ENODEV;
+
+ phy_dev->cfg = match->data;
+
+ phy_dev->rstc = devm_reset_control_get(dev, NULL);
+ if (IS_ERR(phy_dev->rstc)) {
+ dev_err(dev, "failed to ctrl picoPHY reset\n");
+ return PTR_ERR(phy_dev->rstc);
+ }
+
+ dev_info(dev, "reset picoPHY\n");
+ reset_control_deassert(phy_dev->rstc);
+
+ phy_dev->regmap = syscon_regmap_lookup_by_phandle(np, "st,syscfg");
+ if (IS_ERR(phy_dev->regmap)) {
+ dev_err(dev, "No syscfg phandle specified\n");
+ return PTR_ERR(phy_dev->regmap);
+ }
+
+ phy = &phy_dev->phy;
+ phy->dev = dev;
+ phy->label = "STiH407 USB2 picoPHY";
+ phy->init = stih407_usb2_picophy_init;
+ phy->type = USB_PHY_TYPE_USB2;
+
+ usb_add_phy_dev(phy);
+
+ platform_set_drvdata(pdev, phy_dev);
+
+ dev_info(dev, "USB2 picoPHY probed\n");
+
+ return 0;
+}
+
+static int stih407_usb2_picophy_remove(struct platform_device *pdev)
+{
+ struct stih407_usb2_picophy *phy_dev = platform_get_drvdata(pdev);
+
+ reset_control_assert(phy_dev->rstc);
+
+ usb_remove_phy(&phy_dev->phy);
+
+ return 0;
+}
+
+static const struct of_device_id stih407_usb2_picophy_of_match[] = {
+ {.compatible = "st,stih407-usb2phy", .data = &stih407_usb2_picophy_cfg},
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, stih407_usb2_picophy_of_match);
+
+static struct platform_driver stih407_usb2_picophy_driver = {
+ .probe = stih407_usb2_picophy_probe,
+ .remove = stih407_usb2_picophy_remove,
+ .driver = {
+ .name = "stih407-usb2-phy",
+ .owner = THIS_MODULE,
+ .of_match_table = stih407_usb2_picophy_of_match,
+ }
+};
+
+module_platform_driver(stih407_usb2_picophy_driver);
+
+MODULE_AUTHOR("Giuseppe Cavallaro <peppe.cavallaro@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics USB2 picoPHY driver for STiH407 SoC");
+MODULE_LICENSE("GPL v2");