2014-06-05 12:53:30

by Heikki Krogerus

[permalink] [raw]
Subject: [PATCHv2 0/6] phy: simplified phy lookup

Hi,

So the idea with these is that they should help to make it possible to
request phys without caring about how they are mapped to the
consumers, meaning, was is the mapping done in DT, ACPI, etc. Mapping
phys to consumers can be now done with lookups similarly how clocks
can be mapped in clkdev.c.

Vivek needs to handle the phys of dwc3 also in xhci driver on
Exynos5420 SoC, so I'm resending these now.


Heikki Krogerus (6):
phy: safer to_phy() macro
phy: improved lookup method
arm: omap3: twl: use the new lookup method with usb phy
phy: remove the old lookup method
base: platform: name the device already during allocation
usb: dwc3: host: convey the PHYs to xhci

Documentation/phy.txt | 66 +++++----------
arch/arm/mach-omap2/twl-common.c | 18 ++---
drivers/base/platform.c | 77 +++++++++++-------
drivers/phy/phy-bcm-kona-usb2.c | 2 +-
drivers/phy/phy-core.c | 156 +++++++++++++++++++++++++++++-------
drivers/phy/phy-exynos-dp-video.c | 2 +-
drivers/phy/phy-exynos-mipi-video.c | 2 +-
drivers/phy/phy-exynos5-usbdrd.c | 3 +-
drivers/phy/phy-exynos5250-sata.c | 2 +-
drivers/phy/phy-mvebu-sata.c | 2 +-
drivers/phy/phy-omap-usb2.c | 2 +-
drivers/phy/phy-samsung-usb2.c | 2 +-
drivers/phy/phy-sun4i-usb.c | 2 +-
drivers/phy/phy-ti-pipe3.c | 2 +-
drivers/phy/phy-twl4030-usb.c | 4 +-
drivers/phy/phy-xgene.c | 2 +-
drivers/usb/dwc3/host.c | 22 +++--
include/linux/phy/phy.h | 60 +++++++-------
18 files changed, 259 insertions(+), 167 deletions(-)

--
2.0.0.rc4


2014-06-05 12:53:35

by Heikki Krogerus

[permalink] [raw]
Subject: [PATCHv2 6/6] usb: dwc3: host: convey the PHYs to xhci

On some platforms a PHY may need to be handled also in the
host controller driver. Exynos5420 SoC requires some "PHY
tuning" based on the USB speed. This patch delivers dwc3's
PHYs to the xhci platform device when it's created.

Signed-off-by: Heikki Krogerus <[email protected]>
Cc: Felipe Balbi <[email protected]>
---
drivers/usb/dwc3/host.c | 22 ++++++++++++++++------
1 file changed, 16 insertions(+), 6 deletions(-)

diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c
index 32db328..8387564 100644
--- a/drivers/usb/dwc3/host.c
+++ b/drivers/usb/dwc3/host.c
@@ -27,8 +27,7 @@ int dwc3_host_init(struct dwc3 *dwc)
xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO);
if (!xhci) {
dev_err(dwc->dev, "couldn't allocate xHCI device\n");
- ret = -ENOMEM;
- goto err0;
+ return -ENOMEM;
}

dma_set_coherent_mask(&xhci->dev, dwc->dev->coherent_dma_mask);
@@ -46,22 +45,33 @@ int dwc3_host_init(struct dwc3 *dwc)
goto err1;
}

+ phy_create_lookup(dwc->usb2_generic_phy, "usb2-phy",
+ dev_name(&xhci->dev));
+ phy_create_lookup(dwc->usb3_generic_phy, "usb3-phy",
+ dev_name(&xhci->dev));
+
ret = platform_device_add(xhci);
if (ret) {
dev_err(dwc->dev, "failed to register xHCI device\n");
- goto err1;
+ goto err2;
}

return 0;
-
+err2:
+ phy_remove_lookup(dwc->usb2_generic_phy, "usb2-phy",
+ dev_name(&xhci->dev));
+ phy_remove_lookup(dwc->usb3_generic_phy, "usb3-phy",
+ dev_name(&xhci->dev));
err1:
platform_device_put(xhci);
-
-err0:
return ret;
}

void dwc3_host_exit(struct dwc3 *dwc)
{
+ phy_remove_lookup(dwc->usb2_generic_phy, "usb2-phy",
+ dev_name(&dwc->xhci->dev));
+ phy_remove_lookup(dwc->usb3_generic_phy, "usb3-phy",
+ dev_name(&dwc->xhci->dev));
platform_device_unregister(dwc->xhci);
}
--
2.0.0.rc4

2014-06-05 12:53:52

by Heikki Krogerus

[permalink] [raw]
Subject: [PATCHv2 5/6] base: platform: name the device already during allocation

This allows resources such as GPIOs and clocks, which can be
matched based on the device name when requested, to be
assigned even when PLATFORM_DEVID_AUTO is used.

Signed-off-by: Heikki Krogerus <[email protected]>
Cc: Greg Kroah-Hartman <[email protected]>
---
drivers/base/platform.c | 77 ++++++++++++++++++++++++++++++-------------------
1 file changed, 47 insertions(+), 30 deletions(-)

diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 9e9227e..e856bc4 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -177,11 +177,45 @@ struct platform_object {
*/
void platform_device_put(struct platform_device *pdev)
{
- if (pdev)
- put_device(&pdev->dev);
+ if (!pdev)
+ return;
+
+ if (pdev->id_auto) {
+ ida_simple_remove(&platform_devid_ida, pdev->id);
+ pdev->id = PLATFORM_DEVID_AUTO;
+ }
+
+ put_device(&pdev->dev);
}
EXPORT_SYMBOL_GPL(platform_device_put);

+static int pdev_set_name(struct platform_device *pdev)
+{
+ int ret;
+
+ switch (pdev->id) {
+ default:
+ return dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id);
+ case PLATFORM_DEVID_NONE:
+ return dev_set_name(&pdev->dev, "%s", pdev->name);
+ case PLATFORM_DEVID_AUTO:
+ /*
+ * Automatically allocated device ID. We mark it as such so
+ * that we remember it must be freed, and we append a suffix
+ * to avoid namespace collision with explicit IDs.
+ */
+ ret = ida_simple_get(&platform_devid_ida, 0, 0, GFP_KERNEL);
+ if (ret < 0)
+ return ret;
+ pdev->id = ret;
+ pdev->id_auto = true;
+ return dev_set_name(&pdev->dev, "%s.%d.auto", pdev->name,
+ pdev->id);
+ }
+
+ return 0;
+}
+
static void platform_device_release(struct device *dev)
{
struct platform_object *pa = container_of(dev, struct platform_object,
@@ -214,6 +248,10 @@ struct platform_device *platform_device_alloc(const char *name, int id)
device_initialize(&pa->pdev.dev);
pa->pdev.dev.release = platform_device_release;
arch_setup_pdev_archdata(&pa->pdev);
+ if (pdev_set_name(&pa->pdev)) {
+ kfree(pa);
+ return NULL;
+ }
}

return pa ? &pa->pdev : NULL;
@@ -294,28 +332,6 @@ int platform_device_add(struct platform_device *pdev)

pdev->dev.bus = &platform_bus_type;

- switch (pdev->id) {
- default:
- dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id);
- break;
- case PLATFORM_DEVID_NONE:
- dev_set_name(&pdev->dev, "%s", pdev->name);
- break;
- case PLATFORM_DEVID_AUTO:
- /*
- * Automatically allocated device ID. We mark it as such so
- * that we remember it must be freed, and we append a suffix
- * to avoid namespace collision with explicit IDs.
- */
- ret = ida_simple_get(&platform_devid_ida, 0, 0, GFP_KERNEL);
- if (ret < 0)
- goto err_out;
- pdev->id = ret;
- pdev->id_auto = true;
- dev_set_name(&pdev->dev, "%s.%d.auto", pdev->name, pdev->id);
- break;
- }
-
for (i = 0; i < pdev->num_resources; i++) {
struct resource *p, *r = &pdev->resource[i];

@@ -358,7 +374,6 @@ int platform_device_add(struct platform_device *pdev)
release_resource(r);
}

- err_out:
return ret;
}
EXPORT_SYMBOL_GPL(platform_device_add);
@@ -378,11 +393,6 @@ void platform_device_del(struct platform_device *pdev)
if (pdev) {
device_del(&pdev->dev);

- if (pdev->id_auto) {
- ida_simple_remove(&platform_devid_ida, pdev->id);
- pdev->id = PLATFORM_DEVID_AUTO;
- }
-
for (i = 0; i < pdev->num_resources; i++) {
struct resource *r = &pdev->resource[i];
unsigned long type = resource_type(r);
@@ -400,8 +410,15 @@ EXPORT_SYMBOL_GPL(platform_device_del);
*/
int platform_device_register(struct platform_device *pdev)
{
+ int ret;
+
device_initialize(&pdev->dev);
arch_setup_pdev_archdata(pdev);
+
+ ret = pdev_set_name(pdev);
+ if (ret)
+ return ret;
+
return platform_device_add(pdev);
}
EXPORT_SYMBOL_GPL(platform_device_register);
--
2.0.0.rc4

2014-06-05 12:54:16

by Heikki Krogerus

[permalink] [raw]
Subject: [PATCHv2 4/6] phy: remove the old lookup method

The users of the old method are now converted to the new one.

Signed-off-by: Heikki Krogerus <[email protected]>
---
drivers/phy/phy-bcm-kona-usb2.c | 2 +-
drivers/phy/phy-core.c | 45 +++----------------------------------
drivers/phy/phy-exynos-dp-video.c | 2 +-
drivers/phy/phy-exynos-mipi-video.c | 2 +-
drivers/phy/phy-exynos5-usbdrd.c | 3 +--
drivers/phy/phy-exynos5250-sata.c | 2 +-
drivers/phy/phy-mvebu-sata.c | 2 +-
drivers/phy/phy-omap-usb2.c | 2 +-
drivers/phy/phy-samsung-usb2.c | 2 +-
drivers/phy/phy-sun4i-usb.c | 2 +-
drivers/phy/phy-ti-pipe3.c | 2 +-
drivers/phy/phy-twl4030-usb.c | 4 +---
drivers/phy/phy-xgene.c | 2 +-
include/linux/phy/phy.h | 37 ++++--------------------------
14 files changed, 19 insertions(+), 90 deletions(-)

diff --git a/drivers/phy/phy-bcm-kona-usb2.c b/drivers/phy/phy-bcm-kona-usb2.c
index e94f5a6..47d810f 100644
--- a/drivers/phy/phy-bcm-kona-usb2.c
+++ b/drivers/phy/phy-bcm-kona-usb2.c
@@ -117,7 +117,7 @@ static int bcm_kona_usb2_probe(struct platform_device *pdev)

platform_set_drvdata(pdev, phy);

- gphy = devm_phy_create(dev, &ops, NULL);
+ gphy = devm_phy_create(dev, &ops);
if (IS_ERR(gphy))
return PTR_ERR(gphy);

diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c
index 38034fd..74d4346 100644
--- a/drivers/phy/phy-core.c
+++ b/drivers/phy/phy-core.c
@@ -54,36 +54,6 @@ static int devm_phy_match(struct device *dev, void *res, void *match_data)
return res == match_data;
}

-static struct phy *phy_lookup(struct device *device, const char *port)
-{
- unsigned int count;
- struct phy *phy;
- struct device *dev;
- struct phy_consumer *consumers;
- struct class_dev_iter iter;
-
- class_dev_iter_init(&iter, phy_class, NULL, NULL);
- while ((dev = class_dev_iter_next(&iter))) {
- phy = to_phy(dev);
-
- if (!phy->init_data)
- continue;
- count = phy->init_data->num_consumers;
- consumers = phy->init_data->consumers;
- while (count--) {
- if (!strcmp(consumers->dev_name, dev_name(device)) &&
- !strcmp(consumers->port, port)) {
- class_dev_iter_exit(&iter);
- return phy;
- }
- consumers++;
- }
- }
-
- class_dev_iter_exit(&iter);
- return ERR_PTR(-ENODEV);
-}
-
/**
* phy_register_lookup() - register PHY/device association
* @pl: association to register
@@ -209,10 +179,6 @@ static struct phy *phy_find(struct device *dev, const char *con_id)
}
class_dev_iter_exit(&iter);
}
-
- /* fall-back to the old lookup method for now */
- if (IS_ERR(phy))
- phy = phy_lookup(dev, con_id);
return phy;
}

@@ -696,12 +662,10 @@ EXPORT_SYMBOL_GPL(devm_of_phy_get);
* phy_create() - create a new phy
* @dev: device that is creating the new phy
* @ops: function pointers for performing phy operations
- * @init_data: contains the list of PHY consumers or NULL
*
* Called to create a phy using phy framework.
*/
-struct phy *phy_create(struct device *dev, const struct phy_ops *ops,
- struct phy_init_data *init_data)
+struct phy *phy_create(struct device *dev, const struct phy_ops *ops)
{
int ret;
int id;
@@ -729,7 +693,6 @@ struct phy *phy_create(struct device *dev, const struct phy_ops *ops,
phy->dev.of_node = dev->of_node;
phy->id = id;
phy->ops = ops;
- phy->init_data = init_data;

ret = dev_set_name(&phy->dev, "phy-%s.%d", dev_name(dev), id);
if (ret)
@@ -759,15 +722,13 @@ EXPORT_SYMBOL_GPL(phy_create);
* devm_phy_create() - create a new phy
* @dev: device that is creating the new phy
* @ops: function pointers for performing phy operations
- * @init_data: contains the list of PHY consumers or NULL
*
* Creates a new PHY device adding it to the PHY class.
* While at that, it also associates the device with the phy using devres.
* On driver detach, release function is invoked on the devres data,
* then, devres data is freed.
*/
-struct phy *devm_phy_create(struct device *dev, const struct phy_ops *ops,
- struct phy_init_data *init_data)
+struct phy *devm_phy_create(struct device *dev, const struct phy_ops *ops)
{
struct phy **ptr, *phy;

@@ -775,7 +736,7 @@ struct phy *devm_phy_create(struct device *dev, const struct phy_ops *ops,
if (!ptr)
return ERR_PTR(-ENOMEM);

- phy = phy_create(dev, ops, init_data);
+ phy = phy_create(dev, ops);
if (!IS_ERR(phy)) {
*ptr = phy;
devres_add(dev, ptr);
diff --git a/drivers/phy/phy-exynos-dp-video.c b/drivers/phy/phy-exynos-dp-video.c
index 0786fef..1236a03 100644
--- a/drivers/phy/phy-exynos-dp-video.c
+++ b/drivers/phy/phy-exynos-dp-video.c
@@ -76,7 +76,7 @@ static int exynos_dp_video_phy_probe(struct platform_device *pdev)
if (IS_ERR(state->regs))
return PTR_ERR(state->regs);

- phy = devm_phy_create(dev, &exynos_dp_video_phy_ops, NULL);
+ phy = devm_phy_create(dev, &exynos_dp_video_phy_ops);
if (IS_ERR(phy)) {
dev_err(dev, "failed to create Display Port PHY\n");
return PTR_ERR(phy);
diff --git a/drivers/phy/phy-exynos-mipi-video.c b/drivers/phy/phy-exynos-mipi-video.c
index ff02668..a96415e 100644
--- a/drivers/phy/phy-exynos-mipi-video.c
+++ b/drivers/phy/phy-exynos-mipi-video.c
@@ -136,7 +136,7 @@ static int exynos_mipi_video_phy_probe(struct platform_device *pdev)

for (i = 0; i < EXYNOS_MIPI_PHYS_NUM; i++) {
struct phy *phy = devm_phy_create(dev,
- &exynos_mipi_video_phy_ops, NULL);
+ &exynos_mipi_video_phy_ops);
if (IS_ERR(phy)) {
dev_err(dev, "failed to create PHY %d\n", i);
return PTR_ERR(phy);
diff --git a/drivers/phy/phy-exynos5-usbdrd.c b/drivers/phy/phy-exynos5-usbdrd.c
index 76d862b..56285af 100644
--- a/drivers/phy/phy-exynos5-usbdrd.c
+++ b/drivers/phy/phy-exynos5-usbdrd.c
@@ -635,8 +635,7 @@ static int exynos5_usbdrd_phy_probe(struct platform_device *pdev)
dev_vdbg(dev, "Creating usbdrd_phy phy\n");

for (i = 0; i < EXYNOS5_DRDPHYS_NUM; i++) {
- struct phy *phy = devm_phy_create(dev, &exynos5_usbdrd_phy_ops,
- NULL);
+ struct phy *phy = devm_phy_create(dev, &exynos5_usbdrd_phy_ops);
if (IS_ERR(phy)) {
dev_err(dev, "Failed to create usbdrd_phy phy\n");
return PTR_ERR(phy);
diff --git a/drivers/phy/phy-exynos5250-sata.c b/drivers/phy/phy-exynos5250-sata.c
index 0568945..938d1ce 100644
--- a/drivers/phy/phy-exynos5250-sata.c
+++ b/drivers/phy/phy-exynos5250-sata.c
@@ -210,7 +210,7 @@ static int exynos_sata_phy_probe(struct platform_device *pdev)
return ret;
}

- sata_phy->phy = devm_phy_create(dev, &exynos_sata_phy_ops, NULL);
+ sata_phy->phy = devm_phy_create(dev, &exynos_sata_phy_ops);
if (IS_ERR(sata_phy->phy)) {
clk_disable_unprepare(sata_phy->phyclk);
dev_err(dev, "failed to create PHY\n");
diff --git a/drivers/phy/phy-mvebu-sata.c b/drivers/phy/phy-mvebu-sata.c
index d70ecd6..294d0a0 100644
--- a/drivers/phy/phy-mvebu-sata.c
+++ b/drivers/phy/phy-mvebu-sata.c
@@ -99,7 +99,7 @@ static int phy_mvebu_sata_probe(struct platform_device *pdev)
if (IS_ERR(priv->clk))
return PTR_ERR(priv->clk);

- phy = devm_phy_create(&pdev->dev, &phy_mvebu_sata_ops, NULL);
+ phy = devm_phy_create(&pdev->dev, &phy_mvebu_sata_ops);
if (IS_ERR(phy))
return PTR_ERR(phy);

diff --git a/drivers/phy/phy-omap-usb2.c b/drivers/phy/phy-omap-usb2.c
index 7007c11..e84c24f 100644
--- a/drivers/phy/phy-omap-usb2.c
+++ b/drivers/phy/phy-omap-usb2.c
@@ -264,7 +264,7 @@ static int omap_usb2_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, phy);
pm_runtime_enable(phy->dev);

- generic_phy = devm_phy_create(phy->dev, &ops, NULL);
+ generic_phy = devm_phy_create(phy->dev, &ops);
if (IS_ERR(generic_phy))
return PTR_ERR(generic_phy);

diff --git a/drivers/phy/phy-samsung-usb2.c b/drivers/phy/phy-samsung-usb2.c
index 8a8c6bc..2e9be37 100644
--- a/drivers/phy/phy-samsung-usb2.c
+++ b/drivers/phy/phy-samsung-usb2.c
@@ -189,7 +189,7 @@ static int samsung_usb2_phy_probe(struct platform_device *pdev)
struct samsung_usb2_phy_instance *p = &drv->instances[i];

dev_dbg(dev, "Creating phy \"%s\"\n", label);
- p->phy = devm_phy_create(dev, &samsung_usb2_phy_ops, NULL);
+ p->phy = devm_phy_create(dev, &samsung_usb2_phy_ops);
if (IS_ERR(p->phy)) {
dev_err(drv->dev, "Failed to create usb2_phy \"%s\"\n",
label);
diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c
index 115d8d5..40de1f2 100644
--- a/drivers/phy/phy-sun4i-usb.c
+++ b/drivers/phy/phy-sun4i-usb.c
@@ -294,7 +294,7 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev)
return PTR_ERR(phy->pmu);
}

- phy->phy = devm_phy_create(dev, &sun4i_usb_phy_ops, NULL);
+ phy->phy = devm_phy_create(dev, &sun4i_usb_phy_ops);
if (IS_ERR(phy->phy)) {
dev_err(dev, "failed to create PHY %d\n", i);
return PTR_ERR(phy->phy);
diff --git a/drivers/phy/phy-ti-pipe3.c b/drivers/phy/phy-ti-pipe3.c
index 5913676..5e01da7 100644
--- a/drivers/phy/phy-ti-pipe3.c
+++ b/drivers/phy/phy-ti-pipe3.c
@@ -353,7 +353,7 @@ static int ti_pipe3_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, phy);
pm_runtime_enable(phy->dev);

- generic_phy = devm_phy_create(phy->dev, &ops, NULL);
+ generic_phy = devm_phy_create(phy->dev, &ops);
if (IS_ERR(generic_phy))
return PTR_ERR(generic_phy);

diff --git a/drivers/phy/phy-twl4030-usb.c b/drivers/phy/phy-twl4030-usb.c
index 2e0e9b3..803c536 100644
--- a/drivers/phy/phy-twl4030-usb.c
+++ b/drivers/phy/phy-twl4030-usb.c
@@ -659,7 +659,6 @@ static int twl4030_usb_probe(struct platform_device *pdev)
struct usb_otg *otg;
struct device_node *np = pdev->dev.of_node;
struct phy_provider *phy_provider;
- struct phy_init_data *init_data = NULL;

twl = devm_kzalloc(&pdev->dev, sizeof(*twl), GFP_KERNEL);
if (!twl)
@@ -670,7 +669,6 @@ static int twl4030_usb_probe(struct platform_device *pdev)
(enum twl4030_usb_mode *)&twl->usb_mode);
else if (pdata) {
twl->usb_mode = pdata->usb_mode;
- init_data = pdata->init_data;
} else {
dev_err(&pdev->dev, "twl4030 initialized without pdata\n");
return -EINVAL;
@@ -695,7 +693,7 @@ static int twl4030_usb_probe(struct platform_device *pdev)
otg->set_host = twl4030_set_host;
otg->set_peripheral = twl4030_set_peripheral;

- phy = devm_phy_create(twl->dev, &ops, init_data);
+ phy = devm_phy_create(twl->dev, &ops);
if (IS_ERR(phy)) {
dev_dbg(&pdev->dev, "Failed to create PHY\n");
return PTR_ERR(phy);
diff --git a/drivers/phy/phy-xgene.c b/drivers/phy/phy-xgene.c
index 4aa1ccd..57fc42c 100644
--- a/drivers/phy/phy-xgene.c
+++ b/drivers/phy/phy-xgene.c
@@ -1707,7 +1707,7 @@ static int xgene_phy_probe(struct platform_device *pdev)
ctx->dev = &pdev->dev;
platform_set_drvdata(pdev, ctx);

- ctx->phy = devm_phy_create(ctx->dev, &xgene_phy_ops, NULL);
+ ctx->phy = devm_phy_create(ctx->dev, &xgene_phy_ops);
if (IS_ERR(ctx->phy)) {
dev_dbg(&pdev->dev, "Failed to create PHY\n");
rc = PTR_ERR(ctx->phy);
diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h
index 09348a7..5a537a5 100644
--- a/include/linux/phy/phy.h
+++ b/include/linux/phy/phy.h
@@ -60,7 +60,6 @@ struct phy {
struct device dev;
int id;
const struct phy_ops *ops;
- struct phy_init_data *init_data;
struct mutex mutex;
int init_count;
int power_count;
@@ -82,32 +81,6 @@ struct phy_provider {
struct of_phandle_args *args);
};

-/**
- * struct phy_consumer - represents the phy consumer
- * @dev_name: the device name of the controller that will use this PHY device
- * @port: name given to the consumer port
- */
-struct phy_consumer {
- const char *dev_name;
- const char *port;
-};
-
-/**
- * struct phy_init_data - contains the list of PHY consumers
- * @num_consumers: number of consumers for this PHY device
- * @consumers: list of PHY consumers
- */
-struct phy_init_data {
- unsigned int num_consumers;
- struct phy_consumer *consumers;
-};
-
-#define PHY_CONSUMER(_dev_name, _port) \
-{ \
- .dev_name = _dev_name, \
- .port = _port, \
-}
-
struct phy_lookup {
struct list_head node;
const char *phy_name;
@@ -170,10 +143,8 @@ void devm_phy_put(struct device *dev, struct phy *phy);
struct phy *of_phy_get(struct device_node *np, const char *con_id);
struct phy *of_phy_simple_xlate(struct device *dev,
struct of_phandle_args *args);
-struct phy *phy_create(struct device *dev, const struct phy_ops *ops,
- struct phy_init_data *init_data);
-struct phy *devm_phy_create(struct device *dev,
- const struct phy_ops *ops, struct phy_init_data *init_data);
+struct phy *phy_create(struct device *dev, const struct phy_ops *ops);
+struct phy *devm_phy_create(struct device *dev, const struct phy_ops *ops);
void phy_destroy(struct phy *phy);
void devm_phy_destroy(struct device *dev, struct phy *phy);
struct phy_provider *__of_phy_provider_register(struct device *dev,
@@ -315,13 +286,13 @@ static inline struct phy *of_phy_simple_xlate(struct device *dev,
}

static inline struct phy *phy_create(struct device *dev,
- const struct phy_ops *ops, struct phy_init_data *init_data)
+ const struct phy_ops *ops)
{
return ERR_PTR(-ENOSYS);
}

static inline struct phy *devm_phy_create(struct device *dev,
- const struct phy_ops *ops, struct phy_init_data *init_data)
+ const struct phy_ops *ops)
{
return ERR_PTR(-ENOSYS);
}
--
2.0.0.rc4

2014-06-05 12:54:35

by Heikki Krogerus

[permalink] [raw]
Subject: [PATCHv2 3/6] arm: omap3: twl: use the new lookup method with usb phy

Provide complete association for the phy and it's user
(musb) with the new phy lookup method.

Signed-off-by: Heikki Krogerus <[email protected]>
Cc: Tony Lindgren <[email protected]>
---
arch/arm/mach-omap2/twl-common.c | 18 ++++++++----------
1 file changed, 8 insertions(+), 10 deletions(-)

diff --git a/arch/arm/mach-omap2/twl-common.c b/arch/arm/mach-omap2/twl-common.c
index b0d54da..b78383c 100644
--- a/arch/arm/mach-omap2/twl-common.c
+++ b/arch/arm/mach-omap2/twl-common.c
@@ -91,18 +91,14 @@ void __init omap_pmic_late_init(void)
}

#if defined(CONFIG_ARCH_OMAP3)
-struct phy_consumer consumers[] = {
- PHY_CONSUMER("musb-hdrc.0", "usb"),
-};
-
-struct phy_init_data init_data = {
- .consumers = consumers,
- .num_consumers = ARRAY_SIZE(consumers),
+static struct phy_lookup twl4030_usb_lookup = {
+ .phy_name = "phy-twl4030_usb.0",
+ .dev_id = "musb-hdrc.0",
+ .con_id = "usb",
};

static struct twl4030_usb_data omap3_usb_pdata = {
- .usb_mode = T2_USB_MODE_ULPI,
- .init_data = &init_data,
+ .usb_mode = T2_USB_MODE_ULPI,
};

static int omap3_batt_table[] = {
@@ -225,8 +221,10 @@ void __init omap3_pmic_get_config(struct twl4030_platform_data *pmic_data,
}

/* Common platform data configurations */
- if (pdata_flags & TWL_COMMON_PDATA_USB && !pmic_data->usb)
+ if (pdata_flags & TWL_COMMON_PDATA_USB && !pmic_data->usb) {
+ phy_register_lookup(&twl4030_usb_lookup);
pmic_data->usb = &omap3_usb_pdata;
+ }

if (pdata_flags & TWL_COMMON_PDATA_BCI && !pmic_data->bci)
pmic_data->bci = &omap3_bci_pdata;
--
2.0.0.rc4

2014-06-05 12:55:09

by Heikki Krogerus

[permalink] [raw]
Subject: [PATCHv2 1/6] phy: safer to_phy() macro

This makes to_phy() macro work with other variable names
besides "dev".

Signed-off-by: Heikki Krogerus <[email protected]>
---
include/linux/phy/phy.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h
index 2760744..10d9714 100644
--- a/include/linux/phy/phy.h
+++ b/include/linux/phy/phy.h
@@ -108,7 +108,7 @@ struct phy_init_data {
.port = _port, \
}

-#define to_phy(dev) (container_of((dev), struct phy, dev))
+#define to_phy(a) (container_of((a), struct phy, dev))

#define of_phy_provider_register(dev, xlate) \
__of_phy_provider_register((dev), THIS_MODULE, (xlate))
--
2.0.0.rc4

2014-06-05 12:55:08

by Heikki Krogerus

[permalink] [raw]
Subject: [PATCHv2 2/6] phy: improved lookup method

Removes the need for the phys to be aware of their users
even when not using DT. The method is copied from clkdev.c.

Signed-off-by: Heikki Krogerus <[email protected]>
---
Documentation/phy.txt | 66 ++++++++---------------
drivers/phy/phy-core.c | 135 +++++++++++++++++++++++++++++++++++++++++++++++-
include/linux/phy/phy.h | 27 ++++++++++
3 files changed, 183 insertions(+), 45 deletions(-)

diff --git a/Documentation/phy.txt b/Documentation/phy.txt
index ebff6ee..441dc10 100644
--- a/Documentation/phy.txt
+++ b/Documentation/phy.txt
@@ -53,17 +53,13 @@ unregister the PHY.
The PHY driver should create the PHY in order for other peripheral controllers
to make use of it. The PHY framework provides 2 APIs to create the PHY.

-struct phy *phy_create(struct device *dev, const struct phy_ops *ops,
- struct phy_init_data *init_data);
-struct phy *devm_phy_create(struct device *dev, const struct phy_ops *ops,
- struct phy_init_data *init_data);
+struct phy *phy_create(struct device *dev, const struct phy_ops *ops);
+struct phy *devm_phy_create(struct device *dev, const struct phy_ops *ops);

The PHY drivers can use one of the above 2 APIs to create the PHY by passing
-the device pointer, phy ops and init_data.
+the device pointer and phy ops.
phy_ops is a set of function pointers for performing PHY operations such as
-init, exit, power_on and power_off. *init_data* is mandatory to get a reference
-to the PHY in the case of non-dt boot. See section *Board File Initialization*
-on how init_data should be used.
+init, exit, power_on and power_off.

Inorder to dereference the private data (in phy_ops), the phy provider driver
can use phy_set_drvdata() after creating the PHY and use phy_get_drvdata() in
@@ -135,42 +131,24 @@ There are exported APIs like phy_pm_runtime_get, phy_pm_runtime_get_sync,
phy_pm_runtime_put, phy_pm_runtime_put_sync, phy_pm_runtime_allow and
phy_pm_runtime_forbid for performing PM operations.

-8. Board File Initialization
-
-Certain board file initialization is necessary in order to get a reference
-to the PHY in the case of non-dt boot.
-Say we have a single device that implements 3 PHYs that of USB, SATA and PCIe,
-then in the board file the following initialization should be done.
-
-struct phy_consumer consumers[] = {
- PHY_CONSUMER("dwc3.0", "usb"),
- PHY_CONSUMER("pcie.0", "pcie"),
- PHY_CONSUMER("sata.0", "sata"),
-};
-PHY_CONSUMER takes 2 parameters, first is the device name of the controller
-(PHY consumer) and second is the port name.
-
-struct phy_init_data init_data = {
- .consumers = consumers,
- .num_consumers = ARRAY_SIZE(consumers),
-};
-
-static const struct platform_device pipe3_phy_dev = {
- .name = "pipe3-phy",
- .id = -1,
- .dev = {
- .platform_data = {
- .init_data = &init_data,
- },
- },
-};
-
-then, while doing phy_create, the PHY driver should pass this init_data
- phy_create(dev, ops, pdata->init_data);
-
-and the controller driver (phy consumer) should pass the port name along with
-the device to get a reference to the PHY
- phy_get(dev, "pcie");
+8. PHY Mappings
+
+In order to get reference to a PHY without help from DeviceTree, the framework
+offers lookups which can be compared to clkdev that allow clk structures to be
+bound to devices. A lookup can be made statically by directly registering
+phy_lookup structure which contains the name of the PHY device, the name of the
+device which the PHY will be bind to and Connection ID string. Alternatively a
+lookup can be made during runtime when a handle to the struct phy already
+exists.
+
+The framework offers the following APIs for registering and unregistering the
+lookups.
+
+void phy_register_lookup(struct phy_lookup *pl);
+int phy_create_lookup(struct phy *phy, const char *con_id, const char *dev_id);
+
+void phy_unregister_lookup(struct phy_lookup *pl);
+void phy_remove_lookup(struct phy *phy, const char *con_id, const char *dev_id);

9. DeviceTree Binding

diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c
index c64a2f3..38034fd 100644
--- a/drivers/phy/phy-core.c
+++ b/drivers/phy/phy-core.c
@@ -25,6 +25,7 @@
static struct class *phy_class;
static DEFINE_MUTEX(phy_provider_mutex);
static LIST_HEAD(phy_provider_list);
+static LIST_HEAD(phys);
static DEFINE_IDA(phy_ida);

static void devm_phy_release(struct device *dev, void *res)
@@ -83,6 +84,138 @@ static struct phy *phy_lookup(struct device *device, const char *port)
return ERR_PTR(-ENODEV);
}

+/**
+ * phy_register_lookup() - register PHY/device association
+ * @pl: association to register
+ */
+void phy_register_lookup(struct phy_lookup *pl)
+{
+ mutex_lock(&phy_provider_mutex);
+ list_add_tail(&pl->node, &phys);
+ mutex_unlock(&phy_provider_mutex);
+}
+
+/**
+ * phy_unregister_lookup() - remove PHY/device association
+ * @pl: association to be removed
+ */
+void phy_unregister_lookup(struct phy_lookup *pl)
+{
+ mutex_lock(&phy_provider_mutex);
+ list_del(&pl->node);
+ mutex_unlock(&phy_provider_mutex);
+}
+
+/**
+ * phy_create_lookup() - allocate and register PHY/device association
+ * @phy: the phy of the association
+ * @con_id: connection ID string on device
+ * @dev_id: the device of the association
+ *
+ * Creates and registers phy_lookup entry.
+ */
+int phy_create_lookup(struct phy *phy, const char *con_id, const char *dev_id)
+{
+ struct phy_lookup *pl;
+
+ if (!phy || (!dev_id && !con_id))
+ return -EINVAL;
+
+ pl = kzalloc(sizeof(*pl), GFP_KERNEL);
+ if (!pl)
+ return -ENOMEM;
+
+ pl->phy_name = dev_name(&phy->dev);
+ pl->dev_id = dev_id;
+ pl->con_id = con_id;
+
+ phy_register_lookup(pl);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(phy_create_lookup);
+
+/**
+ * phy_remove_lookup() - find and remove PHY/device association
+ * @phy: the phy of the association
+ * @con_id: connection ID string on device
+ * @dev_id: the device of the association
+ *
+ * Finds and unregisters phy_lookup entry that was created with
+ * phy_create_lookup().
+ */
+void phy_remove_lookup(struct phy *phy, const char *con_id, const char *dev_id)
+{
+ struct phy_lookup *pl;
+
+ if (!phy || (!dev_id && !con_id))
+ return;
+
+ list_for_each_entry(pl, &phys, node)
+ if (!strcmp(pl->phy_name, dev_name(&phy->dev)) &&
+ !strcmp(pl->dev_id, dev_id) &&
+ !strcmp(pl->con_id, con_id)) {
+ phy_unregister_lookup(pl);
+ kfree(pl);
+ return;
+ }
+}
+EXPORT_SYMBOL_GPL(phy_remove_lookup);
+
+static struct phy *phy_find(struct device *dev, const char *con_id)
+{
+ const char *dev_id = dev ? dev_name(dev) : NULL;
+ int match, best_found = 0, best_possible = 0;
+ struct phy *phy = ERR_PTR(-ENODEV);
+ struct phy_lookup *p, *pl = NULL;
+
+ if (dev_id)
+ best_possible += 2;
+ if (con_id)
+ best_possible += 1;
+
+ list_for_each_entry(p, &phys, node) {
+ match = 0;
+ if (p->dev_id) {
+ if (!dev_id || strcmp(p->dev_id, dev_id))
+ continue;
+ match += 2;
+ }
+ if (p->con_id) {
+ if (!con_id || strcmp(p->con_id, con_id))
+ continue;
+ match += 1;
+ }
+
+ if (match > best_found) {
+ pl = p;
+ if (match != best_possible)
+ best_found = match;
+ else
+ break;
+ }
+ }
+
+ if (pl) {
+ struct class_dev_iter iter;
+ struct device *phy_dev;
+
+ class_dev_iter_init(&iter, phy_class, NULL, NULL);
+ while ((phy_dev = class_dev_iter_next(&iter))) {
+ if (!strcmp(dev_name(phy_dev), pl->phy_name)) {
+ phy = to_phy(phy_dev);
+ break;
+ }
+ }
+ class_dev_iter_exit(&iter);
+ }
+
+ /* fall-back to the old lookup method for now */
+ if (IS_ERR(phy))
+ phy = phy_lookup(dev, con_id);
+ return phy;
+}
+
static struct phy_provider *of_phy_provider_lookup(struct device_node *node)
{
struct phy_provider *phy_provider;
@@ -439,7 +572,7 @@ struct phy *phy_get(struct device *dev, const char *string)
string);
phy = _of_phy_get(dev->of_node, index);
} else {
- phy = phy_lookup(dev, string);
+ phy = phy_find(dev, string);
}
if (IS_ERR(phy))
return phy;
diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h
index 10d9714..09348a7 100644
--- a/include/linux/phy/phy.h
+++ b/include/linux/phy/phy.h
@@ -108,6 +108,20 @@ struct phy_init_data {
.port = _port, \
}

+struct phy_lookup {
+ struct list_head node;
+ const char *phy_name;
+ const char *dev_id;
+ const char *con_id;
+};
+
+#define PHY_LOOKUP(a, b, c) \
+ { \
+ .phy_name = a, \
+ .dev_id = b, \
+ .con_id = c, \
+ }
+
#define to_phy(a) (container_of((a), struct phy, dev))

#define of_phy_provider_register(dev, xlate) \
@@ -171,6 +185,10 @@ struct phy_provider *__devm_of_phy_provider_register(struct device *dev,
void of_phy_provider_unregister(struct phy_provider *phy_provider);
void devm_of_phy_provider_unregister(struct device *dev,
struct phy_provider *phy_provider);
+void phy_register_lookup(struct phy_lookup *pl);
+void phy_unregister_lookup(struct phy_lookup *pl);
+int phy_create_lookup(struct phy *phy, const char *con_id, const char *dev_id);
+void phy_remove_lookup(struct phy *phy, const char *con_id, const char *dev_id);
#else
static inline int phy_pm_runtime_get(struct phy *phy)
{
@@ -338,6 +356,15 @@ static inline void devm_of_phy_provider_unregister(struct device *dev,
struct phy_provider *phy_provider)
{
}
+static inline void phy_register_lookup(struct phy_lookup *pl) { }
+static inline void phy_unregister_lookup(struct phy_lookup *pl) { }
+static inline int
+phy_create_lookup(struct phy *phy, const char *con_id, const char *dev_id)
+{
+ return 0;
+}
+static inline void phy_remove_lookup(struct phy *phy, const char *con_id,
+ const char *dev_id) { }
#endif

#endif /* __DRIVERS_PHY_H */
--
2.0.0.rc4

2014-06-05 13:21:09

by Vivek Gautam

[permalink] [raw]
Subject: Re: [PATCHv2 0/6] phy: simplified phy lookup

Hi Heikki,


On Thu, Jun 5, 2014 at 6:22 PM, Heikki Krogerus
<[email protected]> wrote:
> Hi,
>
> So the idea with these is that they should help to make it possible to
> request phys without caring about how they are mapped to the
> consumers, meaning, was is the mapping done in DT, ACPI, etc. Mapping
> phys to consumers can be now done with lookups similarly how clocks
> can be mapped in clkdev.c.
>
> Vivek needs to handle the phys of dwc3 also in xhci driver on
> Exynos5420 SoC, so I'm resending these now.

Thank you so much for your efforts.
This will greatly help me in preparing the patches for PHY tuning.

>
>
> Heikki Krogerus (6):
> phy: safer to_phy() macro
> phy: improved lookup method
> arm: omap3: twl: use the new lookup method with usb phy
> phy: remove the old lookup method
> base: platform: name the device already during allocation
> usb: dwc3: host: convey the PHYs to xhci
>
> Documentation/phy.txt | 66 +++++----------
> arch/arm/mach-omap2/twl-common.c | 18 ++---
> drivers/base/platform.c | 77 +++++++++++-------
> drivers/phy/phy-bcm-kona-usb2.c | 2 +-
> drivers/phy/phy-core.c | 156 +++++++++++++++++++++++++++++-------
> drivers/phy/phy-exynos-dp-video.c | 2 +-
> drivers/phy/phy-exynos-mipi-video.c | 2 +-
> drivers/phy/phy-exynos5-usbdrd.c | 3 +-
> drivers/phy/phy-exynos5250-sata.c | 2 +-
> drivers/phy/phy-mvebu-sata.c | 2 +-
> drivers/phy/phy-omap-usb2.c | 2 +-
> drivers/phy/phy-samsung-usb2.c | 2 +-
> drivers/phy/phy-sun4i-usb.c | 2 +-
> drivers/phy/phy-ti-pipe3.c | 2 +-
> drivers/phy/phy-twl4030-usb.c | 4 +-
> drivers/phy/phy-xgene.c | 2 +-
> drivers/usb/dwc3/host.c | 22 +++--
> include/linux/phy/phy.h | 60 +++++++-------
> 18 files changed, 259 insertions(+), 167 deletions(-)
>
> --
> 2.0.0.rc4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-usb" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html



--
Best Regards
Vivek Gautam
Samsung R&D Institute, Bangalore
India

2014-06-19 13:43:39

by Felipe Balbi

[permalink] [raw]
Subject: Re: [PATCHv2 6/6] usb: dwc3: host: convey the PHYs to xhci

On Thu, Jun 05, 2014 at 03:52:58PM +0300, Heikki Krogerus wrote:
> On some platforms a PHY may need to be handled also in the
> host controller driver. Exynos5420 SoC requires some "PHY
> tuning" based on the USB speed. This patch delivers dwc3's
> PHYs to the xhci platform device when it's created.
>
> Signed-off-by: Heikki Krogerus <[email protected]>
> Cc: Felipe Balbi <[email protected]>

if the rest of the series gets applied, I'm fine with this change

Acked-by: Felipe Balbi <[email protected]>

--
balbi


Attachments:
(No filename) (522.00 B)
signature.asc (819.00 B)
Digital signature
Download all attachments

2014-07-02 11:31:49

by Kishon Vijay Abraham I

[permalink] [raw]
Subject: Re: [PATCHv2 0/6] phy: simplified phy lookup

Hi,

On Thursday 05 June 2014 06:51 PM, Vivek Gautam wrote:
> Hi Heikki,
>
>
> On Thu, Jun 5, 2014 at 6:22 PM, Heikki Krogerus
> <[email protected]> wrote:
>> Hi,
>>
>> So the idea with these is that they should help to make it possible to
>> request phys without caring about how they are mapped to the
>> consumers, meaning, was is the mapping done in DT, ACPI, etc. Mapping
>> phys to consumers can be now done with lookups similarly how clocks
>> can be mapped in clkdev.c.
>>
>> Vivek needs to handle the phys of dwc3 also in xhci driver on
>> Exynos5420 SoC, so I'm resending these now.
>
> Thank you so much for your efforts.
> This will greatly help me in preparing the patches for PHY tuning.

Can I get Tested-by please?

Cheers
Kishon

2014-07-03 04:59:03

by Vivek Gautam

[permalink] [raw]
Subject: Re: [PATCHv2 0/6] phy: simplified phy lookup

Hi,


On Wed, Jul 2, 2014 at 5:01 PM, Kishon Vijay Abraham I <[email protected]> wrote:
> Hi,
>
> On Thursday 05 June 2014 06:51 PM, Vivek Gautam wrote:
>> Hi Heikki,
>>
>>
>> On Thu, Jun 5, 2014 at 6:22 PM, Heikki Krogerus
>> <[email protected]> wrote:
>>> Hi,
>>>
>>> So the idea with these is that they should help to make it possible to
>>> request phys without caring about how they are mapped to the
>>> consumers, meaning, was is the mapping done in DT, ACPI, etc. Mapping
>>> phys to consumers can be now done with lookups similarly how clocks
>>> can be mapped in clkdev.c.
>>>
>>> Vivek needs to handle the phys of dwc3 also in xhci driver on
>>> Exynos5420 SoC, so I'm resending these now.
>>
>> Thank you so much for your efforts.
>> This will greatly help me in preparing the patches for PHY tuning.
>
> Can I get Tested-by please?

Sure,
I have tested this series with my phy-calibration patches. [1]
The entire lookup method looks fine.

Although i am re-working on my patches, but for this series -

Tested-by: Vivek Gautam <[email protected]>


[1] https://lkml.org/lkml/2014/6/6/202


--
Best Regards
Vivek Gautam
Samsung R&D Institute, Bangalore
India

2014-07-14 06:19:32

by Kishon Vijay Abraham I

[permalink] [raw]
Subject: Re: [PATCHv2 3/6] arm: omap3: twl: use the new lookup method with usb phy

Hi Tony,

On Thursday 05 June 2014 06:22 PM, Heikki Krogerus wrote:
> Provide complete association for the phy and it's user
> (musb) with the new phy lookup method.

I can take this patch with your Ack or if you want to take it
Acked-by: Kishon Vijay Abraham I <[email protected]>

Thanks
Kishon
>
> Signed-off-by: Heikki Krogerus <[email protected]>
> Cc: Tony Lindgren <[email protected]>
> ---
> arch/arm/mach-omap2/twl-common.c | 18 ++++++++----------
> 1 file changed, 8 insertions(+), 10 deletions(-)
>
> diff --git a/arch/arm/mach-omap2/twl-common.c b/arch/arm/mach-omap2/twl-common.c
> index b0d54da..b78383c 100644
> --- a/arch/arm/mach-omap2/twl-common.c
> +++ b/arch/arm/mach-omap2/twl-common.c
> @@ -91,18 +91,14 @@ void __init omap_pmic_late_init(void)
> }
>
> #if defined(CONFIG_ARCH_OMAP3)
> -struct phy_consumer consumers[] = {
> - PHY_CONSUMER("musb-hdrc.0", "usb"),
> -};
> -
> -struct phy_init_data init_data = {
> - .consumers = consumers,
> - .num_consumers = ARRAY_SIZE(consumers),
> +static struct phy_lookup twl4030_usb_lookup = {
> + .phy_name = "phy-twl4030_usb.0",
> + .dev_id = "musb-hdrc.0",
> + .con_id = "usb",
> };
>
> static struct twl4030_usb_data omap3_usb_pdata = {
> - .usb_mode = T2_USB_MODE_ULPI,
> - .init_data = &init_data,
> + .usb_mode = T2_USB_MODE_ULPI,
> };
>
> static int omap3_batt_table[] = {
> @@ -225,8 +221,10 @@ void __init omap3_pmic_get_config(struct twl4030_platform_data *pmic_data,
> }
>
> /* Common platform data configurations */
> - if (pdata_flags & TWL_COMMON_PDATA_USB && !pmic_data->usb)
> + if (pdata_flags & TWL_COMMON_PDATA_USB && !pmic_data->usb) {
> + phy_register_lookup(&twl4030_usb_lookup);
> pmic_data->usb = &omap3_usb_pdata;
> + }
>
> if (pdata_flags & TWL_COMMON_PDATA_BCI && !pmic_data->bci)
> pmic_data->bci = &omap3_bci_pdata;
>

2014-07-14 06:20:06

by Kishon Vijay Abraham I

[permalink] [raw]
Subject: Re: [PATCHv2 5/6] base: platform: name the device already during allocation

Greg,

On Thursday 05 June 2014 06:22 PM, Heikki Krogerus wrote:
> This allows resources such as GPIOs and clocks, which can be
> matched based on the device name when requested, to be
> assigned even when PLATFORM_DEVID_AUTO is used.

Any comments on this patch?

Thanks
Kishon
>
> Signed-off-by: Heikki Krogerus <[email protected]>
> Cc: Greg Kroah-Hartman <[email protected]>
> ---
> drivers/base/platform.c | 77 ++++++++++++++++++++++++++++++-------------------
> 1 file changed, 47 insertions(+), 30 deletions(-)
>
> diff --git a/drivers/base/platform.c b/drivers/base/platform.c
> index 9e9227e..e856bc4 100644
> --- a/drivers/base/platform.c
> +++ b/drivers/base/platform.c
> @@ -177,11 +177,45 @@ struct platform_object {
> */
> void platform_device_put(struct platform_device *pdev)
> {
> - if (pdev)
> - put_device(&pdev->dev);
> + if (!pdev)
> + return;
> +
> + if (pdev->id_auto) {
> + ida_simple_remove(&platform_devid_ida, pdev->id);
> + pdev->id = PLATFORM_DEVID_AUTO;
> + }
> +
> + put_device(&pdev->dev);
> }
> EXPORT_SYMBOL_GPL(platform_device_put);
>
> +static int pdev_set_name(struct platform_device *pdev)
> +{
> + int ret;
> +
> + switch (pdev->id) {
> + default:
> + return dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id);
> + case PLATFORM_DEVID_NONE:
> + return dev_set_name(&pdev->dev, "%s", pdev->name);
> + case PLATFORM_DEVID_AUTO:
> + /*
> + * Automatically allocated device ID. We mark it as such so
> + * that we remember it must be freed, and we append a suffix
> + * to avoid namespace collision with explicit IDs.
> + */
> + ret = ida_simple_get(&platform_devid_ida, 0, 0, GFP_KERNEL);
> + if (ret < 0)
> + return ret;
> + pdev->id = ret;
> + pdev->id_auto = true;
> + return dev_set_name(&pdev->dev, "%s.%d.auto", pdev->name,
> + pdev->id);
> + }
> +
> + return 0;
> +}
> +
> static void platform_device_release(struct device *dev)
> {
> struct platform_object *pa = container_of(dev, struct platform_object,
> @@ -214,6 +248,10 @@ struct platform_device *platform_device_alloc(const char *name, int id)
> device_initialize(&pa->pdev.dev);
> pa->pdev.dev.release = platform_device_release;
> arch_setup_pdev_archdata(&pa->pdev);
> + if (pdev_set_name(&pa->pdev)) {
> + kfree(pa);
> + return NULL;
> + }
> }
>
> return pa ? &pa->pdev : NULL;
> @@ -294,28 +332,6 @@ int platform_device_add(struct platform_device *pdev)
>
> pdev->dev.bus = &platform_bus_type;
>
> - switch (pdev->id) {
> - default:
> - dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id);
> - break;
> - case PLATFORM_DEVID_NONE:
> - dev_set_name(&pdev->dev, "%s", pdev->name);
> - break;
> - case PLATFORM_DEVID_AUTO:
> - /*
> - * Automatically allocated device ID. We mark it as such so
> - * that we remember it must be freed, and we append a suffix
> - * to avoid namespace collision with explicit IDs.
> - */
> - ret = ida_simple_get(&platform_devid_ida, 0, 0, GFP_KERNEL);
> - if (ret < 0)
> - goto err_out;
> - pdev->id = ret;
> - pdev->id_auto = true;
> - dev_set_name(&pdev->dev, "%s.%d.auto", pdev->name, pdev->id);
> - break;
> - }
> -
> for (i = 0; i < pdev->num_resources; i++) {
> struct resource *p, *r = &pdev->resource[i];
>
> @@ -358,7 +374,6 @@ int platform_device_add(struct platform_device *pdev)
> release_resource(r);
> }
>
> - err_out:
> return ret;
> }
> EXPORT_SYMBOL_GPL(platform_device_add);
> @@ -378,11 +393,6 @@ void platform_device_del(struct platform_device *pdev)
> if (pdev) {
> device_del(&pdev->dev);
>
> - if (pdev->id_auto) {
> - ida_simple_remove(&platform_devid_ida, pdev->id);
> - pdev->id = PLATFORM_DEVID_AUTO;
> - }
> -
> for (i = 0; i < pdev->num_resources; i++) {
> struct resource *r = &pdev->resource[i];
> unsigned long type = resource_type(r);
> @@ -400,8 +410,15 @@ EXPORT_SYMBOL_GPL(platform_device_del);
> */
> int platform_device_register(struct platform_device *pdev)
> {
> + int ret;
> +
> device_initialize(&pdev->dev);
> arch_setup_pdev_archdata(pdev);
> +
> + ret = pdev_set_name(pdev);
> + if (ret)
> + return ret;
> +
> return platform_device_add(pdev);
> }
> EXPORT_SYMBOL_GPL(platform_device_register);
>

2014-07-14 14:56:37

by Greg Kroah-Hartman

[permalink] [raw]
Subject: Re: [PATCHv2 5/6] base: platform: name the device already during allocation

On Mon, Jul 14, 2014 at 11:49:38AM +0530, Kishon Vijay Abraham I wrote:
> Greg,
>
> On Thursday 05 June 2014 06:22 PM, Heikki Krogerus wrote:
> > This allows resources such as GPIOs and clocks, which can be
> > matched based on the device name when requested, to be
> > assigned even when PLATFORM_DEVID_AUTO is used.
>
> Any comments on this patch?

I thought I rejected it in the past, don't have my email archives
around at the moment, sorry.


> > Signed-off-by: Heikki Krogerus <[email protected]>
> > Cc: Greg Kroah-Hartman <[email protected]>
> > ---
> > drivers/base/platform.c | 77 ++++++++++++++++++++++++++++++-------------------
> > 1 file changed, 47 insertions(+), 30 deletions(-)
> >
> > diff --git a/drivers/base/platform.c b/drivers/base/platform.c
> > index 9e9227e..e856bc4 100644
> > --- a/drivers/base/platform.c
> > +++ b/drivers/base/platform.c
> > @@ -177,11 +177,45 @@ struct platform_object {
> > */
> > void platform_device_put(struct platform_device *pdev)
> > {
> > - if (pdev)
> > - put_device(&pdev->dev);
> > + if (!pdev)
> > + return;
> > +
> > + if (pdev->id_auto) {
> > + ida_simple_remove(&platform_devid_ida, pdev->id);
> > + pdev->id = PLATFORM_DEVID_AUTO;
> > + }
> > +
> > + put_device(&pdev->dev);
> > }
> > EXPORT_SYMBOL_GPL(platform_device_put);

Why would a single call to this function remove an id? That seems
really wrong, you should be able to call get and put on a device
numerous times, only the "last" reference should cause the device to be
cleaned up.

Shouldn't this be in the release function instead?

thanks,

greg k-h