root/drivers/usb/musb/jz4740.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. jz4740_musb_interrupt
  2. jz4740_musb_init
  3. jz4740_probe
  4. jz4740_remove

   1 // SPDX-License-Identifier: GPL-2.0+
   2 /*
   3  * Ingenic JZ4740 "glue layer"
   4  *
   5  * Copyright (C) 2013, Apelete Seketeli <apelete@seketeli.net>
   6  */
   7 
   8 #include <linux/clk.h>
   9 #include <linux/dma-mapping.h>
  10 #include <linux/errno.h>
  11 #include <linux/kernel.h>
  12 #include <linux/module.h>
  13 #include <linux/of_device.h>
  14 #include <linux/platform_device.h>
  15 #include <linux/usb/usb_phy_generic.h>
  16 
  17 #include "musb_core.h"
  18 
  19 struct jz4740_glue {
  20         struct device           *dev;
  21         struct platform_device  *musb;
  22         struct clk              *clk;
  23 };
  24 
  25 static irqreturn_t jz4740_musb_interrupt(int irq, void *__hci)
  26 {
  27         unsigned long   flags;
  28         irqreturn_t     retval = IRQ_NONE;
  29         struct musb     *musb = __hci;
  30 
  31         spin_lock_irqsave(&musb->lock, flags);
  32 
  33         musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB);
  34         musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX);
  35         musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX);
  36 
  37         /*
  38          * The controller is gadget only, the state of the host mode IRQ bits is
  39          * undefined. Mask them to make sure that the musb driver core will
  40          * never see them set
  41          */
  42         musb->int_usb &= MUSB_INTR_SUSPEND | MUSB_INTR_RESUME |
  43             MUSB_INTR_RESET | MUSB_INTR_SOF;
  44 
  45         if (musb->int_usb || musb->int_tx || musb->int_rx)
  46                 retval = musb_interrupt(musb);
  47 
  48         spin_unlock_irqrestore(&musb->lock, flags);
  49 
  50         return retval;
  51 }
  52 
  53 static struct musb_fifo_cfg jz4740_musb_fifo_cfg[] = {
  54 { .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, },
  55 { .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, },
  56 { .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 64, },
  57 };
  58 
  59 static const struct musb_hdrc_config jz4740_musb_config = {
  60         /* Silicon does not implement USB OTG. */
  61         .multipoint = 0,
  62         /* Max EPs scanned, driver will decide which EP can be used. */
  63         .num_eps    = 4,
  64         /* RAMbits needed to configure EPs from table */
  65         .ram_bits   = 9,
  66         .fifo_cfg = jz4740_musb_fifo_cfg,
  67         .fifo_cfg_size = ARRAY_SIZE(jz4740_musb_fifo_cfg),
  68 };
  69 
  70 static struct musb_hdrc_platform_data jz4740_musb_platform_data = {
  71         .mode   = MUSB_PERIPHERAL,
  72         .config = &jz4740_musb_config,
  73 };
  74 
  75 static int jz4740_musb_init(struct musb *musb)
  76 {
  77         struct device *dev = musb->controller->parent;
  78         int err;
  79 
  80         if (dev->of_node)
  81                 musb->xceiv = devm_usb_get_phy_by_phandle(dev, "phys", 0);
  82         else
  83                 musb->xceiv = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
  84         if (IS_ERR(musb->xceiv)) {
  85                 err = PTR_ERR(musb->xceiv);
  86                 if (err != -EPROBE_DEFER)
  87                         dev_err(dev, "No transceiver configured: %d", err);
  88                 return err;
  89         }
  90 
  91         /* Silicon does not implement ConfigData register.
  92          * Set dyn_fifo to avoid reading EP config from hardware.
  93          */
  94         musb->dyn_fifo = true;
  95 
  96         musb->isr = jz4740_musb_interrupt;
  97 
  98         return 0;
  99 }
 100 
 101 /*
 102  * DMA has not been confirmed to work with CONFIG_USB_INVENTRA_DMA,
 103  * so let's not set up the dma function pointers yet.
 104  */
 105 static const struct musb_platform_ops jz4740_musb_ops = {
 106         .quirks         = MUSB_DMA_INVENTRA | MUSB_INDEXED_EP,
 107         .fifo_mode      = 2,
 108         .init           = jz4740_musb_init,
 109 };
 110 
 111 static int jz4740_probe(struct platform_device *pdev)
 112 {
 113         struct musb_hdrc_platform_data  *pdata = &jz4740_musb_platform_data;
 114         struct platform_device          *musb;
 115         struct jz4740_glue              *glue;
 116         struct clk                      *clk;
 117         int                             ret;
 118 
 119         glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL);
 120         if (!glue)
 121                 return -ENOMEM;
 122 
 123         musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO);
 124         if (!musb) {
 125                 dev_err(&pdev->dev, "failed to allocate musb device\n");
 126                 return -ENOMEM;
 127         }
 128 
 129         clk = devm_clk_get(&pdev->dev, "udc");
 130         if (IS_ERR(clk)) {
 131                 dev_err(&pdev->dev, "failed to get clock\n");
 132                 ret = PTR_ERR(clk);
 133                 goto err_platform_device_put;
 134         }
 135 
 136         ret = clk_prepare_enable(clk);
 137         if (ret) {
 138                 dev_err(&pdev->dev, "failed to enable clock\n");
 139                 goto err_platform_device_put;
 140         }
 141 
 142         musb->dev.parent                = &pdev->dev;
 143 
 144         glue->dev                       = &pdev->dev;
 145         glue->musb                      = musb;
 146         glue->clk                       = clk;
 147 
 148         pdata->platform_ops             = &jz4740_musb_ops;
 149 
 150         platform_set_drvdata(pdev, glue);
 151 
 152         ret = platform_device_add_resources(musb, pdev->resource,
 153                                             pdev->num_resources);
 154         if (ret) {
 155                 dev_err(&pdev->dev, "failed to add resources\n");
 156                 goto err_clk_disable;
 157         }
 158 
 159         ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
 160         if (ret) {
 161                 dev_err(&pdev->dev, "failed to add platform_data\n");
 162                 goto err_clk_disable;
 163         }
 164 
 165         ret = platform_device_add(musb);
 166         if (ret) {
 167                 dev_err(&pdev->dev, "failed to register musb device\n");
 168                 goto err_clk_disable;
 169         }
 170 
 171         return 0;
 172 
 173 err_clk_disable:
 174         clk_disable_unprepare(clk);
 175 err_platform_device_put:
 176         platform_device_put(musb);
 177         return ret;
 178 }
 179 
 180 static int jz4740_remove(struct platform_device *pdev)
 181 {
 182         struct jz4740_glue      *glue = platform_get_drvdata(pdev);
 183 
 184         platform_device_unregister(glue->musb);
 185         clk_disable_unprepare(glue->clk);
 186 
 187         return 0;
 188 }
 189 
 190 #ifdef CONFIG_OF
 191 static const struct of_device_id jz4740_musb_of_match[] = {
 192         { .compatible = "ingenic,jz4740-musb" },
 193         {},
 194 };
 195 MODULE_DEVICE_TABLE(of, jz4740_musb_of_match);
 196 #endif
 197 
 198 static struct platform_driver jz4740_driver = {
 199         .probe          = jz4740_probe,
 200         .remove         = jz4740_remove,
 201         .driver         = {
 202                 .name   = "musb-jz4740",
 203                 .of_match_table = of_match_ptr(jz4740_musb_of_match),
 204         },
 205 };
 206 
 207 MODULE_DESCRIPTION("JZ4740 MUSB Glue Layer");
 208 MODULE_AUTHOR("Apelete Seketeli <apelete@seketeli.net>");
 209 MODULE_LICENSE("GPL v2");
 210 module_platform_driver(jz4740_driver);

/* [<][>][^][v][top][bottom][index][help] */