brintos

brintos / linux-shallow public Read only

0
0
Text · 7.5 KiB · c8b05f7 Raw
302 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Intel Keem Bay USB PHY driver4 * Copyright (C) 2020 Intel Corporation5 */6 7#include <linux/bitfield.h>8#include <linux/bits.h>9#include <linux/clk.h>10#include <linux/delay.h>11#include <linux/mod_devicetable.h>12#include <linux/module.h>13#include <linux/phy/phy.h>14#include <linux/platform_device.h>15#include <linux/regmap.h>16 17/* USS (USB Subsystem) clock control registers */18#define USS_CPR_CLK_EN		0x0019#define USS_CPR_CLK_SET		0x0420#define USS_CPR_CLK_CLR		0x0821#define USS_CPR_RST_EN		0x1022#define USS_CPR_RST_SET		0x1423#define USS_CPR_RST_CLR		0x1824 25/* USS clock/reset bit fields */26#define USS_CPR_PHY_TST		BIT(6)27#define USS_CPR_LOW_JIT		BIT(5)28#define USS_CPR_CORE		BIT(4)29#define USS_CPR_SUSPEND		BIT(3)30#define USS_CPR_ALT_REF		BIT(2)31#define USS_CPR_REF		BIT(1)32#define USS_CPR_SYS		BIT(0)33#define USS_CPR_MASK		GENMASK(6, 0)34 35/* USS APB slave registers */36#define USS_USB_CTRL_CFG0		0x1037#define  VCC_RESET_N_MASK		BIT(31)38 39#define USS_USB_PHY_CFG0		0x3040#define  POR_MASK			BIT(15)41#define  PHY_RESET_MASK			BIT(14)42#define  PHY_REF_USE_PAD_MASK		BIT(5)43 44#define USS_USB_PHY_CFG6		0x6445#define  PHY0_SRAM_EXT_LD_DONE_MASK	BIT(23)46 47#define USS_USB_PARALLEL_IF_CTRL	0xa048#define  USB_PHY_CR_PARA_SEL_MASK	BIT(2)49 50#define USS_USB_TSET_SIGNALS_AND_GLOB	0xac51#define  USB_PHY_CR_PARA_CLK_EN_MASK	BIT(7)52 53#define USS_USB_STATUS_REG		0xb854#define  PHY0_SRAM_INIT_DONE_MASK	BIT(3)55 56#define USS_USB_TIEOFFS_CONSTANTS_REG1	0xc057#define  IDDQ_ENABLE_MASK		BIT(10)58 59struct keembay_usb_phy {60	struct device *dev;61	struct regmap *regmap_cpr;62	struct regmap *regmap_slv;63};64 65static const struct regmap_config keembay_regmap_config = {66	.reg_bits = 32,67	.val_bits = 32,68	.reg_stride = 4,69	.max_register = USS_USB_TIEOFFS_CONSTANTS_REG1,70};71 72static int keembay_usb_clocks_on(struct keembay_usb_phy *priv)73{74	int ret;75 76	ret = regmap_update_bits(priv->regmap_cpr, USS_CPR_CLK_SET,77				 USS_CPR_MASK, USS_CPR_MASK);78	if (ret) {79		dev_err(priv->dev, "error clock set: %d\n", ret);80		return ret;81	}82 83	ret = regmap_update_bits(priv->regmap_cpr, USS_CPR_RST_SET,84				 USS_CPR_MASK, USS_CPR_MASK);85	if (ret) {86		dev_err(priv->dev, "error reset set: %d\n", ret);87		return ret;88	}89 90	ret = regmap_update_bits(priv->regmap_slv,91				 USS_USB_TIEOFFS_CONSTANTS_REG1,92				 IDDQ_ENABLE_MASK,93				 FIELD_PREP(IDDQ_ENABLE_MASK, 0));94	if (ret) {95		dev_err(priv->dev, "error iddq disable: %d\n", ret);96		return ret;97	}98 99	/* Wait 30us to ensure all analog blocks are powered up. */100	usleep_range(30, 60);101 102	ret = regmap_update_bits(priv->regmap_slv, USS_USB_PHY_CFG0,103				 PHY_REF_USE_PAD_MASK,104				 FIELD_PREP(PHY_REF_USE_PAD_MASK, 1));105	if (ret)106		dev_err(priv->dev, "error ref clock select: %d\n", ret);107 108	return ret;109}110 111static int keembay_usb_core_off(struct keembay_usb_phy *priv)112{113	int ret;114 115	ret = regmap_update_bits(priv->regmap_slv, USS_USB_CTRL_CFG0,116				 VCC_RESET_N_MASK,117				 FIELD_PREP(VCC_RESET_N_MASK, 0));118	if (ret)119		dev_err(priv->dev, "error core reset: %d\n", ret);120 121	return ret;122}123 124static int keembay_usb_core_on(struct keembay_usb_phy *priv)125{126	int ret;127 128	ret = regmap_update_bits(priv->regmap_slv, USS_USB_CTRL_CFG0,129				 VCC_RESET_N_MASK,130				 FIELD_PREP(VCC_RESET_N_MASK, 1));131	if (ret)132		dev_err(priv->dev, "error core on: %d\n", ret);133 134	return ret;135}136 137static int keembay_usb_phys_on(struct keembay_usb_phy *priv)138{139	int ret;140 141	ret = regmap_update_bits(priv->regmap_slv, USS_USB_PHY_CFG0,142				 POR_MASK | PHY_RESET_MASK,143				 FIELD_PREP(POR_MASK | PHY_RESET_MASK, 0));144	if (ret)145		dev_err(priv->dev, "error phys on: %d\n", ret);146 147	return ret;148}149 150static int keembay_usb_phy_init(struct phy *phy)151{152	struct keembay_usb_phy *priv = phy_get_drvdata(phy);153	u32 val;154	int ret;155 156	ret = keembay_usb_core_off(priv);157	if (ret)158		return ret;159 160	/*161	 * According to Keem Bay datasheet, wait minimum 20us after clock162	 * enable before bringing PHYs out of reset.163	 */164	usleep_range(20, 40);165 166	ret = keembay_usb_phys_on(priv);167	if (ret)168		return ret;169 170	ret = regmap_update_bits(priv->regmap_slv,171				 USS_USB_TSET_SIGNALS_AND_GLOB,172				 USB_PHY_CR_PARA_CLK_EN_MASK,173				 FIELD_PREP(USB_PHY_CR_PARA_CLK_EN_MASK, 0));174	if (ret) {175		dev_err(priv->dev, "error cr clock disable: %d\n", ret);176		return ret;177	}178 179	/*180	 * According to Keem Bay datasheet, wait 2us after disabling the181	 * clock into the USB 3.x parallel interface.182	 */183	udelay(2);184 185	ret = regmap_update_bits(priv->regmap_slv,186				 USS_USB_PARALLEL_IF_CTRL,187				 USB_PHY_CR_PARA_SEL_MASK,188				 FIELD_PREP(USB_PHY_CR_PARA_SEL_MASK, 1));189	if (ret) {190		dev_err(priv->dev, "error cr select: %d\n", ret);191		return ret;192	}193 194	ret = regmap_update_bits(priv->regmap_slv,195				 USS_USB_TSET_SIGNALS_AND_GLOB,196				 USB_PHY_CR_PARA_CLK_EN_MASK,197				 FIELD_PREP(USB_PHY_CR_PARA_CLK_EN_MASK, 1));198	if (ret) {199		dev_err(priv->dev, "error cr clock enable: %d\n", ret);200		return ret;201	}202 203	ret = regmap_read_poll_timeout(priv->regmap_slv, USS_USB_STATUS_REG,204				       val, val & PHY0_SRAM_INIT_DONE_MASK,205				       USEC_PER_MSEC, 10 * USEC_PER_MSEC);206	if (ret) {207		dev_err(priv->dev, "SRAM init not done: %d\n", ret);208		return ret;209	}210 211	ret = regmap_update_bits(priv->regmap_slv, USS_USB_PHY_CFG6,212				 PHY0_SRAM_EXT_LD_DONE_MASK,213				 FIELD_PREP(PHY0_SRAM_EXT_LD_DONE_MASK, 1));214	if (ret) {215		dev_err(priv->dev, "error SRAM init done set: %d\n", ret);216		return ret;217	}218 219	/*220	 * According to Keem Bay datasheet, wait 20us after setting the221	 * SRAM load done bit, before releasing the controller reset.222	 */223	usleep_range(20, 40);224 225	return keembay_usb_core_on(priv);226}227 228static const struct phy_ops ops = {229	.init		= keembay_usb_phy_init,230	.owner		= THIS_MODULE,231};232 233static int keembay_usb_phy_probe(struct platform_device *pdev)234{235	struct device *dev = &pdev->dev;236	struct keembay_usb_phy *priv;237	struct phy *generic_phy;238	struct phy_provider *phy_provider;239	void __iomem *base;240	int ret;241 242	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);243	if (!priv)244		return -ENOMEM;245 246	base = devm_platform_ioremap_resource_byname(pdev, "cpr-apb-base");247	if (IS_ERR(base))248		return PTR_ERR(base);249 250	priv->regmap_cpr = devm_regmap_init_mmio(dev, base,251						 &keembay_regmap_config);252	if (IS_ERR(priv->regmap_cpr))253		return PTR_ERR(priv->regmap_cpr);254 255	base = devm_platform_ioremap_resource_byname(pdev, "slv-apb-base");256	if (IS_ERR(base))257		return PTR_ERR(base);258 259	priv->regmap_slv = devm_regmap_init_mmio(dev, base,260						 &keembay_regmap_config);261	if (IS_ERR(priv->regmap_slv))262		return PTR_ERR(priv->regmap_slv);263 264	generic_phy = devm_phy_create(dev, dev->of_node, &ops);265	if (IS_ERR(generic_phy))266		return dev_err_probe(dev, PTR_ERR(generic_phy),267				     "failed to create PHY\n");268 269	phy_set_drvdata(generic_phy, priv);270	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);271	if (IS_ERR(phy_provider))272		return dev_err_probe(dev, PTR_ERR(phy_provider),273				     "failed to register phy provider\n");274 275	/* Setup USB subsystem clocks */276	ret = keembay_usb_clocks_on(priv);277	if (ret)278		return ret;279 280	/* and turn on the DWC3 core, prior to DWC3 driver init. */281	return keembay_usb_core_on(priv);282}283 284static const struct of_device_id keembay_usb_phy_dt_ids[] = {285	{ .compatible = "intel,keembay-usb-phy" },286	{}287};288MODULE_DEVICE_TABLE(of, keembay_usb_phy_dt_ids);289 290static struct platform_driver keembay_usb_phy_driver = {291	.probe		= keembay_usb_phy_probe,292	.driver		= {293		.name	= "keembay-usb-phy",294		.of_match_table = keembay_usb_phy_dt_ids,295	},296};297module_platform_driver(keembay_usb_phy_driver);298 299MODULE_AUTHOR("Wan Ahmad Zainie <wan.ahmad.zainie.wan.mohamad@intel.com>");300MODULE_DESCRIPTION("Intel Keem Bay USB PHY driver");301MODULE_LICENSE("GPL v2");302