0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/module.h>
0009 #include <linux/mmc/sdio.h>
0010 #include <linux/mmc/sdio_func.h>
0011 #include <linux/mmc/card.h>
0012 #include <linux/interrupt.h>
0013 #include <linux/of_device.h>
0014 #include <linux/of_irq.h>
0015 #include <linux/irq.h>
0016 #include <linux/align.h>
0017
0018 #include "bus.h"
0019 #include "wfx.h"
0020 #include "hwio.h"
0021 #include "main.h"
0022 #include "bh.h"
0023
0024 static const struct wfx_platform_data pdata_wf200 = {
0025 .file_fw = "wfx/wfm_wf200",
0026 .file_pds = "wfx/wf200.pds",
0027 };
0028
0029 static const struct wfx_platform_data pdata_brd4001a = {
0030 .file_fw = "wfx/wfm_wf200",
0031 .file_pds = "wfx/brd4001a.pds",
0032 };
0033
0034 static const struct wfx_platform_data pdata_brd8022a = {
0035 .file_fw = "wfx/wfm_wf200",
0036 .file_pds = "wfx/brd8022a.pds",
0037 };
0038
0039 static const struct wfx_platform_data pdata_brd8023a = {
0040 .file_fw = "wfx/wfm_wf200",
0041 .file_pds = "wfx/brd8023a.pds",
0042 };
0043
0044 struct wfx_sdio_priv {
0045 struct sdio_func *func;
0046 struct wfx_dev *core;
0047 u8 buf_id_tx;
0048 u8 buf_id_rx;
0049 int of_irq;
0050 };
0051
0052 static int wfx_sdio_copy_from_io(void *priv, unsigned int reg_id, void *dst, size_t count)
0053 {
0054 struct wfx_sdio_priv *bus = priv;
0055 unsigned int sdio_addr = reg_id << 2;
0056 int ret;
0057
0058 WARN(reg_id > 7, "chip only has 7 registers");
0059 WARN(!IS_ALIGNED((uintptr_t)dst, 4), "unaligned buffer address");
0060 WARN(!IS_ALIGNED(count, 4), "unaligned buffer size");
0061
0062
0063 if (reg_id == WFX_REG_IN_OUT_QUEUE)
0064 sdio_addr |= (bus->buf_id_rx + 1) << 7;
0065 ret = sdio_memcpy_fromio(bus->func, dst, sdio_addr, count);
0066 if (!ret && reg_id == WFX_REG_IN_OUT_QUEUE)
0067 bus->buf_id_rx = (bus->buf_id_rx + 1) % 4;
0068
0069 return ret;
0070 }
0071
0072 static int wfx_sdio_copy_to_io(void *priv, unsigned int reg_id, const void *src, size_t count)
0073 {
0074 struct wfx_sdio_priv *bus = priv;
0075 unsigned int sdio_addr = reg_id << 2;
0076 int ret;
0077
0078 WARN(reg_id > 7, "chip only has 7 registers");
0079 WARN(!IS_ALIGNED((uintptr_t)src, 4), "unaligned buffer address");
0080 WARN(!IS_ALIGNED(count, 4), "unaligned buffer size");
0081
0082
0083 if (reg_id == WFX_REG_IN_OUT_QUEUE)
0084 sdio_addr |= bus->buf_id_tx << 7;
0085
0086 ret = sdio_memcpy_toio(bus->func, sdio_addr, (void *)src, count);
0087 if (!ret && reg_id == WFX_REG_IN_OUT_QUEUE)
0088 bus->buf_id_tx = (bus->buf_id_tx + 1) % 32;
0089
0090 return ret;
0091 }
0092
0093 static void wfx_sdio_lock(void *priv)
0094 {
0095 struct wfx_sdio_priv *bus = priv;
0096
0097 sdio_claim_host(bus->func);
0098 }
0099
0100 static void wfx_sdio_unlock(void *priv)
0101 {
0102 struct wfx_sdio_priv *bus = priv;
0103
0104 sdio_release_host(bus->func);
0105 }
0106
0107 static void wfx_sdio_irq_handler(struct sdio_func *func)
0108 {
0109 struct wfx_sdio_priv *bus = sdio_get_drvdata(func);
0110
0111 wfx_bh_request_rx(bus->core);
0112 }
0113
0114 static irqreturn_t wfx_sdio_irq_handler_ext(int irq, void *priv)
0115 {
0116 struct wfx_sdio_priv *bus = priv;
0117
0118 sdio_claim_host(bus->func);
0119 wfx_bh_request_rx(bus->core);
0120 sdio_release_host(bus->func);
0121 return IRQ_HANDLED;
0122 }
0123
0124 static int wfx_sdio_irq_subscribe(void *priv)
0125 {
0126 struct wfx_sdio_priv *bus = priv;
0127 u32 flags;
0128 int ret;
0129 u8 cccr;
0130
0131 if (!bus->of_irq) {
0132 sdio_claim_host(bus->func);
0133 ret = sdio_claim_irq(bus->func, wfx_sdio_irq_handler);
0134 sdio_release_host(bus->func);
0135 return ret;
0136 }
0137
0138 flags = irq_get_trigger_type(bus->of_irq);
0139 if (!flags)
0140 flags = IRQF_TRIGGER_HIGH;
0141 flags |= IRQF_ONESHOT;
0142 ret = devm_request_threaded_irq(&bus->func->dev, bus->of_irq, NULL,
0143 wfx_sdio_irq_handler_ext, flags, "wfx", bus);
0144 if (ret)
0145 return ret;
0146 sdio_claim_host(bus->func);
0147 cccr = sdio_f0_readb(bus->func, SDIO_CCCR_IENx, NULL);
0148 cccr |= BIT(0);
0149 cccr |= BIT(bus->func->num);
0150 sdio_f0_writeb(bus->func, cccr, SDIO_CCCR_IENx, NULL);
0151 sdio_release_host(bus->func);
0152 return 0;
0153 }
0154
0155 static int wfx_sdio_irq_unsubscribe(void *priv)
0156 {
0157 struct wfx_sdio_priv *bus = priv;
0158 int ret;
0159
0160 if (bus->of_irq)
0161 devm_free_irq(&bus->func->dev, bus->of_irq, bus);
0162 sdio_claim_host(bus->func);
0163 ret = sdio_release_irq(bus->func);
0164 sdio_release_host(bus->func);
0165 return ret;
0166 }
0167
0168 static size_t wfx_sdio_align_size(void *priv, size_t size)
0169 {
0170 struct wfx_sdio_priv *bus = priv;
0171
0172 return sdio_align_size(bus->func, size);
0173 }
0174
0175 static const struct wfx_hwbus_ops wfx_sdio_hwbus_ops = {
0176 .copy_from_io = wfx_sdio_copy_from_io,
0177 .copy_to_io = wfx_sdio_copy_to_io,
0178 .irq_subscribe = wfx_sdio_irq_subscribe,
0179 .irq_unsubscribe = wfx_sdio_irq_unsubscribe,
0180 .lock = wfx_sdio_lock,
0181 .unlock = wfx_sdio_unlock,
0182 .align_size = wfx_sdio_align_size,
0183 };
0184
0185 static const struct of_device_id wfx_sdio_of_match[] = {
0186 { .compatible = "silabs,wf200", .data = &pdata_wf200 },
0187 { .compatible = "silabs,brd4001a", .data = &pdata_brd4001a },
0188 { .compatible = "silabs,brd8022a", .data = &pdata_brd8022a },
0189 { .compatible = "silabs,brd8023a", .data = &pdata_brd8023a },
0190 { },
0191 };
0192 MODULE_DEVICE_TABLE(of, wfx_sdio_of_match);
0193
0194 static int wfx_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id)
0195 {
0196 const struct wfx_platform_data *pdata = of_device_get_match_data(&func->dev);
0197 struct device_node *np = func->dev.of_node;
0198 struct wfx_sdio_priv *bus;
0199 int ret;
0200
0201 if (func->num != 1) {
0202 dev_err(&func->dev, "SDIO function number is %d while it should always be 1 (unsupported chip?)\n",
0203 func->num);
0204 return -ENODEV;
0205 }
0206
0207 if (!pdata) {
0208 dev_warn(&func->dev, "no compatible device found in DT\n");
0209 return -ENODEV;
0210 }
0211
0212 bus = devm_kzalloc(&func->dev, sizeof(*bus), GFP_KERNEL);
0213 if (!bus)
0214 return -ENOMEM;
0215
0216 bus->func = func;
0217 bus->of_irq = irq_of_parse_and_map(np, 0);
0218 sdio_set_drvdata(func, bus);
0219
0220 sdio_claim_host(func);
0221 ret = sdio_enable_func(func);
0222
0223 sdio_set_block_size(func, 64);
0224 sdio_release_host(func);
0225 if (ret)
0226 return ret;
0227
0228 bus->core = wfx_init_common(&func->dev, pdata, &wfx_sdio_hwbus_ops, bus);
0229 if (!bus->core) {
0230 ret = -EIO;
0231 goto sdio_release;
0232 }
0233
0234 ret = wfx_probe(bus->core);
0235 if (ret)
0236 goto sdio_release;
0237
0238 return 0;
0239
0240 sdio_release:
0241 sdio_claim_host(func);
0242 sdio_disable_func(func);
0243 sdio_release_host(func);
0244 return ret;
0245 }
0246
0247 static void wfx_sdio_remove(struct sdio_func *func)
0248 {
0249 struct wfx_sdio_priv *bus = sdio_get_drvdata(func);
0250
0251 wfx_release(bus->core);
0252 sdio_claim_host(func);
0253 sdio_disable_func(func);
0254 sdio_release_host(func);
0255 }
0256
0257 static const struct sdio_device_id wfx_sdio_ids[] = {
0258
0259 { SDIO_DEVICE(0x0000, 0x1000) },
0260 { },
0261 };
0262 MODULE_DEVICE_TABLE(sdio, wfx_sdio_ids);
0263
0264 struct sdio_driver wfx_sdio_driver = {
0265 .name = "wfx-sdio",
0266 .id_table = wfx_sdio_ids,
0267 .probe = wfx_sdio_probe,
0268 .remove = wfx_sdio_remove,
0269 .drv = {
0270 .owner = THIS_MODULE,
0271 .of_match_table = wfx_sdio_of_match,
0272 }
0273 };