Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.2.
  1/*
  2 * Copyright (c) 2015 Linaro Ltd.
  3 * Copyright (c) 2015 Hisilicon Limited.
  4 *
  5 * This program is free software; you can redistribute it and/or modify
  6 * it under the terms of the GNU General Public License as published by
  7 * the Free Software Foundation; either version 2 of the License, or
  8 * (at your option) any later version.
  9 */
 10
 11#include <linux/mfd/syscon.h>
 12#include <linux/module.h>
 13#include <linux/platform_device.h>
 14#include <linux/phy/phy.h>
 15#include <linux/regmap.h>
 16
 17#define SC_PERIPH_CTRL4			0x00c
 18
 19#define CTRL4_PICO_SIDDQ		BIT(6)
 20#define CTRL4_PICO_OGDISABLE		BIT(8)
 21#define CTRL4_PICO_VBUSVLDEXT		BIT(10)
 22#define CTRL4_PICO_VBUSVLDEXTSEL	BIT(11)
 23#define CTRL4_OTG_PHY_SEL		BIT(21)
 24
 25#define SC_PERIPH_CTRL5			0x010
 26
 27#define CTRL5_USBOTG_RES_SEL		BIT(3)
 28#define CTRL5_PICOPHY_ACAENB		BIT(4)
 29#define CTRL5_PICOPHY_BC_MODE		BIT(5)
 30#define CTRL5_PICOPHY_CHRGSEL		BIT(6)
 31#define CTRL5_PICOPHY_VDATSRCEND	BIT(7)
 32#define CTRL5_PICOPHY_VDATDETENB	BIT(8)
 33#define CTRL5_PICOPHY_DCDENB		BIT(9)
 34#define CTRL5_PICOPHY_IDDIG		BIT(10)
 35
 36#define SC_PERIPH_CTRL8			0x018
 37#define SC_PERIPH_RSTEN0		0x300
 38#define SC_PERIPH_RSTDIS0		0x304
 39
 40#define RST0_USBOTG_BUS			BIT(4)
 41#define RST0_POR_PICOPHY		BIT(5)
 42#define RST0_USBOTG			BIT(6)
 43#define RST0_USBOTG_32K			BIT(7)
 44
 45#define EYE_PATTERN_PARA		0x7053348c
 46
 47struct hi6220_priv {
 48	struct regmap *reg;
 49	struct device *dev;
 50};
 51
 52static void hi6220_phy_init(struct hi6220_priv *priv)
 53{
 54	struct regmap *reg = priv->reg;
 55	u32 val, mask;
 56
 57	val = RST0_USBOTG_BUS | RST0_POR_PICOPHY |
 58	      RST0_USBOTG | RST0_USBOTG_32K;
 59	mask = val;
 60	regmap_update_bits(reg, SC_PERIPH_RSTEN0, mask, val);
 61	regmap_update_bits(reg, SC_PERIPH_RSTDIS0, mask, val);
 62}
 63
 64static int hi6220_phy_setup(struct hi6220_priv *priv, bool on)
 65{
 66	struct regmap *reg = priv->reg;
 67	u32 val, mask;
 68	int ret;
 69
 70	if (on) {
 71		val = CTRL5_USBOTG_RES_SEL | CTRL5_PICOPHY_ACAENB;
 72		mask = val | CTRL5_PICOPHY_BC_MODE;
 73		ret = regmap_update_bits(reg, SC_PERIPH_CTRL5, mask, val);
 74		if (ret)
 75			goto out;
 76
 77		val =  CTRL4_PICO_VBUSVLDEXT | CTRL4_PICO_VBUSVLDEXTSEL |
 78		       CTRL4_OTG_PHY_SEL;
 79		mask = val | CTRL4_PICO_SIDDQ | CTRL4_PICO_OGDISABLE;
 80		ret = regmap_update_bits(reg, SC_PERIPH_CTRL4, mask, val);
 81		if (ret)
 82			goto out;
 83
 84		ret = regmap_write(reg, SC_PERIPH_CTRL8, EYE_PATTERN_PARA);
 85		if (ret)
 86			goto out;
 87	} else {
 88		val = CTRL4_PICO_SIDDQ;
 89		mask = val;
 90		ret = regmap_update_bits(reg, SC_PERIPH_CTRL4, mask, val);
 91		if (ret)
 92			goto out;
 93	}
 94
 95	return 0;
 96out:
 97	dev_err(priv->dev, "failed to setup phy ret: %d\n", ret);
 98	return ret;
 99}
100
101static int hi6220_phy_start(struct phy *phy)
102{
103	struct hi6220_priv *priv = phy_get_drvdata(phy);
104
105	return hi6220_phy_setup(priv, true);
106}
107
108static int hi6220_phy_exit(struct phy *phy)
109{
110	struct hi6220_priv *priv = phy_get_drvdata(phy);
111
112	return hi6220_phy_setup(priv, false);
113}
114
115static struct phy_ops hi6220_phy_ops = {
116	.init		= hi6220_phy_start,
117	.exit		= hi6220_phy_exit,
118	.owner		= THIS_MODULE,
119};
120
121static int hi6220_phy_probe(struct platform_device *pdev)
122{
123	struct phy_provider *phy_provider;
124	struct device *dev = &pdev->dev;
125	struct phy *phy;
126	struct hi6220_priv *priv;
127
128	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
129	if (!priv)
130		return -ENOMEM;
131
132	priv->dev = dev;
133	priv->reg = syscon_regmap_lookup_by_phandle(dev->of_node,
134					"hisilicon,peripheral-syscon");
135	if (IS_ERR(priv->reg)) {
136		dev_err(dev, "no hisilicon,peripheral-syscon\n");
137		return PTR_ERR(priv->reg);
138	}
139
140	hi6220_phy_init(priv);
141
142	phy = devm_phy_create(dev, NULL, &hi6220_phy_ops);
143	if (IS_ERR(phy))
144		return PTR_ERR(phy);
145
146	phy_set_drvdata(phy, priv);
147	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
148	return PTR_ERR_OR_ZERO(phy_provider);
149}
150
151static const struct of_device_id hi6220_phy_of_match[] = {
152	{.compatible = "hisilicon,hi6220-usb-phy",},
153	{ },
154};
155MODULE_DEVICE_TABLE(of, hi6220_phy_of_match);
156
157static struct platform_driver hi6220_phy_driver = {
158	.probe	= hi6220_phy_probe,
159	.driver = {
160		.name	= "hi6220-usb-phy",
161		.of_match_table	= hi6220_phy_of_match,
162	}
163};
164module_platform_driver(hi6220_phy_driver);
165
166MODULE_DESCRIPTION("HISILICON HI6220 USB PHY driver");
167MODULE_ALIAS("platform:hi6220-usb-phy");
168MODULE_LICENSE("GPL");