1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * SDIO interface. 4 * 5 * Copyright (c) 2017-2020, Silicon Laboratories, Inc. 6 * Copyright (c) 2010, ST-Ericsson 7 */ 8 #include <linux/module.h> 9 #include <linux/mmc/sdio.h> 10 #include <linux/mmc/sdio_func.h> 11 #include <linux/mmc/card.h> 12 #include <linux/interrupt.h> 13 #include <linux/of.h> 14 #include <linux/of_irq.h> 15 #include <linux/irq.h> 16 #include <linux/align.h> 17 #include <linux/pm.h> 18 19 #include "bus.h" 20 #include "wfx.h" 21 #include "hwio.h" 22 #include "main.h" 23 #include "bh.h" 24 25 static const struct wfx_platform_data pdata_wf200 = { 26 .file_fw = "wfx/wfm_wf200", 27 .file_pds = "wfx/wf200.pds", 28 }; 29 30 static const struct wfx_platform_data pdata_brd4001a = { 31 .file_fw = "wfx/wfm_wf200", 32 .file_pds = "wfx/brd4001a.pds", 33 }; 34 35 static const struct wfx_platform_data pdata_brd8022a = { 36 .file_fw = "wfx/wfm_wf200", 37 .file_pds = "wfx/brd8022a.pds", 38 }; 39 40 static const struct wfx_platform_data pdata_brd8023a = { 41 .file_fw = "wfx/wfm_wf200", 42 .file_pds = "wfx/brd8023a.pds", 43 }; 44 45 struct wfx_sdio_priv { 46 struct sdio_func *func; 47 struct wfx_dev *core; 48 u8 buf_id_tx; 49 u8 buf_id_rx; 50 int of_irq; 51 }; 52 53 static int wfx_sdio_copy_from_io(void *priv, unsigned int reg_id, void *dst, size_t count) 54 { 55 struct wfx_sdio_priv *bus = priv; 56 unsigned int sdio_addr = reg_id << 2; 57 int ret; 58 59 WARN(reg_id > 7, "chip only has 7 registers"); 60 WARN(!IS_ALIGNED((uintptr_t)dst, 4), "unaligned buffer address"); 61 WARN(!IS_ALIGNED(count, 4), "unaligned buffer size"); 62 63 /* Use queue mode buffers */ 64 if (reg_id == WFX_REG_IN_OUT_QUEUE) 65 sdio_addr |= (bus->buf_id_rx + 1) << 7; 66 ret = sdio_memcpy_fromio(bus->func, dst, sdio_addr, count); 67 if (!ret && reg_id == WFX_REG_IN_OUT_QUEUE) 68 bus->buf_id_rx = (bus->buf_id_rx + 1) % 4; 69 70 return ret; 71 } 72 73 static int wfx_sdio_copy_to_io(void *priv, unsigned int reg_id, const void *src, size_t count) 74 { 75 struct wfx_sdio_priv *bus = priv; 76 unsigned int sdio_addr = reg_id << 2; 77 int ret; 78 79 WARN(reg_id > 7, "chip only has 7 registers"); 80 WARN(!IS_ALIGNED((uintptr_t)src, 4), "unaligned buffer address"); 81 WARN(!IS_ALIGNED(count, 4), "unaligned buffer size"); 82 83 /* Use queue mode buffers */ 84 if (reg_id == WFX_REG_IN_OUT_QUEUE) 85 sdio_addr |= bus->buf_id_tx << 7; 86 /* FIXME: discards 'const' qualifier for src */ 87 ret = sdio_memcpy_toio(bus->func, sdio_addr, (void *)src, count); 88 if (!ret && reg_id == WFX_REG_IN_OUT_QUEUE) 89 bus->buf_id_tx = (bus->buf_id_tx + 1) % 32; 90 91 return ret; 92 } 93 94 static void wfx_sdio_lock(void *priv) 95 { 96 struct wfx_sdio_priv *bus = priv; 97 98 sdio_claim_host(bus->func); 99 } 100 101 static void wfx_sdio_unlock(void *priv) 102 { 103 struct wfx_sdio_priv *bus = priv; 104 105 sdio_release_host(bus->func); 106 } 107 108 static void wfx_sdio_irq_handler(struct sdio_func *func) 109 { 110 struct wfx_sdio_priv *bus = sdio_get_drvdata(func); 111 112 wfx_bh_request_rx(bus->core); 113 } 114 115 static irqreturn_t wfx_sdio_irq_handler_ext(int irq, void *priv) 116 { 117 struct wfx_sdio_priv *bus = priv; 118 119 sdio_claim_host(bus->func); 120 wfx_bh_request_rx(bus->core); 121 sdio_release_host(bus->func); 122 return IRQ_HANDLED; 123 } 124 125 static int wfx_sdio_irq_subscribe(void *priv) 126 { 127 struct wfx_sdio_priv *bus = priv; 128 u32 flags; 129 int ret; 130 u8 cccr; 131 132 if (!bus->of_irq) { 133 sdio_claim_host(bus->func); 134 ret = sdio_claim_irq(bus->func, wfx_sdio_irq_handler); 135 sdio_release_host(bus->func); 136 return ret; 137 } 138 139 flags = irq_get_trigger_type(bus->of_irq); 140 if (!flags) 141 flags = IRQF_TRIGGER_HIGH; 142 flags |= IRQF_ONESHOT; 143 ret = devm_request_threaded_irq(&bus->func->dev, bus->of_irq, NULL, 144 wfx_sdio_irq_handler_ext, flags, "wfx", bus); 145 if (ret) 146 return ret; 147 sdio_claim_host(bus->func); 148 cccr = sdio_f0_readb(bus->func, SDIO_CCCR_IENx, NULL); 149 cccr |= BIT(0); 150 cccr |= BIT(bus->func->num); 151 sdio_f0_writeb(bus->func, cccr, SDIO_CCCR_IENx, NULL); 152 sdio_release_host(bus->func); 153 return 0; 154 } 155 156 static int wfx_sdio_irq_unsubscribe(void *priv) 157 { 158 struct wfx_sdio_priv *bus = priv; 159 int ret; 160 161 if (bus->of_irq) 162 devm_free_irq(&bus->func->dev, bus->of_irq, bus); 163 sdio_claim_host(bus->func); 164 ret = sdio_release_irq(bus->func); 165 sdio_release_host(bus->func); 166 return ret; 167 } 168 169 static size_t wfx_sdio_align_size(void *priv, size_t size) 170 { 171 struct wfx_sdio_priv *bus = priv; 172 173 return sdio_align_size(bus->func, size); 174 } 175 176 static void wfx_sdio_set_wakeup(void *priv, bool enabled) 177 { 178 struct wfx_sdio_priv *bus = priv; 179 180 device_set_wakeup_enable(&bus->func->dev, enabled); 181 } 182 183 static const struct wfx_hwbus_ops wfx_sdio_hwbus_ops = { 184 .copy_from_io = wfx_sdio_copy_from_io, 185 .copy_to_io = wfx_sdio_copy_to_io, 186 .irq_subscribe = wfx_sdio_irq_subscribe, 187 .irq_unsubscribe = wfx_sdio_irq_unsubscribe, 188 .lock = wfx_sdio_lock, 189 .unlock = wfx_sdio_unlock, 190 .align_size = wfx_sdio_align_size, 191 .set_wakeup = wfx_sdio_set_wakeup, 192 }; 193 194 static const struct of_device_id wfx_sdio_of_match[] = { 195 { .compatible = "silabs,wf200", .data = &pdata_wf200 }, 196 { .compatible = "silabs,brd4001a", .data = &pdata_brd4001a }, 197 { .compatible = "silabs,brd8022a", .data = &pdata_brd8022a }, 198 { .compatible = "silabs,brd8023a", .data = &pdata_brd8023a }, 199 { }, 200 }; 201 MODULE_DEVICE_TABLE(of, wfx_sdio_of_match); 202 203 static int wfx_sdio_suspend(struct device *dev) 204 { 205 struct sdio_func *func = dev_to_sdio_func(dev); 206 struct wfx_sdio_priv *bus = sdio_get_drvdata(func); 207 int ret; 208 209 if (!device_may_wakeup(dev)) 210 return 0; 211 212 flush_work(&bus->core->hif.bh); 213 /* Either "wakeup-source" attribute or out-of-band IRQ is required for 214 * WoWLAN 215 */ 216 if (bus->of_irq) { 217 ret = enable_irq_wake(bus->of_irq); 218 if (ret) 219 return ret; 220 } else { 221 ret = sdio_set_host_pm_flags(func, MMC_PM_WAKE_SDIO_IRQ); 222 if (ret) 223 return ret; 224 } 225 return sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); 226 } 227 228 static int wfx_sdio_resume(struct device *dev) 229 { 230 struct sdio_func *func = dev_to_sdio_func(dev); 231 struct wfx_sdio_priv *bus = sdio_get_drvdata(func); 232 233 if (!device_may_wakeup(dev)) 234 return 0; 235 if (bus->of_irq) 236 return disable_irq_wake(bus->of_irq); 237 else 238 return 0; 239 } 240 241 static int wfx_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) 242 { 243 const struct wfx_platform_data *pdata = of_device_get_match_data(&func->dev); 244 mmc_pm_flag_t pm_flag = sdio_get_host_pm_caps(func); 245 struct device_node *np = func->dev.of_node; 246 struct wfx_sdio_priv *bus; 247 int ret; 248 249 if (func->num != 1) { 250 dev_err(&func->dev, "SDIO function number is %d while it should always be 1 (unsupported chip?)\n", 251 func->num); 252 return -ENODEV; 253 } 254 255 if (!pdata) { 256 dev_warn(&func->dev, "no compatible device found in DT\n"); 257 return -ENODEV; 258 } 259 260 bus = devm_kzalloc(&func->dev, sizeof(*bus), GFP_KERNEL); 261 if (!bus) 262 return -ENOMEM; 263 264 bus->func = func; 265 bus->of_irq = irq_of_parse_and_map(np, 0); 266 sdio_set_drvdata(func, bus); 267 268 sdio_claim_host(func); 269 ret = sdio_enable_func(func); 270 /* Block of 64 bytes is more efficient than 512B for frame sizes < 4k */ 271 sdio_set_block_size(func, 64); 272 sdio_release_host(func); 273 if (ret) 274 return ret; 275 276 bus->core = wfx_init_common(&func->dev, pdata, &wfx_sdio_hwbus_ops, bus); 277 if (!bus->core) { 278 ret = -EIO; 279 goto sdio_release; 280 } 281 282 ret = wfx_probe(bus->core); 283 if (ret) 284 goto sdio_release; 285 286 if (pm_flag & MMC_PM_KEEP_POWER) 287 device_set_wakeup_capable(&func->dev, true); 288 289 return 0; 290 291 sdio_release: 292 sdio_claim_host(func); 293 sdio_disable_func(func); 294 sdio_release_host(func); 295 return ret; 296 } 297 298 static void wfx_sdio_remove(struct sdio_func *func) 299 { 300 struct wfx_sdio_priv *bus = sdio_get_drvdata(func); 301 302 wfx_release(bus->core); 303 sdio_claim_host(func); 304 sdio_disable_func(func); 305 sdio_release_host(func); 306 } 307 308 static const struct sdio_device_id wfx_sdio_ids[] = { 309 /* WF200 does not have official VID/PID */ 310 { SDIO_DEVICE(0x0000, 0x1000) }, 311 { }, 312 }; 313 MODULE_DEVICE_TABLE(sdio, wfx_sdio_ids); 314 315 static DEFINE_SIMPLE_DEV_PM_OPS(wfx_sdio_pm_ops, wfx_sdio_suspend, wfx_sdio_resume); 316 317 struct sdio_driver wfx_sdio_driver = { 318 .name = "wfx-sdio", 319 .id_table = wfx_sdio_ids, 320 .probe = wfx_sdio_probe, 321 .remove = wfx_sdio_remove, 322 .drv = { 323 .of_match_table = wfx_sdio_of_match, 324 .pm = &wfx_sdio_pm_ops, 325 } 326 }; 327