This series fixes an annoying regression to make MUSB working
on omap4 again. Although it's getting rather late for these changes for the -rc cycle, it is important as many devices are using MUSB for charging and connectivity. With the USB PHY changes, MUSB started using the newly added drivers/usb/phy/omap-usb2.c driver introduced by commit657b306a
(usb: phy: add a new driver for omap usb2 phy) that is using the newly introduced drivers/bus/omap-ocp2scp.c introduced by commit26a84b3e
(drivers: bus: add a new driver for omap-ocp2scp). These changes allowed dropping a lot of PHY related code from arch/arm/mach-omap2/omap_phy_internal.c and have it live in the device driver like it should with commitc9e4412a
(arm: omap: phy: remove unused functions from omap-phy-internal.c). However, MUSB on omap4 broke with these changes for legacy platform data boot, and now only works with device tree for omap4. Unfortunately we are still few critical bindings away from being able to make omap4 usbale with device tree. Fix the regression properly by adding platform data support to the ocp2scp driver so we can avoid adding back the driver code to arch/arm/mach-omap2. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.12 (GNU/Linux) iQIcBAABAgAGBQJQmqakAAoJEBvUPslcq6VzBjcQANthvtvNsUrR3X3lB5GRwtIJ uGcOVqdrI9Y6seHQMqCiwa9JNlBHu+ABLYV4UGSNtHLAlaI+pilaqby7cUndFmBo O7FMPAK6EmrUqXewkQh3W3yx/JEy4zu7Kup5rK8p9kPBmqblrjdtfmlrIKjBBhbA 4ZBQC82GSDg/UtLcVxjXgb2aJnLim5L2WU1drCSHgclyBWueg8ijFsTl9l7R9Zwh x6FV6DYHZyxFzvuXlB+83iZ1sJ6qpkD92hPe+Lj3jyxpW6+b6Mx5d/268743+Nde xzCxQ09JGYN+h/N+QX6SRhurHjlXGFwmAhYofdO+r7OdLrT12VHiOptRKh0N9DfX s1Mtk+X6f5iwKo8O//5DXkZPDLW8fI1GNs6QNsw71yM1mDP7tCamYUsSpLLJLcYo bB/O77HdQDWAWBOwbu+GY4eICTgh/Chj3LYe0Aic8F1jm8kzQm5CJMgxyAeMUrHX 2O0yGUUIIqWkNdn/iluVHVs0nHwjfDZsRN4cAdMbjkqF4cJRkH2lIjrSSYlJxYmL cymFrkR0Evj2fmGXhEcX8pGgymlSp1Aj1tnaQ6I06XEjrlbtRpAsibniSx4OCcB2 3sMZOpvmUYD/FecaZRatoOLQC6aNMY8ape0ghLFAklz1By7c2ytzGRQsoDqMoXql hl44QO9QKIYBYb2pPcDj =bbq5 -----END PGP SIGNATURE----- Merge tag 'omap-for-v3.7-rc4/musb-regression-signed' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap into fixes From Tony Lindgren <tony@atomide.com>: This series fixes an annoying regression to make MUSB working on omap4 again. Although it's getting rather late for these changes for the -rc cycle, it is important as many devices are using MUSB for charging and connectivity. With the USB PHY changes, MUSB started using the newly added drivers/usb/phy/omap-usb2.c driver introduced by commit657b306a
(usb: phy: add a new driver for omap usb2 phy) that is using the newly introduced drivers/bus/omap-ocp2scp.c introduced by commit26a84b3e
(drivers: bus: add a new driver for omap-ocp2scp). These changes allowed dropping a lot of PHY related code from arch/arm/mach-omap2/omap_phy_internal.c and have it live in the device driver like it should with commitc9e4412a
(arm: omap: phy: remove unused functions from omap-phy-internal.c). However, MUSB on omap4 broke with these changes for legacy platform data boot, and now only works with device tree for omap4. Unfortunately we are still few critical bindings away from being able to make omap4 usbale with device tree. Fix the regression properly by adding platform data support to the ocp2scp driver so we can avoid adding back the driver code to arch/arm/mach-omap2. * tag 'omap-for-v3.7-rc4/musb-regression-signed' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap: ARM: OMAP: ocp2scp: create omap device for ocp2scp ARM: OMAP4: add _dev_attr_ to ocp2scp for representing usb_phy drivers: bus: ocp2scp: add pdata support Signed-off-by: Arnd Bergmann <arnd@arndb.de>
This commit is contained in:
Коммит
69178dfeb1
|
@ -19,6 +19,7 @@
|
|||
#include <linux/of.h>
|
||||
#include <linux/pinctrl/machine.h>
|
||||
#include <linux/platform_data/omap4-keypad.h>
|
||||
#include <linux/platform_data/omap_ocp2scp.h>
|
||||
|
||||
#include <asm/mach-types.h>
|
||||
#include <asm/mach/map.h>
|
||||
|
@ -613,6 +614,83 @@ static void omap_init_vout(void)
|
|||
static inline void omap_init_vout(void) {}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_OMAP_OCP2SCP) || defined(CONFIG_OMAP_OCP2SCP_MODULE)
|
||||
static int count_ocp2scp_devices(struct omap_ocp2scp_dev *ocp2scp_dev)
|
||||
{
|
||||
int cnt = 0;
|
||||
|
||||
while (ocp2scp_dev->drv_name != NULL) {
|
||||
cnt++;
|
||||
ocp2scp_dev++;
|
||||
}
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
||||
static void omap_init_ocp2scp(void)
|
||||
{
|
||||
struct omap_hwmod *oh;
|
||||
struct platform_device *pdev;
|
||||
int bus_id = -1, dev_cnt = 0, i;
|
||||
struct omap_ocp2scp_dev *ocp2scp_dev;
|
||||
const char *oh_name, *name;
|
||||
struct omap_ocp2scp_platform_data *pdata;
|
||||
|
||||
if (!cpu_is_omap44xx())
|
||||
return;
|
||||
|
||||
oh_name = "ocp2scp_usb_phy";
|
||||
name = "omap-ocp2scp";
|
||||
|
||||
oh = omap_hwmod_lookup(oh_name);
|
||||
if (!oh) {
|
||||
pr_err("%s: could not find omap_hwmod for %s\n", __func__,
|
||||
oh_name);
|
||||
return;
|
||||
}
|
||||
|
||||
pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
|
||||
if (!pdata) {
|
||||
pr_err("%s: No memory for ocp2scp pdata\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
ocp2scp_dev = oh->dev_attr;
|
||||
dev_cnt = count_ocp2scp_devices(ocp2scp_dev);
|
||||
|
||||
if (!dev_cnt) {
|
||||
pr_err("%s: No devices connected to ocp2scp\n", __func__);
|
||||
kfree(pdata);
|
||||
return;
|
||||
}
|
||||
|
||||
pdata->devices = kzalloc(sizeof(struct omap_ocp2scp_dev *)
|
||||
* dev_cnt, GFP_KERNEL);
|
||||
if (!pdata->devices) {
|
||||
pr_err("%s: No memory for ocp2scp pdata devices\n", __func__);
|
||||
kfree(pdata);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < dev_cnt; i++, ocp2scp_dev++)
|
||||
pdata->devices[i] = ocp2scp_dev;
|
||||
|
||||
pdata->dev_cnt = dev_cnt;
|
||||
|
||||
pdev = omap_device_build(name, bus_id, oh, pdata, sizeof(*pdata), NULL,
|
||||
0, false);
|
||||
if (IS_ERR(pdev)) {
|
||||
pr_err("Could not build omap_device for %s %s\n",
|
||||
name, oh_name);
|
||||
kfree(pdata->devices);
|
||||
kfree(pdata);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#else
|
||||
static inline void omap_init_ocp2scp(void) { }
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static int __init omap2_init_devices(void)
|
||||
|
@ -640,6 +718,7 @@ static int __init omap2_init_devices(void)
|
|||
omap_init_sham();
|
||||
omap_init_aes();
|
||||
omap_init_vout();
|
||||
omap_init_ocp2scp();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/platform_data/gpio-omap.h>
|
||||
#include <linux/power/smartreflex.h>
|
||||
#include <linux/platform_data/omap_ocp2scp.h>
|
||||
|
||||
#include <plat/omap_hwmod.h>
|
||||
#include <plat/i2c.h>
|
||||
|
@ -2681,6 +2682,32 @@ static struct omap_hwmod_class omap44xx_ocp2scp_hwmod_class = {
|
|||
.sysc = &omap44xx_ocp2scp_sysc,
|
||||
};
|
||||
|
||||
/* ocp2scp dev_attr */
|
||||
static struct resource omap44xx_usb_phy_and_pll_addrs[] = {
|
||||
{
|
||||
.name = "usb_phy",
|
||||
.start = 0x4a0ad080,
|
||||
.end = 0x4a0ae000,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
{
|
||||
/* XXX: Remove this once control module driver is in place */
|
||||
.name = "ctrl_dev",
|
||||
.start = 0x4a002300,
|
||||
.end = 0x4a002303,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct omap_ocp2scp_dev ocp2scp_dev_attr[] = {
|
||||
{
|
||||
.drv_name = "omap-usb2",
|
||||
.res = omap44xx_usb_phy_and_pll_addrs,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
/* ocp2scp_usb_phy */
|
||||
static struct omap_hwmod omap44xx_ocp2scp_usb_phy_hwmod = {
|
||||
.name = "ocp2scp_usb_phy",
|
||||
|
@ -2694,6 +2721,7 @@ static struct omap_hwmod omap44xx_ocp2scp_usb_phy_hwmod = {
|
|||
.modulemode = MODULEMODE_HWCTRL,
|
||||
},
|
||||
},
|
||||
.dev_attr = ocp2scp_dev_attr,
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -22,6 +22,26 @@
|
|||
#include <linux/pm_runtime.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_data/omap_ocp2scp.h>
|
||||
|
||||
/**
|
||||
* _count_resources - count for the number of resources
|
||||
* @res: struct resource *
|
||||
*
|
||||
* Count and return the number of resources populated for the device that is
|
||||
* connected to ocp2scp.
|
||||
*/
|
||||
static unsigned _count_resources(struct resource *res)
|
||||
{
|
||||
int cnt = 0;
|
||||
|
||||
while (res->start != res->end) {
|
||||
cnt++;
|
||||
res++;
|
||||
}
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
||||
static int ocp2scp_remove_devices(struct device *dev, void *c)
|
||||
{
|
||||
|
@ -34,20 +54,62 @@ static int ocp2scp_remove_devices(struct device *dev, void *c)
|
|||
|
||||
static int __devinit omap_ocp2scp_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
int ret;
|
||||
unsigned res_cnt, i;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct platform_device *pdev_child;
|
||||
struct omap_ocp2scp_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct omap_ocp2scp_dev *dev;
|
||||
|
||||
if (np) {
|
||||
ret = of_platform_populate(np, NULL, NULL, &pdev->dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to add resources for ocp2scp child\n");
|
||||
dev_err(&pdev->dev,
|
||||
"failed to add resources for ocp2scp child\n");
|
||||
goto err0;
|
||||
}
|
||||
} else if (pdata) {
|
||||
for (i = 0, dev = *pdata->devices; i < pdata->dev_cnt; i++,
|
||||
dev++) {
|
||||
res_cnt = _count_resources(dev->res);
|
||||
|
||||
pdev_child = platform_device_alloc(dev->drv_name,
|
||||
PLATFORM_DEVID_AUTO);
|
||||
if (!pdev_child) {
|
||||
dev_err(&pdev->dev,
|
||||
"failed to allocate mem for ocp2scp child\n");
|
||||
goto err0;
|
||||
}
|
||||
|
||||
ret = platform_device_add_resources(pdev_child,
|
||||
dev->res, res_cnt);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"failed to add resources for ocp2scp child\n");
|
||||
goto err1;
|
||||
}
|
||||
|
||||
pdev_child->dev.parent = &pdev->dev;
|
||||
|
||||
ret = platform_device_add(pdev_child);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"failed to register ocp2scp child device\n");
|
||||
goto err1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
dev_err(&pdev->dev, "OCP2SCP initialized without plat data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
|
||||
err1:
|
||||
platform_device_put(pdev_child);
|
||||
|
||||
err0:
|
||||
device_for_each_child(&pdev->dev, NULL, ocp2scp_remove_devices);
|
||||
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* omap_ocp2scp.h -- ocp2scp header file
|
||||
*
|
||||
* Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Author: Kishon Vijay Abraham I <kishon@ti.com>
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __DRIVERS_OMAP_OCP2SCP_H
|
||||
#define __DRIVERS_OMAP_OCP2SCP_H
|
||||
|
||||
struct omap_ocp2scp_dev {
|
||||
const char *drv_name;
|
||||
struct resource *res;
|
||||
};
|
||||
|
||||
struct omap_ocp2scp_platform_data {
|
||||
int dev_cnt;
|
||||
struct omap_ocp2scp_dev **devices;
|
||||
};
|
||||
#endif /* __DRIVERS_OMAP_OCP2SCP_H */
|
Загрузка…
Ссылка в новой задаче