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/platform_device.h> 14 #include <linux/usb/usb_phy_generic.h> 15 16 #include "musb_core.h" 17 18 struct jz4740_glue { 19 struct device *dev; 20 struct platform_device *musb; 21 struct clk *clk; 22 }; 23 24 static irqreturn_t jz4740_musb_interrupt(int irq, void *__hci) 25 { 26 unsigned long flags; 27 irqreturn_t retval = IRQ_NONE; 28 struct musb *musb = __hci; 29 30 spin_lock_irqsave(&musb->lock, flags); 31 32 musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB); 33 musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX); 34 musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX); 35 36 /* 37 * The controller is gadget only, the state of the host mode IRQ bits is 38 * undefined. Mask them to make sure that the musb driver core will 39 * never see them set 40 */ 41 musb->int_usb &= MUSB_INTR_SUSPEND | MUSB_INTR_RESUME | 42 MUSB_INTR_RESET | MUSB_INTR_SOF; 43 44 if (musb->int_usb || musb->int_tx || musb->int_rx) 45 retval = musb_interrupt(musb); 46 47 spin_unlock_irqrestore(&musb->lock, flags); 48 49 return retval; 50 } 51 52 static struct musb_fifo_cfg jz4740_musb_fifo_cfg[] = { 53 { .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, }, 54 { .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, }, 55 { .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 64, }, 56 }; 57 58 static const struct musb_hdrc_config jz4740_musb_config = { 59 /* Silicon does not implement USB OTG. */ 60 .multipoint = 0, 61 /* Max EPs scanned, driver will decide which EP can be used. */ 62 .num_eps = 4, 63 /* RAMbits needed to configure EPs from table */ 64 .ram_bits = 9, 65 .fifo_cfg = jz4740_musb_fifo_cfg, 66 .fifo_cfg_size = ARRAY_SIZE(jz4740_musb_fifo_cfg), 67 }; 68 69 static struct musb_hdrc_platform_data jz4740_musb_platform_data = { 70 .mode = MUSB_PERIPHERAL, 71 .config = &jz4740_musb_config, 72 }; 73 74 static int jz4740_musb_init(struct musb *musb) 75 { 76 usb_phy_generic_register(); 77 musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2); 78 if (IS_ERR(musb->xceiv)) { 79 pr_err("HS UDC: no transceiver configured\n"); 80 return PTR_ERR(musb->xceiv); 81 } 82 83 /* Silicon does not implement ConfigData register. 84 * Set dyn_fifo to avoid reading EP config from hardware. 85 */ 86 musb->dyn_fifo = true; 87 88 musb->isr = jz4740_musb_interrupt; 89 90 return 0; 91 } 92 93 static int jz4740_musb_exit(struct musb *musb) 94 { 95 usb_put_phy(musb->xceiv); 96 97 return 0; 98 } 99 100 /* 101 * DMA has not been confirmed to work with CONFIG_USB_INVENTRA_DMA, 102 * so let's not set up the dma function pointers yet. 103 */ 104 static const struct musb_platform_ops jz4740_musb_ops = { 105 .quirks = MUSB_DMA_INVENTRA | MUSB_INDEXED_EP, 106 .fifo_mode = 2, 107 .init = jz4740_musb_init, 108 .exit = jz4740_musb_exit, 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 usb_phy_generic_unregister(pdev); 186 clk_disable_unprepare(glue->clk); 187 188 return 0; 189 } 190 191 static struct platform_driver jz4740_driver = { 192 .probe = jz4740_probe, 193 .remove = jz4740_remove, 194 .driver = { 195 .name = "musb-jz4740", 196 }, 197 }; 198 199 MODULE_DESCRIPTION("JZ4740 MUSB Glue Layer"); 200 MODULE_AUTHOR("Apelete Seketeli <apelete@seketeli.net>"); 201 MODULE_LICENSE("GPL v2"); 202 module_platform_driver(jz4740_driver); 203