c2a96b7f18
Here is the big set of driver core changes for 6.11-rc1. Lots of stuff in here, with not a huge diffstat, but apis are evolving which required lots of files to be touched. Highlights of the changes in here are: - platform remove callback api final fixups (Uwe took many releases to get here, finally!) - Rust bindings for basic firmware apis and initial driver-core interactions. It's not all that useful for a "write a whole driver in rust" type of thing, but the firmware bindings do help out the phy rust drivers, and the driver core bindings give a solid base on which others can start their work. There is still a long way to go here before we have a multitude of rust drivers being added, but it's a great first step. - driver core const api changes. This reached across all bus types, and there are some fix-ups for some not-common bus types that linux-next and 0-day testing shook out. This work is being done to help make the rust bindings more safe, as well as the C code, moving toward the end-goal of allowing us to put driver structures into read-only memory. We aren't there yet, but are getting closer. - minor devres cleanups and fixes found by code inspection - arch_topology minor changes - other minor driver core cleanups All of these have been in linux-next for a very long time with no reported problems. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCZqH+aQ8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ymoOQCfVBdLcBjEDAGh3L8qHRGMPy4rV2EAoL/r+zKm cJEYtJpGtWX6aAtugm9E =ZyJV -----END PGP SIGNATURE----- Merge tag 'driver-core-6.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core Pull driver core updates from Greg KH: "Here is the big set of driver core changes for 6.11-rc1. Lots of stuff in here, with not a huge diffstat, but apis are evolving which required lots of files to be touched. Highlights of the changes in here are: - platform remove callback api final fixups (Uwe took many releases to get here, finally!) - Rust bindings for basic firmware apis and initial driver-core interactions. It's not all that useful for a "write a whole driver in rust" type of thing, but the firmware bindings do help out the phy rust drivers, and the driver core bindings give a solid base on which others can start their work. There is still a long way to go here before we have a multitude of rust drivers being added, but it's a great first step. - driver core const api changes. This reached across all bus types, and there are some fix-ups for some not-common bus types that linux-next and 0-day testing shook out. This work is being done to help make the rust bindings more safe, as well as the C code, moving toward the end-goal of allowing us to put driver structures into read-only memory. We aren't there yet, but are getting closer. - minor devres cleanups and fixes found by code inspection - arch_topology minor changes - other minor driver core cleanups All of these have been in linux-next for a very long time with no reported problems" * tag 'driver-core-6.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core: (55 commits) ARM: sa1100: make match function take a const pointer sysfs/cpu: Make crash_hotplug attribute world-readable dio: Have dio_bus_match() callback take a const * zorro: make match function take a const pointer driver core: module: make module_[add|remove]_driver take a const * driver core: make driver_find_device() take a const * driver core: make driver_[create|remove]_file take a const * firmware_loader: fix soundness issue in `request_internal` firmware_loader: annotate doctests as `no_run` devres: Correct code style for functions that return a pointer type devres: Initialize an uninitialized struct member devres: Fix memory leakage caused by driver API devm_free_percpu() devres: Fix devm_krealloc() wasting memory driver core: platform: Switch to use kmemdup_array() driver core: have match() callback in struct bus_type take a const * MAINTAINERS: add Rust device abstractions to DRIVER CORE device: rust: improve safety comments MAINTAINERS: add Danilo as FIRMWARE LOADER maintainer MAINTAINERS: add Rust FW abstractions to FIRMWARE LOADER firmware: rust: improve safety comments ...
218 lines
5.5 KiB
C
218 lines
5.5 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Renesas RZ/G2L USBPHY control driver
|
|
*
|
|
* Copyright (C) 2021 Renesas Electronics Corporation
|
|
*/
|
|
|
|
#include <linux/io.h>
|
|
#include <linux/module.h>
|
|
#include <linux/of.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/pm_runtime.h>
|
|
#include <linux/regmap.h>
|
|
#include <linux/reset.h>
|
|
#include <linux/reset-controller.h>
|
|
|
|
#define RESET 0x000
|
|
#define VBENCTL 0x03c
|
|
|
|
#define RESET_SEL_PLLRESET BIT(12)
|
|
#define RESET_PLLRESET BIT(8)
|
|
|
|
#define RESET_SEL_P2RESET BIT(5)
|
|
#define RESET_SEL_P1RESET BIT(4)
|
|
#define RESET_PHYRST_2 BIT(1)
|
|
#define RESET_PHYRST_1 BIT(0)
|
|
|
|
#define PHY_RESET_PORT2 (RESET_SEL_P2RESET | RESET_PHYRST_2)
|
|
#define PHY_RESET_PORT1 (RESET_SEL_P1RESET | RESET_PHYRST_1)
|
|
|
|
#define NUM_PORTS 2
|
|
|
|
struct rzg2l_usbphy_ctrl_priv {
|
|
struct reset_controller_dev rcdev;
|
|
struct reset_control *rstc;
|
|
void __iomem *base;
|
|
struct platform_device *vdev;
|
|
|
|
spinlock_t lock;
|
|
};
|
|
|
|
#define rcdev_to_priv(x) container_of(x, struct rzg2l_usbphy_ctrl_priv, rcdev)
|
|
|
|
static int rzg2l_usbphy_ctrl_assert(struct reset_controller_dev *rcdev,
|
|
unsigned long id)
|
|
{
|
|
struct rzg2l_usbphy_ctrl_priv *priv = rcdev_to_priv(rcdev);
|
|
u32 port_mask = PHY_RESET_PORT1 | PHY_RESET_PORT2;
|
|
void __iomem *base = priv->base;
|
|
unsigned long flags;
|
|
u32 val;
|
|
|
|
spin_lock_irqsave(&priv->lock, flags);
|
|
val = readl(base + RESET);
|
|
val |= id ? PHY_RESET_PORT2 : PHY_RESET_PORT1;
|
|
if (port_mask == (val & port_mask))
|
|
val |= RESET_PLLRESET;
|
|
writel(val, base + RESET);
|
|
spin_unlock_irqrestore(&priv->lock, flags);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int rzg2l_usbphy_ctrl_deassert(struct reset_controller_dev *rcdev,
|
|
unsigned long id)
|
|
{
|
|
struct rzg2l_usbphy_ctrl_priv *priv = rcdev_to_priv(rcdev);
|
|
void __iomem *base = priv->base;
|
|
unsigned long flags;
|
|
u32 val;
|
|
|
|
spin_lock_irqsave(&priv->lock, flags);
|
|
val = readl(base + RESET);
|
|
|
|
val |= RESET_SEL_PLLRESET;
|
|
val &= ~(RESET_PLLRESET | (id ? PHY_RESET_PORT2 : PHY_RESET_PORT1));
|
|
writel(val, base + RESET);
|
|
spin_unlock_irqrestore(&priv->lock, flags);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int rzg2l_usbphy_ctrl_status(struct reset_controller_dev *rcdev,
|
|
unsigned long id)
|
|
{
|
|
struct rzg2l_usbphy_ctrl_priv *priv = rcdev_to_priv(rcdev);
|
|
u32 port_mask;
|
|
|
|
port_mask = id ? PHY_RESET_PORT2 : PHY_RESET_PORT1;
|
|
|
|
return !!(readl(priv->base + RESET) & port_mask);
|
|
}
|
|
|
|
static const struct of_device_id rzg2l_usbphy_ctrl_match_table[] = {
|
|
{ .compatible = "renesas,rzg2l-usbphy-ctrl" },
|
|
{ /* Sentinel */ }
|
|
};
|
|
MODULE_DEVICE_TABLE(of, rzg2l_usbphy_ctrl_match_table);
|
|
|
|
static const struct reset_control_ops rzg2l_usbphy_ctrl_reset_ops = {
|
|
.assert = rzg2l_usbphy_ctrl_assert,
|
|
.deassert = rzg2l_usbphy_ctrl_deassert,
|
|
.status = rzg2l_usbphy_ctrl_status,
|
|
};
|
|
|
|
static const struct regmap_config rzg2l_usb_regconf = {
|
|
.reg_bits = 32,
|
|
.val_bits = 32,
|
|
.reg_stride = 4,
|
|
.max_register = 1,
|
|
};
|
|
|
|
static int rzg2l_usbphy_ctrl_probe(struct platform_device *pdev)
|
|
{
|
|
struct device *dev = &pdev->dev;
|
|
struct rzg2l_usbphy_ctrl_priv *priv;
|
|
struct platform_device *vdev;
|
|
struct regmap *regmap;
|
|
unsigned long flags;
|
|
int error;
|
|
u32 val;
|
|
|
|
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
|
if (!priv)
|
|
return -ENOMEM;
|
|
|
|
priv->base = devm_platform_ioremap_resource(pdev, 0);
|
|
if (IS_ERR(priv->base))
|
|
return PTR_ERR(priv->base);
|
|
|
|
regmap = devm_regmap_init_mmio(dev, priv->base + VBENCTL, &rzg2l_usb_regconf);
|
|
if (IS_ERR(regmap))
|
|
return PTR_ERR(regmap);
|
|
|
|
priv->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
|
|
if (IS_ERR(priv->rstc))
|
|
return dev_err_probe(dev, PTR_ERR(priv->rstc),
|
|
"failed to get reset\n");
|
|
|
|
error = reset_control_deassert(priv->rstc);
|
|
if (error)
|
|
return error;
|
|
|
|
spin_lock_init(&priv->lock);
|
|
dev_set_drvdata(dev, priv);
|
|
|
|
pm_runtime_enable(&pdev->dev);
|
|
error = pm_runtime_resume_and_get(&pdev->dev);
|
|
if (error < 0) {
|
|
dev_err_probe(&pdev->dev, error, "pm_runtime_resume_and_get failed");
|
|
goto err_pm_disable_reset_deassert;
|
|
}
|
|
|
|
/* put pll and phy into reset state */
|
|
spin_lock_irqsave(&priv->lock, flags);
|
|
val = readl(priv->base + RESET);
|
|
val |= RESET_SEL_PLLRESET | RESET_PLLRESET | PHY_RESET_PORT2 | PHY_RESET_PORT1;
|
|
writel(val, priv->base + RESET);
|
|
spin_unlock_irqrestore(&priv->lock, flags);
|
|
|
|
priv->rcdev.ops = &rzg2l_usbphy_ctrl_reset_ops;
|
|
priv->rcdev.of_reset_n_cells = 1;
|
|
priv->rcdev.nr_resets = NUM_PORTS;
|
|
priv->rcdev.of_node = dev->of_node;
|
|
priv->rcdev.dev = dev;
|
|
|
|
error = devm_reset_controller_register(dev, &priv->rcdev);
|
|
if (error)
|
|
goto err_pm_runtime_put;
|
|
|
|
vdev = platform_device_alloc("rzg2l-usb-vbus-regulator", pdev->id);
|
|
if (!vdev) {
|
|
error = -ENOMEM;
|
|
goto err_pm_runtime_put;
|
|
}
|
|
vdev->dev.parent = dev;
|
|
priv->vdev = vdev;
|
|
|
|
error = platform_device_add(vdev);
|
|
if (error)
|
|
goto err_device_put;
|
|
|
|
return 0;
|
|
|
|
err_device_put:
|
|
platform_device_put(vdev);
|
|
err_pm_runtime_put:
|
|
pm_runtime_put(&pdev->dev);
|
|
err_pm_disable_reset_deassert:
|
|
pm_runtime_disable(&pdev->dev);
|
|
reset_control_assert(priv->rstc);
|
|
return error;
|
|
}
|
|
|
|
static void rzg2l_usbphy_ctrl_remove(struct platform_device *pdev)
|
|
{
|
|
struct rzg2l_usbphy_ctrl_priv *priv = dev_get_drvdata(&pdev->dev);
|
|
|
|
platform_device_unregister(priv->vdev);
|
|
pm_runtime_put(&pdev->dev);
|
|
pm_runtime_disable(&pdev->dev);
|
|
reset_control_assert(priv->rstc);
|
|
}
|
|
|
|
static struct platform_driver rzg2l_usbphy_ctrl_driver = {
|
|
.driver = {
|
|
.name = "rzg2l_usbphy_ctrl",
|
|
.of_match_table = rzg2l_usbphy_ctrl_match_table,
|
|
},
|
|
.probe = rzg2l_usbphy_ctrl_probe,
|
|
.remove_new = rzg2l_usbphy_ctrl_remove,
|
|
};
|
|
module_platform_driver(rzg2l_usbphy_ctrl_driver);
|
|
|
|
MODULE_LICENSE("GPL v2");
|
|
MODULE_DESCRIPTION("Renesas RZ/G2L USBPHY Control");
|
|
MODULE_AUTHOR("biju.das.jz@bp.renesas.com>");
|