From be2dbb09a014cba5691c8483ad2d0747d3eeb514 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Wed, 15 May 2013 10:51:43 +0100 Subject: usb: musb: ux500: move channel number knowledge into the driver For all ux500 based platforms the maximum number of end-points are used. Move this knowledge into the driver so we can relinquish the burden from platform data. This also removes quite a bit of complexity from the driver and will aid us when we come to enable the driver for Device Tree. Cc: linux-usb@vger.kernel.org Acked-by: Felipe Balbi Acked-by: Fabio Baltieri Signed-off-by: Lee Jones Signed-off-by: Linus Walleij --- drivers/usb/musb/ux500_dma.c | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/musb/ux500_dma.c b/drivers/usb/musb/ux500_dma.c index 338120641145..382291b91f7b 100644 --- a/drivers/usb/musb/ux500_dma.c +++ b/drivers/usb/musb/ux500_dma.c @@ -48,10 +48,8 @@ struct ux500_dma_channel { struct ux500_dma_controller { struct dma_controller controller; - struct ux500_dma_channel rx_channel[UX500_MUSB_DMA_NUM_RX_CHANNELS]; - struct ux500_dma_channel tx_channel[UX500_MUSB_DMA_NUM_TX_CHANNELS]; - u32 num_rx_channels; - u32 num_tx_channels; + struct ux500_dma_channel rx_channel[UX500_MUSB_DMA_NUM_RX_TX_CHANNELS]; + struct ux500_dma_channel tx_channel[UX500_MUSB_DMA_NUM_RX_TX_CHANNELS]; void *private_data; dma_addr_t phy_base; }; @@ -144,19 +142,15 @@ static struct dma_channel *ux500_dma_channel_allocate(struct dma_controller *c, struct ux500_dma_channel *ux500_channel = NULL; struct musb *musb = controller->private_data; u8 ch_num = hw_ep->epnum - 1; - u32 max_ch; - /* Max 8 DMA channels (0 - 7). Each DMA channel can only be allocated + /* 8 DMA channels (0 - 7). Each DMA channel can only be allocated * to specified hw_ep. For example DMA channel 0 can only be allocated * to hw_ep 1 and 9. */ if (ch_num > 7) ch_num -= 8; - max_ch = is_tx ? controller->num_tx_channels : - controller->num_rx_channels; - - if (ch_num >= max_ch) + if (ch_num >= UX500_MUSB_DMA_NUM_RX_TX_CHANNELS) return NULL; ux500_channel = is_tx ? &(controller->tx_channel[ch_num]) : @@ -264,7 +258,7 @@ static int ux500_dma_controller_stop(struct dma_controller *c) struct dma_channel *channel; u8 ch_num; - for (ch_num = 0; ch_num < controller->num_rx_channels; ch_num++) { + for (ch_num = 0; ch_num < UX500_MUSB_DMA_NUM_RX_TX_CHANNELS; ch_num++) { channel = &controller->rx_channel[ch_num].channel; ux500_channel = channel->private_data; @@ -274,7 +268,7 @@ static int ux500_dma_controller_stop(struct dma_controller *c) dma_release_channel(ux500_channel->dma_chan); } - for (ch_num = 0; ch_num < controller->num_tx_channels; ch_num++) { + for (ch_num = 0; ch_num < UX500_MUSB_DMA_NUM_RX_TX_CHANNELS; ch_num++) { channel = &controller->tx_channel[ch_num].channel; ux500_channel = channel->private_data; @@ -303,26 +297,21 @@ static int ux500_dma_controller_start(struct dma_controller *c) void **param_array; struct ux500_dma_channel *channel_array; - u32 ch_count; dma_cap_mask_t mask; - if ((data->num_rx_channels > UX500_MUSB_DMA_NUM_RX_CHANNELS) || - (data->num_tx_channels > UX500_MUSB_DMA_NUM_TX_CHANNELS)) - return -EINVAL; - controller->num_rx_channels = data->num_rx_channels; - controller->num_tx_channels = data->num_tx_channels; dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); /* Prepare the loop for RX channels */ channel_array = controller->rx_channel; - ch_count = data->num_rx_channels; param_array = data->dma_rx_param_array; for (dir = 0; dir < 2; dir++) { - for (ch_num = 0; ch_num < ch_count; ch_num++) { + for (ch_num = 0; + ch_num < UX500_MUSB_DMA_NUM_RX_TX_CHANNELS; + ch_num++) { ux500_channel = &channel_array[ch_num]; ux500_channel->controller = controller; ux500_channel->ch_num = ch_num; @@ -350,7 +339,6 @@ static int ux500_dma_controller_start(struct dma_controller *c) /* Prepare the loop for TX channels */ channel_array = controller->tx_channel; - ch_count = data->num_tx_channels; param_array = data->dma_tx_param_array; is_tx = 1; } -- cgit v1.2.3 From a20b1b791e42d84dedd5854b60abb841ec1a7585 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Wed, 15 May 2013 10:51:44 +0100 Subject: usb: musb: ux500: move the MUSB HDRC configuration into the driver The MUSB HDRC configuration never changes between each of the ux500 supported platforms, so there's little point passing it though platform data. If we set it in the driver instead, we can make good use of it when booting with either ATAGs or Device Tree. Cc: linux-usb@vger.kernel.org Acked-by: Felipe Balbi Acked-by: Fabio Baltieri Signed-off-by: Lee Jones Signed-off-by: Linus Walleij --- arch/arm/mach-ux500/usb.c | 8 -------- drivers/usb/musb/ux500.c | 8 ++++++++ 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/usb') diff --git a/arch/arm/mach-ux500/usb.c b/arch/arm/mach-ux500/usb.c index a21c2e1b7333..49d6e571f5af 100644 --- a/arch/arm/mach-ux500/usb.c +++ b/arch/arm/mach-ux500/usb.c @@ -76,16 +76,8 @@ static struct ux500_musb_board_data musb_board_data = { static u64 ux500_musb_dmamask = DMA_BIT_MASK(32); -static struct musb_hdrc_config musb_hdrc_config = { - .multipoint = true, - .dyn_fifo = true, - .num_eps = 16, - .ram_bits = 16, -}; - static struct musb_hdrc_platform_data musb_platform_data = { .mode = MUSB_OTG, - .config = &musb_hdrc_config, .board_data = &musb_board_data, }; diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c index 2c80004e0a83..371776f76ba2 100644 --- a/drivers/usb/musb/ux500.c +++ b/drivers/usb/musb/ux500.c @@ -30,6 +30,13 @@ #include "musb_core.h" +static struct musb_hdrc_config ux500_musb_hdrc_config = { + .multipoint = true, + .dyn_fifo = true, + .num_eps = 16, + .ram_bits = 16, +}; + struct ux500_glue { struct device *dev; struct platform_device *musb; @@ -229,6 +236,7 @@ static int ux500_probe(struct platform_device *pdev) glue->clk = clk; pdata->platform_ops = &ux500_ops; + pdata->config = &ux500_musb_hdrc_config; platform_set_drvdata(pdev, glue); -- cgit v1.2.3 From 1e6eebb4e907548d53347a6e90769feb3d73e9da Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Wed, 15 May 2013 10:51:45 +0100 Subject: usb: musb: ux500: take the dma_mask from coherent_dma_mask The dma_mask will always be the same as the coherent_dma_mask, so let's cut down on the platform_data burden and set it as such in the driver. This also saves us from supporting it separately when we come to enable this driver for Device Tree. Cc: linux-usb@vger.kernel.org Acked-by: Felipe Balbi Acked-by: Fabio Baltieri Signed-off-by: Lee Jones Signed-off-by: Linus Walleij --- arch/arm/mach-ux500/usb.c | 3 --- drivers/usb/musb/ux500.c | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/usb') diff --git a/arch/arm/mach-ux500/usb.c b/arch/arm/mach-ux500/usb.c index 49d6e571f5af..2f9abe99dfaa 100644 --- a/arch/arm/mach-ux500/usb.c +++ b/arch/arm/mach-ux500/usb.c @@ -74,8 +74,6 @@ static struct ux500_musb_board_data musb_board_data = { .dma_filter = stedma40_filter, }; -static u64 ux500_musb_dmamask = DMA_BIT_MASK(32); - static struct musb_hdrc_platform_data musb_platform_data = { .mode = MUSB_OTG, .board_data = &musb_board_data, @@ -98,7 +96,6 @@ struct platform_device ux500_musb_device = { .id = 0, .dev = { .platform_data = &musb_platform_data, - .dma_mask = &ux500_musb_dmamask, .coherent_dma_mask = DMA_BIT_MASK(32), }, .num_resources = ARRAY_SIZE(usb_resources), diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c index 371776f76ba2..3cf10bcaf118 100644 --- a/drivers/usb/musb/ux500.c +++ b/drivers/usb/musb/ux500.c @@ -228,7 +228,7 @@ static int ux500_probe(struct platform_device *pdev) } musb->dev.parent = &pdev->dev; - musb->dev.dma_mask = pdev->dev.dma_mask; + musb->dev.dma_mask = &pdev->dev.coherent_dma_mask; musb->dev.coherent_dma_mask = pdev->dev.coherent_dma_mask; glue->dev = &pdev->dev; -- cgit v1.2.3 From 5f6091a023ca435c49467348e388fa89e635436a Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Wed, 15 May 2013 10:51:46 +0100 Subject: usb: musb: ux500: harden checks for platform data In its current state, the ux500-musb driver uses platform data pointers blindly with no prior checking. If no platform data pointer is passed this will Oops the kernel. In this patch we ensure platform data and board data are present prior to using them. Cc: linux-usb@vger.kernel.org Acked-by: Felipe Balbi Acked-by: Fabio Baltieri Signed-off-by: Lee Jones Signed-off-by: Linus Walleij --- drivers/usb/musb/ux500_dma.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/musb/ux500_dma.c b/drivers/usb/musb/ux500_dma.c index 382291b91f7b..4bd5400e0395 100644 --- a/drivers/usb/musb/ux500_dma.c +++ b/drivers/usb/musb/ux500_dma.c @@ -289,7 +289,7 @@ static int ux500_dma_controller_start(struct dma_controller *c) struct musb *musb = controller->private_data; struct device *dev = musb->controller; struct musb_hdrc_platform_data *plat = dev->platform_data; - struct ux500_musb_board_data *data = plat->board_data; + struct ux500_musb_board_data *data; struct dma_channel *dma_channel = NULL; u32 ch_num; u8 dir; @@ -299,14 +299,19 @@ static int ux500_dma_controller_start(struct dma_controller *c) struct ux500_dma_channel *channel_array; dma_cap_mask_t mask; + if (!plat) { + dev_err(musb->controller, "No platform data\n"); + return -EINVAL; + } + data = plat->board_data; dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); /* Prepare the loop for RX channels */ channel_array = controller->rx_channel; - param_array = data->dma_rx_param_array; + param_array = data ? data->dma_rx_param_array : NULL; for (dir = 0; dir < 2; dir++) { for (ch_num = 0; @@ -339,7 +344,7 @@ static int ux500_dma_controller_start(struct dma_controller *c) /* Prepare the loop for TX channels */ channel_array = controller->tx_channel; - param_array = data->dma_tx_param_array; + param_array = data ? data->dma_tx_param_array : NULL; is_tx = 1; } -- cgit v1.2.3 From 2968da0b2c7297a29d49c7084d6865c2cf627093 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Wed, 15 May 2013 10:51:47 +0100 Subject: usb: musb: ux500: attempt to find channels by name before using pdata If we can ever get to a state where we can solely search for DMA channels by name, this will almost completely alleviate the requirement to pass copious amounts of information though platform data. Here we take the first step towards this. The next step will be to enable Device Tree complete with name<->event_line mapping. Cc: linux-usb@vger.kernel.org Acked-by: Felipe Balbi Acked-by: Fabio Baltieri Signed-off-by: Lee Jones Signed-off-by: Linus Walleij --- drivers/usb/musb/ux500_dma.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/musb/ux500_dma.c b/drivers/usb/musb/ux500_dma.c index 4bd5400e0395..7d80699a5ff7 100644 --- a/drivers/usb/musb/ux500_dma.c +++ b/drivers/usb/musb/ux500_dma.c @@ -34,6 +34,11 @@ #include #include "musb_core.h" +static const char *iep_chan_names[] = { "iep_1_9", "iep_2_10", "iep_3_11", "iep_4_12", + "iep_5_13", "iep_6_14", "iep_7_15", "iep_8" }; +static const char *oep_chan_names[] = { "oep_1_9", "oep_2_10", "oep_3_11", "oep_4_12", + "oep_5_13", "oep_6_14", "oep_7_15", "oep_8" }; + struct ux500_dma_channel { struct dma_channel channel; struct ux500_dma_controller *controller; @@ -291,6 +296,7 @@ static int ux500_dma_controller_start(struct dma_controller *c) struct musb_hdrc_platform_data *plat = dev->platform_data; struct ux500_musb_board_data *data; struct dma_channel *dma_channel = NULL; + char **chan_names; u32 ch_num; u8 dir; u8 is_tx = 0; @@ -312,6 +318,7 @@ static int ux500_dma_controller_start(struct dma_controller *c) /* Prepare the loop for RX channels */ channel_array = controller->rx_channel; param_array = data ? data->dma_rx_param_array : NULL; + chan_names = (char **)iep_chan_names; for (dir = 0; dir < 2; dir++) { for (ch_num = 0; @@ -327,9 +334,15 @@ static int ux500_dma_controller_start(struct dma_controller *c) dma_channel->status = MUSB_DMA_STATUS_FREE; dma_channel->max_len = SZ_16M; - ux500_channel->dma_chan = dma_request_channel(mask, - data->dma_filter, - param_array[ch_num]); + ux500_channel->dma_chan = + dma_request_slave_channel(dev, chan_names[ch_num]); + + if (!ux500_channel->dma_chan) + ux500_channel->dma_chan = + dma_request_channel(mask, + data->dma_filter, + param_array[ch_num]); + if (!ux500_channel->dma_chan) { ERR("Dma pipe allocation error dir=%d ch=%d\n", dir, ch_num); @@ -345,6 +358,7 @@ static int ux500_dma_controller_start(struct dma_controller *c) /* Prepare the loop for TX channels */ channel_array = controller->tx_channel; param_array = data ? data->dma_tx_param_array : NULL; + chan_names = (char **)oep_chan_names; is_tx = 1; } -- cgit v1.2.3 From 313bdb11e52a301aa7f6f8729a87ff0908785163 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Wed, 15 May 2013 10:51:48 +0100 Subject: usb: musb: ux500: add device tree probing support This patch will allow ux500-musb to be probed and configured solely from configuration found in Device Tree. Cc: Rob Herring Cc: linux-usb@vger.kernel.org Cc: devicetree-discuss@lists.ozlabs.org Acked-by: Felipe Balbi Acked-by: Fabio Baltieri Signed-off-by: Lee Jones Signed-off-by: Linus Walleij --- .../devicetree/bindings/usb/ux500-usb.txt | 50 +++++++++++++++++++++ drivers/usb/musb/ux500.c | 51 ++++++++++++++++++++++ 2 files changed, 101 insertions(+) create mode 100644 Documentation/devicetree/bindings/usb/ux500-usb.txt (limited to 'drivers/usb') diff --git a/Documentation/devicetree/bindings/usb/ux500-usb.txt b/Documentation/devicetree/bindings/usb/ux500-usb.txt new file mode 100644 index 000000000000..330d6ec15401 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/ux500-usb.txt @@ -0,0 +1,50 @@ +Ux500 MUSB + +Required properties: + - compatible : Should be "stericsson,db8500-musb" + - reg : Offset and length of registers + - interrupts : Interrupt; mode, number and trigger + - dr_mode : Dual-role; either host mode "host", peripheral mode "peripheral" + or both "otg" + +Optional properties: + - dmas : A list of dma channels; + dma-controller, event-line, fixed-channel, flags + - dma-names : An ordered list of channel names affiliated to the above + +Example: + +usb_per5@a03e0000 { + compatible = "stericsson,db8500-musb", "mentor,musb"; + reg = <0xa03e0000 0x10000>; + interrupts = <0 23 0x4>; + interrupt-names = "mc"; + + dr_mode = "otg"; + + dmas = <&dma 38 0 0x2>, /* Logical - DevToMem */ + <&dma 38 0 0x0>, /* Logical - MemToDev */ + <&dma 37 0 0x2>, /* Logical - DevToMem */ + <&dma 37 0 0x0>, /* Logical - MemToDev */ + <&dma 36 0 0x2>, /* Logical - DevToMem */ + <&dma 36 0 0x0>, /* Logical - MemToDev */ + <&dma 19 0 0x2>, /* Logical - DevToMem */ + <&dma 19 0 0x0>, /* Logical - MemToDev */ + <&dma 18 0 0x2>, /* Logical - DevToMem */ + <&dma 18 0 0x0>, /* Logical - MemToDev */ + <&dma 17 0 0x2>, /* Logical - DevToMem */ + <&dma 17 0 0x0>, /* Logical - MemToDev */ + <&dma 16 0 0x2>, /* Logical - DevToMem */ + <&dma 16 0 0x0>, /* Logical - MemToDev */ + <&dma 39 0 0x2>, /* Logical - DevToMem */ + <&dma 39 0 0x0>; /* Logical - MemToDev */ + + dma-names = "iep_1_9", "oep_1_9", + "iep_2_10", "oep_2_10", + "iep_3_11", "oep_3_11", + "iep_4_12", "oep_4_12", + "iep_5_13", "oep_5_13", + "iep_6_14", "oep_6_14", + "iep_7_15", "oep_7_15", + "iep_8", "oep_8"; +}; diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c index 3cf10bcaf118..f0beee7b868e 100644 --- a/drivers/usb/musb/ux500.c +++ b/drivers/usb/musb/ux500.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -194,14 +195,57 @@ static const struct musb_platform_ops ux500_ops = { .set_vbus = ux500_musb_set_vbus, }; +static struct musb_hdrc_platform_data * +ux500_of_probe(struct platform_device *pdev, struct device_node *np) +{ + struct musb_hdrc_platform_data *pdata; + const char *mode; + int strlen; + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return NULL; + + mode = of_get_property(np, "dr_mode", &strlen); + if (!mode) { + dev_err(&pdev->dev, "No 'dr_mode' property found\n"); + return NULL; + } + + if (strlen > 0) { + if (!strcmp(mode, "host")) + pdata->mode = MUSB_HOST; + if (!strcmp(mode, "otg")) + pdata->mode = MUSB_OTG; + if (!strcmp(mode, "peripheral")) + pdata->mode = MUSB_PERIPHERAL; + } + + return pdata; +} + static int ux500_probe(struct platform_device *pdev) { struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data; + struct device_node *np = pdev->dev.of_node; struct platform_device *musb; struct ux500_glue *glue; struct clk *clk; int ret = -ENOMEM; + if (!pdata) { + if (np) { + pdata = ux500_of_probe(pdev, np); + if (!pdata) + goto err0; + + pdev->dev.platform_data = pdata; + } else { + dev_err(&pdev->dev, "no pdata or device tree found\n"); + goto err0; + } + } + glue = kzalloc(sizeof(*glue), GFP_KERNEL); if (!glue) { dev_err(&pdev->dev, "failed to allocate glue context\n"); @@ -230,6 +274,7 @@ static int ux500_probe(struct platform_device *pdev) musb->dev.parent = &pdev->dev; musb->dev.dma_mask = &pdev->dev.coherent_dma_mask; musb->dev.coherent_dma_mask = pdev->dev.coherent_dma_mask; + musb->dev.of_node = pdev->dev.of_node; glue->dev = &pdev->dev; glue->musb = musb; @@ -328,12 +373,18 @@ static const struct dev_pm_ops ux500_pm_ops = { #define DEV_PM_OPS NULL #endif +static const struct of_device_id ux500_match[] = { + { .compatible = "stericsson,db8500-musb", }, + {} +}; + static struct platform_driver ux500_driver = { .probe = ux500_probe, .remove = ux500_remove, .driver = { .name = "musb-ux500", .pm = DEV_PM_OPS, + .of_match_table = ux500_match, }, }; -- cgit v1.2.3