1 // SPDX-License-Identifier: GPL-2.0-only
3 * Intel Keem Bay USB PHY driver
4 * Copyright (C) 2020 Intel Corporation
7 #include <linux/bitfield.h>
8 #include <linux/bits.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>
17 /* USS (USB Subsystem) clock control registers */
18 #define USS_CPR_CLK_EN 0x00
19 #define USS_CPR_CLK_SET 0x04
20 #define USS_CPR_CLK_CLR 0x08
21 #define USS_CPR_RST_EN 0x10
22 #define USS_CPR_RST_SET 0x14
23 #define USS_CPR_RST_CLR 0x18
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)
35 /* USS APB slave registers */
36 #define USS_USB_CTRL_CFG0 0x10
37 #define VCC_RESET_N_MASK BIT(31)
39 #define USS_USB_PHY_CFG0 0x30
40 #define POR_MASK BIT(15)
41 #define PHY_RESET_MASK BIT(14)
42 #define PHY_REF_USE_PAD_MASK BIT(5)
44 #define USS_USB_PHY_CFG6 0x64
45 #define PHY0_SRAM_EXT_LD_DONE_MASK BIT(23)
47 #define USS_USB_PARALLEL_IF_CTRL 0xa0
48 #define USB_PHY_CR_PARA_SEL_MASK BIT(2)
50 #define USS_USB_TSET_SIGNALS_AND_GLOB 0xac
51 #define USB_PHY_CR_PARA_CLK_EN_MASK BIT(7)
53 #define USS_USB_STATUS_REG 0xb8
54 #define PHY0_SRAM_INIT_DONE_MASK BIT(3)
56 #define USS_USB_TIEOFFS_CONSTANTS_REG1 0xc0
57 #define IDDQ_ENABLE_MASK BIT(10)
59 struct keembay_usb_phy
{
61 struct regmap
*regmap_cpr
;
62 struct regmap
*regmap_slv
;
65 static const struct regmap_config keembay_regmap_config
= {
69 .max_register
= USS_USB_TIEOFFS_CONSTANTS_REG1
,
72 static int keembay_usb_clocks_on(struct keembay_usb_phy
*priv
)
76 ret
= regmap_update_bits(priv
->regmap_cpr
, USS_CPR_CLK_SET
,
77 USS_CPR_MASK
, USS_CPR_MASK
);
79 dev_err(priv
->dev
, "error clock set: %d\n", ret
);
83 ret
= regmap_update_bits(priv
->regmap_cpr
, USS_CPR_RST_SET
,
84 USS_CPR_MASK
, USS_CPR_MASK
);
86 dev_err(priv
->dev
, "error reset set: %d\n", ret
);
90 ret
= regmap_update_bits(priv
->regmap_slv
,
91 USS_USB_TIEOFFS_CONSTANTS_REG1
,
93 FIELD_PREP(IDDQ_ENABLE_MASK
, 0));
95 dev_err(priv
->dev
, "error iddq disable: %d\n", ret
);
99 /* Wait 30us to ensure all analog blocks are powered up. */
100 usleep_range(30, 60);
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));
106 dev_err(priv
->dev
, "error ref clock select: %d\n", ret
);
111 static int keembay_usb_core_off(struct keembay_usb_phy
*priv
)
115 ret
= regmap_update_bits(priv
->regmap_slv
, USS_USB_CTRL_CFG0
,
117 FIELD_PREP(VCC_RESET_N_MASK
, 0));
119 dev_err(priv
->dev
, "error core reset: %d\n", ret
);
124 static int keembay_usb_core_on(struct keembay_usb_phy
*priv
)
128 ret
= regmap_update_bits(priv
->regmap_slv
, USS_USB_CTRL_CFG0
,
130 FIELD_PREP(VCC_RESET_N_MASK
, 1));
132 dev_err(priv
->dev
, "error core on: %d\n", ret
);
137 static int keembay_usb_phys_on(struct keembay_usb_phy
*priv
)
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));
145 dev_err(priv
->dev
, "error phys on: %d\n", ret
);
150 static int keembay_usb_phy_init(struct phy
*phy
)
152 struct keembay_usb_phy
*priv
= phy_get_drvdata(phy
);
156 ret
= keembay_usb_core_off(priv
);
161 * According to Keem Bay datasheet, wait minimum 20us after clock
162 * enable before bringing PHYs out of reset.
164 usleep_range(20, 40);
166 ret
= keembay_usb_phys_on(priv
);
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));
175 dev_err(priv
->dev
, "error cr clock disable: %d\n", ret
);
180 * According to Keem Bay datasheet, wait 2us after disabling the
181 * clock into the USB 3.x parallel interface.
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));
190 dev_err(priv
->dev
, "error cr select: %d\n", ret
);
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));
199 dev_err(priv
->dev
, "error cr clock enable: %d\n", ret
);
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
);
207 dev_err(priv
->dev
, "SRAM init not done: %d\n", ret
);
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));
215 dev_err(priv
->dev
, "error SRAM init done set: %d\n", ret
);
220 * According to Keem Bay datasheet, wait 20us after setting the
221 * SRAM load done bit, before releasing the controller reset.
223 usleep_range(20, 40);
225 return keembay_usb_core_on(priv
);
228 static const struct phy_ops ops
= {
229 .init
= keembay_usb_phy_init
,
230 .owner
= THIS_MODULE
,
233 static int keembay_usb_phy_probe(struct platform_device
*pdev
)
235 struct device
*dev
= &pdev
->dev
;
236 struct keembay_usb_phy
*priv
;
237 struct phy
*generic_phy
;
238 struct phy_provider
*phy_provider
;
242 priv
= devm_kzalloc(dev
, sizeof(*priv
), GFP_KERNEL
);
246 base
= devm_platform_ioremap_resource_byname(pdev
, "cpr-apb-base");
248 return PTR_ERR(base
);
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
);
255 base
= devm_platform_ioremap_resource_byname(pdev
, "slv-apb-base");
257 return PTR_ERR(base
);
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
);
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");
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");
275 /* Setup USB subsystem clocks */
276 ret
= keembay_usb_clocks_on(priv
);
280 /* and turn on the DWC3 core, prior to DWC3 driver init. */
281 return keembay_usb_core_on(priv
);
284 static const struct of_device_id keembay_usb_phy_dt_ids
[] = {
285 { .compatible
= "intel,keembay-usb-phy" },
288 MODULE_DEVICE_TABLE(of
, keembay_usb_phy_dt_ids
);
290 static struct platform_driver keembay_usb_phy_driver
= {
291 .probe
= keembay_usb_phy_probe
,
293 .name
= "keembay-usb-phy",
294 .of_match_table
= keembay_usb_phy_dt_ids
,
297 module_platform_driver(keembay_usb_phy_driver
);
299 MODULE_AUTHOR("Wan Ahmad Zainie <wan.ahmad.zainie.wan.mohamad@intel.com>");
300 MODULE_DESCRIPTION("Intel Keem Bay USB PHY driver");
301 MODULE_LICENSE("GPL v2");