phy: rockchip-inno-usb2: Implement clock operations for usb2phy clock
This clock doesn't seem needed but appears in a phandle list used by ehci-generic.c to bulk enable it. The phandle list comes from linux, where it is needed for suspend/resume to work [1]. My tests give the same results with or without this patch, but Marek Vasut found it weird to declare an empty clk_ops [2]. So I adapted the code from linux 6.1-rc8 so that it hopefully works if it ever has some user. For now, without real use, it seems to at least not give any errors when called. Link: [1] https://lkml.kernel.org/lkml/1731551.Q6cHK6n5ZM@phil/T/ [2] https://patchwork.ozlabs.org/project/uboot/patch/Y5IWpjYLB4aXMy9o@localhost/ Cc: Simon Glass <sjg@chromium.org> Cc: Philipp Tomsich <philipp.tomsich@vrull.eu> Cc: Kever Yang <kever.yang@rock-chips.com> Cc: Lukasz Majewski <lukma@denx.de> Cc: Sean Anderson <seanga2@gmail.com> Cc: Marek Vasut <marex@denx.de> Cc: Christoph Fritz <chf.fritz@googlemail.com> Cc: Jagan Teki <jagan@amarulasolutions.com> Signed-off-by: Xavier Drudis Ferran <xdrudis@tinet.cat> Reviewed-by: Kever Yang <kever.yang@rock-chips.com> Reviewed-by: Jagan Teki <jagan@amarulasolutions.com> Tested-by: Jagan Teki <jagan@amarulasolutions.com> # rk3399, rk3328, rv1126
This commit is contained in:
parent
e81512ac30
commit
40359c9440
1 changed files with 78 additions and 2 deletions
|
@ -56,6 +56,7 @@ struct rockchip_usb2phy_port_cfg {
|
||||||
|
|
||||||
struct rockchip_usb2phy_cfg {
|
struct rockchip_usb2phy_cfg {
|
||||||
unsigned int reg;
|
unsigned int reg;
|
||||||
|
struct usb2phy_reg clkout_ctl;
|
||||||
const struct rockchip_usb2phy_port_cfg port_cfgs[USB2PHY_NUM_PORTS];
|
const struct rockchip_usb2phy_port_cfg port_cfgs[USB2PHY_NUM_PORTS];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -77,6 +78,18 @@ static inline int property_enable(void *reg_base,
|
||||||
return writel(val, reg_base + reg->offset);
|
return writel(val, reg_base + reg->offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool property_enabled(void *reg_base,
|
||||||
|
const struct usb2phy_reg *reg)
|
||||||
|
{
|
||||||
|
unsigned int tmp, orig;
|
||||||
|
unsigned int mask = GENMASK(reg->bitend, reg->bitstart);
|
||||||
|
|
||||||
|
orig = readl(reg_base + reg->offset);
|
||||||
|
|
||||||
|
tmp = (orig & mask) >> reg->bitstart;
|
||||||
|
return tmp != reg->disable;
|
||||||
|
}
|
||||||
|
|
||||||
static const
|
static const
|
||||||
struct rockchip_usb2phy_port_cfg *us2phy_get_port(struct phy *phy)
|
struct rockchip_usb2phy_port_cfg *us2phy_get_port(struct phy *phy)
|
||||||
{
|
{
|
||||||
|
@ -169,7 +182,63 @@ static struct phy_ops rockchip_usb2phy_ops = {
|
||||||
.of_xlate = rockchip_usb2phy_of_xlate,
|
.of_xlate = rockchip_usb2phy_of_xlate,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* round_rate() - Adjust a rate to the exact rate a clock can provide.
|
||||||
|
* @clk: The clock to manipulate.
|
||||||
|
* @rate: Desidered clock rate in Hz.
|
||||||
|
*
|
||||||
|
* Return: rounded rate in Hz, or -ve error code.
|
||||||
|
*/
|
||||||
|
ulong rockchip_usb2phy_clk_round_rate(struct clk *clk, ulong rate)
|
||||||
|
{
|
||||||
|
return 480000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* enable() - Enable a clock.
|
||||||
|
* @clk: The clock to manipulate.
|
||||||
|
*
|
||||||
|
* Return: zero on success, or -ve error code.
|
||||||
|
*/
|
||||||
|
int rockchip_usb2phy_clk_enable(struct clk *clk)
|
||||||
|
{
|
||||||
|
struct udevice *parent = dev_get_parent(clk->dev);
|
||||||
|
struct rockchip_usb2phy *priv = dev_get_priv(parent);
|
||||||
|
const struct rockchip_usb2phy_cfg *phy_cfg = priv->phy_cfg;
|
||||||
|
|
||||||
|
/* turn on 480m clk output if it is off */
|
||||||
|
if (!property_enabled(priv->reg_base, &phy_cfg->clkout_ctl)) {
|
||||||
|
property_enable(priv->reg_base, &phy_cfg->clkout_ctl, true);
|
||||||
|
|
||||||
|
/* waiting for the clk become stable */
|
||||||
|
usleep_range(1200, 1300);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* disable() - Disable a clock.
|
||||||
|
* @clk: The clock to manipulate.
|
||||||
|
*
|
||||||
|
* Return: zero on success, or -ve error code.
|
||||||
|
*/
|
||||||
|
int rockchip_usb2phy_clk_disable(struct clk *clk)
|
||||||
|
{
|
||||||
|
struct udevice *parent = dev_get_parent(clk->dev);
|
||||||
|
struct rockchip_usb2phy *priv = dev_get_priv(parent);
|
||||||
|
const struct rockchip_usb2phy_cfg *phy_cfg = priv->phy_cfg;
|
||||||
|
|
||||||
|
/* turn off 480m clk output */
|
||||||
|
property_enable(priv->reg_base, &phy_cfg->clkout_ctl, false);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static struct clk_ops rockchip_usb2phy_clk_ops = {
|
static struct clk_ops rockchip_usb2phy_clk_ops = {
|
||||||
|
.enable = rockchip_usb2phy_clk_enable,
|
||||||
|
.disable = rockchip_usb2phy_clk_disable,
|
||||||
|
.round_rate = rockchip_usb2phy_clk_round_rate
|
||||||
};
|
};
|
||||||
|
|
||||||
static int rockchip_usb2phy_probe(struct udevice *dev)
|
static int rockchip_usb2phy_probe(struct udevice *dev)
|
||||||
|
@ -255,8 +324,11 @@ static int rockchip_usb2phy_bind(struct udevice *dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
node = dev_ofnode(dev);
|
node = dev_ofnode(dev);
|
||||||
name = ofnode_get_name(node);
|
name = "clk_usbphy_480m";
|
||||||
dev_dbg(dev, "clk for node %s\n", name);
|
dev_read_string_index(dev, "clock-output-names", 0, &name);
|
||||||
|
|
||||||
|
dev_dbg(dev, "clk %s for node %s\n", name, ofnode_get_name(node));
|
||||||
|
|
||||||
ret = device_bind_driver_to_node(dev, "rockchip_usb2phy_clock",
|
ret = device_bind_driver_to_node(dev, "rockchip_usb2phy_clock",
|
||||||
name, node, &usb2phy_dev);
|
name, node, &usb2phy_dev);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
@ -276,6 +348,7 @@ bind_fail:
|
||||||
static const struct rockchip_usb2phy_cfg rk3399_usb2phy_cfgs[] = {
|
static const struct rockchip_usb2phy_cfg rk3399_usb2phy_cfgs[] = {
|
||||||
{
|
{
|
||||||
.reg = 0xe450,
|
.reg = 0xe450,
|
||||||
|
.clkout_ctl = { 0xe450, 4, 4, 1, 0 },
|
||||||
.port_cfgs = {
|
.port_cfgs = {
|
||||||
[USB2PHY_PORT_OTG] = {
|
[USB2PHY_PORT_OTG] = {
|
||||||
.phy_sus = { 0xe454, 1, 0, 2, 1 },
|
.phy_sus = { 0xe454, 1, 0, 2, 1 },
|
||||||
|
@ -297,6 +370,7 @@ static const struct rockchip_usb2phy_cfg rk3399_usb2phy_cfgs[] = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.reg = 0xe460,
|
.reg = 0xe460,
|
||||||
|
.clkout_ctl = { 0xe460, 4, 4, 1, 0 },
|
||||||
.port_cfgs = {
|
.port_cfgs = {
|
||||||
[USB2PHY_PORT_OTG] = {
|
[USB2PHY_PORT_OTG] = {
|
||||||
.phy_sus = { 0xe464, 1, 0, 2, 1 },
|
.phy_sus = { 0xe464, 1, 0, 2, 1 },
|
||||||
|
@ -322,6 +396,7 @@ static const struct rockchip_usb2phy_cfg rk3399_usb2phy_cfgs[] = {
|
||||||
static const struct rockchip_usb2phy_cfg rk3568_phy_cfgs[] = {
|
static const struct rockchip_usb2phy_cfg rk3568_phy_cfgs[] = {
|
||||||
{
|
{
|
||||||
.reg = 0xfe8a0000,
|
.reg = 0xfe8a0000,
|
||||||
|
.clkout_ctl = { 0x0008, 4, 4, 1, 0 },
|
||||||
.port_cfgs = {
|
.port_cfgs = {
|
||||||
[USB2PHY_PORT_OTG] = {
|
[USB2PHY_PORT_OTG] = {
|
||||||
.phy_sus = { 0x0000, 8, 0, 0x052, 0x1d1 },
|
.phy_sus = { 0x0000, 8, 0, 0x052, 0x1d1 },
|
||||||
|
@ -347,6 +422,7 @@ static const struct rockchip_usb2phy_cfg rk3568_phy_cfgs[] = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.reg = 0xfe8b0000,
|
.reg = 0xfe8b0000,
|
||||||
|
.clkout_ctl = { 0x0008, 4, 4, 1, 0 },
|
||||||
.port_cfgs = {
|
.port_cfgs = {
|
||||||
[USB2PHY_PORT_OTG] = {
|
[USB2PHY_PORT_OTG] = {
|
||||||
.phy_sus = { 0x0000, 8, 0, 0x1d2, 0x1d1 },
|
.phy_sus = { 0x0000, 8, 0, 0x1d2, 0x1d1 },
|
||||||
|
|
Loading…
Reference in a new issue