Skip to content

Commit

Permalink
chipidea: usbmisc_imx: Add USB support for VF610 SoCs
Browse files Browse the repository at this point in the history
This adds Vybrid VF610 SoC support. The IP is very similar to i.MX6,
however, the non-core registers are spread in two different register
areas. Hence we support multiple instances of the USB misc driver
and add the driver instance to the imx_usbmisc_data structure.

Signed-off-by: Peter Chen <[email protected]>
Signed-off-by: Stefan Agner <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
  • Loading branch information
agners authored and gregkh committed Sep 24, 2014
1 parent c0e602d commit f40017e
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 11 deletions.
1 change: 1 addition & 0 deletions Documentation/devicetree/bindings/usb/usbmisc-imx.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Required properties:
- #index-cells: Cells used to descibe usb controller index. Should be <1>
- compatible: Should be one of below:
"fsl,imx6q-usbmisc" for imx6q
"fsl,vf610-usbmisc" for Vybrid vf610
- reg: Should contain registers location and length

Examples:
Expand Down
8 changes: 8 additions & 0 deletions drivers/usb/chipidea/ci_hdrc_imx.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ struct ci_hdrc_imx_data {

static struct imx_usbmisc_data *usbmisc_get_init_data(struct device *dev)
{
struct platform_device *misc_pdev;
struct device_node *np = dev->of_node;
struct of_phandle_args args;
struct imx_usbmisc_data *data;
Expand All @@ -79,8 +80,15 @@ static struct imx_usbmisc_data *usbmisc_get_init_data(struct device *dev)
}

data->index = args.args[0];

misc_pdev = of_find_device_by_node(args.np);
of_node_put(args.np);

if (!misc_pdev)
return ERR_PTR(-EPROBE_DEFER);

data->dev = &misc_pdev->dev;

if (of_find_property(np, "disable-over-current", NULL))
data->disable_oc = 1;

Expand Down
1 change: 1 addition & 0 deletions drivers/usb/chipidea/ci_hdrc_imx.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#define __DRIVER_USB_CHIPIDEA_CI_HDRC_IMX_H

struct imx_usbmisc_data {
struct device *dev;
int index;

unsigned int disable_oc:1; /* over current detect disabled */
Expand Down
52 changes: 41 additions & 11 deletions drivers/usb/chipidea/usbmisc_imx.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@

#define MX6_BM_OVER_CUR_DIS BIT(7)

#define VF610_OVER_CUR_DIS BIT(7)

struct usbmisc_ops {
/* It's called once when probe a usb device */
int (*init)(struct imx_usbmisc_data *data);
Expand All @@ -71,10 +73,9 @@ struct imx_usbmisc {
const struct usbmisc_ops *ops;
};

static struct imx_usbmisc *usbmisc;

static int usbmisc_imx25_init(struct imx_usbmisc_data *data)
{
struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
unsigned long flags;
u32 val = 0;

Expand Down Expand Up @@ -108,6 +109,7 @@ static int usbmisc_imx25_init(struct imx_usbmisc_data *data)

static int usbmisc_imx25_post(struct imx_usbmisc_data *data)
{
struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
void __iomem *reg;
unsigned long flags;
u32 val;
Expand All @@ -130,6 +132,7 @@ static int usbmisc_imx25_post(struct imx_usbmisc_data *data)

static int usbmisc_imx27_init(struct imx_usbmisc_data *data)
{
struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
unsigned long flags;
u32 val;

Expand Down Expand Up @@ -160,6 +163,7 @@ static int usbmisc_imx27_init(struct imx_usbmisc_data *data)

static int usbmisc_imx53_init(struct imx_usbmisc_data *data)
{
struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
void __iomem *reg = NULL;
unsigned long flags;
u32 val = 0;
Expand Down Expand Up @@ -204,6 +208,7 @@ static int usbmisc_imx53_init(struct imx_usbmisc_data *data)

static int usbmisc_imx6q_init(struct imx_usbmisc_data *data)
{
struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
unsigned long flags;
u32 reg;

Expand All @@ -221,6 +226,26 @@ static int usbmisc_imx6q_init(struct imx_usbmisc_data *data)
return 0;
}

static int usbmisc_vf610_init(struct imx_usbmisc_data *data)
{
struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
u32 reg;

/*
* Vybrid only has one misc register set, but in two different
* areas. These is reflected in two instances of this driver.
*/
if (data->index >= 1)
return -EINVAL;

if (data->disable_oc) {
reg = readl(usbmisc->base);
writel(reg | VF610_OVER_CUR_DIS, usbmisc->base);
}

return 0;
}

static const struct usbmisc_ops imx25_usbmisc_ops = {
.init = usbmisc_imx25_init,
.post = usbmisc_imx25_post,
Expand All @@ -238,10 +263,14 @@ static const struct usbmisc_ops imx6q_usbmisc_ops = {
.init = usbmisc_imx6q_init,
};

static const struct usbmisc_ops vf610_usbmisc_ops = {
.init = usbmisc_vf610_init,
};

int imx_usbmisc_init(struct imx_usbmisc_data *data)
{
if (!usbmisc)
return -EPROBE_DEFER;
struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);

if (!usbmisc->ops->init)
return 0;
return usbmisc->ops->init(data);
Expand All @@ -250,8 +279,8 @@ EXPORT_SYMBOL_GPL(imx_usbmisc_init);

int imx_usbmisc_init_post(struct imx_usbmisc_data *data)
{
if (!usbmisc)
return -EPROBE_DEFER;
struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);

if (!usbmisc->ops->post)
return 0;
return usbmisc->ops->post(data);
Expand Down Expand Up @@ -283,6 +312,10 @@ static const struct of_device_id usbmisc_imx_dt_ids[] = {
.compatible = "fsl,imx6q-usbmisc",
.data = &imx6q_usbmisc_ops,
},
{
.compatible = "fsl,vf610-usbmisc",
.data = &vf610_usbmisc_ops,
},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, usbmisc_imx_dt_ids);
Expand All @@ -294,9 +327,6 @@ static int usbmisc_imx_probe(struct platform_device *pdev)
int ret;
struct of_device_id *tmp_dev;

if (usbmisc)
return -EBUSY;

data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
Expand Down Expand Up @@ -325,15 +355,15 @@ static int usbmisc_imx_probe(struct platform_device *pdev)
tmp_dev = (struct of_device_id *)
of_match_device(usbmisc_imx_dt_ids, &pdev->dev);
data->ops = (const struct usbmisc_ops *)tmp_dev->data;
usbmisc = data;
platform_set_drvdata(pdev, data);

return 0;
}

static int usbmisc_imx_remove(struct platform_device *pdev)
{
struct imx_usbmisc *usbmisc = dev_get_drvdata(&pdev->dev);
clk_disable_unprepare(usbmisc->clk);
usbmisc = NULL;
return 0;
}

Expand Down

0 comments on commit f40017e

Please sign in to comment.