428 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * tifm_7xx1.c - TI FlashMedia driver4 *5 * Copyright (C) 2006 Alex Dubov <oakad@yahoo.com>6 */7 8#include <linux/tifm.h>9#include <linux/dma-mapping.h>10#include <linux/module.h>11 12#define DRIVER_NAME "tifm_7xx1"13#define DRIVER_VERSION "0.8"14 15#define TIFM_IRQ_ENABLE 0x8000000016#define TIFM_IRQ_SOCKMASK(x) (x)17#define TIFM_IRQ_CARDMASK(x) ((x) << 8)18#define TIFM_IRQ_FIFOMASK(x) ((x) << 16)19#define TIFM_IRQ_SETALL 0xffffffff20 21static void tifm_7xx1_dummy_eject(struct tifm_adapter *fm,22 struct tifm_dev *sock)23{24}25 26static void tifm_7xx1_eject(struct tifm_adapter *fm, struct tifm_dev *sock)27{28 unsigned long flags;29 30 spin_lock_irqsave(&fm->lock, flags);31 fm->socket_change_set |= 1 << sock->socket_id;32 tifm_queue_work(&fm->media_switcher);33 spin_unlock_irqrestore(&fm->lock, flags);34}35 36static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id)37{38 struct tifm_adapter *fm = dev_id;39 struct tifm_dev *sock;40 unsigned int irq_status, cnt;41 42 spin_lock(&fm->lock);43 irq_status = readl(fm->addr + FM_INTERRUPT_STATUS);44 if (irq_status == 0 || irq_status == (~0)) {45 spin_unlock(&fm->lock);46 return IRQ_NONE;47 }48 49 if (irq_status & TIFM_IRQ_ENABLE) {50 writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);51 52 for (cnt = 0; cnt < fm->num_sockets; cnt++) {53 sock = fm->sockets[cnt];54 if (sock) {55 if ((irq_status >> cnt) & TIFM_IRQ_FIFOMASK(1))56 sock->data_event(sock);57 if ((irq_status >> cnt) & TIFM_IRQ_CARDMASK(1))58 sock->card_event(sock);59 }60 }61 62 fm->socket_change_set |= irq_status63 & ((1 << fm->num_sockets) - 1);64 }65 writel(irq_status, fm->addr + FM_INTERRUPT_STATUS);66 67 if (fm->finish_me)68 complete_all(fm->finish_me);69 else if (!fm->socket_change_set)70 writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE);71 else72 tifm_queue_work(&fm->media_switcher);73 74 spin_unlock(&fm->lock);75 return IRQ_HANDLED;76}77 78static unsigned char tifm_7xx1_toggle_sock_power(char __iomem *sock_addr)79{80 unsigned int s_state;81 int cnt;82 83 writel(0x0e00, sock_addr + SOCK_CONTROL);84 85 for (cnt = 16; cnt <= 256; cnt <<= 1) {86 if (!(TIFM_SOCK_STATE_POWERED87 & readl(sock_addr + SOCK_PRESENT_STATE)))88 break;89 90 msleep(cnt);91 }92 93 s_state = readl(sock_addr + SOCK_PRESENT_STATE);94 if (!(TIFM_SOCK_STATE_OCCUPIED & s_state))95 return 0;96 97 writel(readl(sock_addr + SOCK_CONTROL) | TIFM_CTRL_LED,98 sock_addr + SOCK_CONTROL);99 100 /* xd needs some extra time before power on */101 if (((readl(sock_addr + SOCK_PRESENT_STATE) >> 4) & 7)102 == TIFM_TYPE_XD)103 msleep(40);104 105 writel((s_state & TIFM_CTRL_POWER_MASK) | 0x0c00,106 sock_addr + SOCK_CONTROL);107 /* wait for power to stabilize */108 msleep(20);109 for (cnt = 16; cnt <= 256; cnt <<= 1) {110 if ((TIFM_SOCK_STATE_POWERED111 & readl(sock_addr + SOCK_PRESENT_STATE)))112 break;113 114 msleep(cnt);115 }116 117 writel(readl(sock_addr + SOCK_CONTROL) & (~TIFM_CTRL_LED),118 sock_addr + SOCK_CONTROL);119 120 return (readl(sock_addr + SOCK_PRESENT_STATE) >> 4) & 7;121}122 123inline static void tifm_7xx1_sock_power_off(char __iomem *sock_addr)124{125 writel((~TIFM_CTRL_POWER_MASK) & readl(sock_addr + SOCK_CONTROL),126 sock_addr + SOCK_CONTROL);127}128 129inline static char __iomem *130tifm_7xx1_sock_addr(char __iomem *base_addr, unsigned int sock_num)131{132 return base_addr + ((sock_num + 1) << 10);133}134 135static void tifm_7xx1_switch_media(struct work_struct *work)136{137 struct tifm_adapter *fm = container_of(work, struct tifm_adapter,138 media_switcher);139 struct tifm_dev *sock;140 char __iomem *sock_addr;141 unsigned long flags;142 unsigned char media_id;143 unsigned int socket_change_set, cnt;144 145 spin_lock_irqsave(&fm->lock, flags);146 socket_change_set = fm->socket_change_set;147 fm->socket_change_set = 0;148 149 dev_dbg(fm->dev.parent, "checking media set %x\n",150 socket_change_set);151 152 if (!socket_change_set) {153 spin_unlock_irqrestore(&fm->lock, flags);154 return;155 }156 157 for (cnt = 0; cnt < fm->num_sockets; cnt++) {158 if (!(socket_change_set & (1 << cnt)))159 continue;160 sock = fm->sockets[cnt];161 if (sock) {162 printk(KERN_INFO163 "%s : demand removing card from socket %u:%u\n",164 dev_name(&fm->dev), fm->id, cnt);165 fm->sockets[cnt] = NULL;166 sock_addr = sock->addr;167 spin_unlock_irqrestore(&fm->lock, flags);168 device_unregister(&sock->dev);169 spin_lock_irqsave(&fm->lock, flags);170 tifm_7xx1_sock_power_off(sock_addr);171 writel(0x0e00, sock_addr + SOCK_CONTROL);172 }173 174 spin_unlock_irqrestore(&fm->lock, flags);175 176 media_id = tifm_7xx1_toggle_sock_power(177 tifm_7xx1_sock_addr(fm->addr, cnt));178 179 // tifm_alloc_device will check if media_id is valid180 sock = tifm_alloc_device(fm, cnt, media_id);181 if (sock) {182 sock->addr = tifm_7xx1_sock_addr(fm->addr, cnt);183 184 if (!device_register(&sock->dev)) {185 spin_lock_irqsave(&fm->lock, flags);186 if (!fm->sockets[cnt]) {187 fm->sockets[cnt] = sock;188 sock = NULL;189 }190 spin_unlock_irqrestore(&fm->lock, flags);191 }192 if (sock)193 put_device(&sock->dev);194 }195 spin_lock_irqsave(&fm->lock, flags);196 }197 198 writel(TIFM_IRQ_FIFOMASK(socket_change_set)199 | TIFM_IRQ_CARDMASK(socket_change_set),200 fm->addr + FM_CLEAR_INTERRUPT_ENABLE);201 202 writel(TIFM_IRQ_FIFOMASK(socket_change_set)203 | TIFM_IRQ_CARDMASK(socket_change_set),204 fm->addr + FM_SET_INTERRUPT_ENABLE);205 206 writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE);207 spin_unlock_irqrestore(&fm->lock, flags);208}209 210static int __maybe_unused tifm_7xx1_suspend(struct device *dev_d)211{212 struct pci_dev *dev = to_pci_dev(dev_d);213 struct tifm_adapter *fm = pci_get_drvdata(dev);214 int cnt;215 216 dev_dbg(&dev->dev, "suspending host\n");217 218 for (cnt = 0; cnt < fm->num_sockets; cnt++) {219 if (fm->sockets[cnt])220 tifm_7xx1_sock_power_off(fm->sockets[cnt]->addr);221 }222 223 device_wakeup_disable(dev_d);224 return 0;225}226 227static int __maybe_unused tifm_7xx1_resume(struct device *dev_d)228{229 struct pci_dev *dev = to_pci_dev(dev_d);230 struct tifm_adapter *fm = pci_get_drvdata(dev);231 int rc;232 unsigned long time_left;233 unsigned int good_sockets = 0, bad_sockets = 0;234 unsigned long flags;235 /* Maximum number of entries is 4 */236 unsigned char new_ids[4];237 DECLARE_COMPLETION_ONSTACK(finish_resume);238 239 if (WARN_ON(fm->num_sockets > ARRAY_SIZE(new_ids)))240 return -ENXIO;241 242 pci_set_master(dev);243 244 dev_dbg(&dev->dev, "resuming host\n");245 246 for (rc = 0; rc < fm->num_sockets; rc++)247 new_ids[rc] = tifm_7xx1_toggle_sock_power(248 tifm_7xx1_sock_addr(fm->addr, rc));249 spin_lock_irqsave(&fm->lock, flags);250 for (rc = 0; rc < fm->num_sockets; rc++) {251 if (fm->sockets[rc]) {252 if (fm->sockets[rc]->type == new_ids[rc])253 good_sockets |= 1 << rc;254 else255 bad_sockets |= 1 << rc;256 }257 }258 259 writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1),260 fm->addr + FM_SET_INTERRUPT_ENABLE);261 dev_dbg(&dev->dev, "change sets on resume: good %x, bad %x\n",262 good_sockets, bad_sockets);263 264 fm->socket_change_set = 0;265 if (good_sockets) {266 fm->finish_me = &finish_resume;267 spin_unlock_irqrestore(&fm->lock, flags);268 time_left = wait_for_completion_timeout(&finish_resume, HZ);269 dev_dbg(&dev->dev, "wait returned %lu\n", time_left);270 writel(TIFM_IRQ_FIFOMASK(good_sockets)271 | TIFM_IRQ_CARDMASK(good_sockets),272 fm->addr + FM_CLEAR_INTERRUPT_ENABLE);273 writel(TIFM_IRQ_FIFOMASK(good_sockets)274 | TIFM_IRQ_CARDMASK(good_sockets),275 fm->addr + FM_SET_INTERRUPT_ENABLE);276 spin_lock_irqsave(&fm->lock, flags);277 fm->finish_me = NULL;278 fm->socket_change_set ^= good_sockets & fm->socket_change_set;279 }280 281 fm->socket_change_set |= bad_sockets;282 if (fm->socket_change_set)283 tifm_queue_work(&fm->media_switcher);284 285 spin_unlock_irqrestore(&fm->lock, flags);286 writel(TIFM_IRQ_ENABLE,287 fm->addr + FM_SET_INTERRUPT_ENABLE);288 289 return 0;290}291 292static int tifm_7xx1_dummy_has_ms_pif(struct tifm_adapter *fm,293 struct tifm_dev *sock)294{295 return 0;296}297 298static int tifm_7xx1_has_ms_pif(struct tifm_adapter *fm, struct tifm_dev *sock)299{300 if (((fm->num_sockets == 4) && (sock->socket_id == 2))301 || ((fm->num_sockets == 2) && (sock->socket_id == 0)))302 return 1;303 304 return 0;305}306 307static int tifm_7xx1_probe(struct pci_dev *dev,308 const struct pci_device_id *dev_id)309{310 struct tifm_adapter *fm;311 int pci_dev_busy = 0;312 int rc;313 314 rc = dma_set_mask(&dev->dev, DMA_BIT_MASK(32));315 if (rc)316 return rc;317 318 rc = pci_enable_device(dev);319 if (rc)320 return rc;321 322 pci_set_master(dev);323 324 rc = pci_request_regions(dev, DRIVER_NAME);325 if (rc) {326 pci_dev_busy = 1;327 goto err_out;328 }329 330 pci_intx(dev, 1);331 332 fm = tifm_alloc_adapter(dev->device == PCI_DEVICE_ID_TI_XX21_XX11_FM333 ? 4 : 2, &dev->dev);334 if (!fm) {335 rc = -ENOMEM;336 goto err_out_int;337 }338 339 INIT_WORK(&fm->media_switcher, tifm_7xx1_switch_media);340 fm->eject = tifm_7xx1_eject;341 fm->has_ms_pif = tifm_7xx1_has_ms_pif;342 pci_set_drvdata(dev, fm);343 344 fm->addr = pci_ioremap_bar(dev, 0);345 if (!fm->addr) {346 rc = -ENODEV;347 goto err_out_free;348 }349 350 rc = request_irq(dev->irq, tifm_7xx1_isr, IRQF_SHARED, DRIVER_NAME, fm);351 if (rc)352 goto err_out_unmap;353 354 rc = tifm_add_adapter(fm);355 if (rc)356 goto err_out_irq;357 358 writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1),359 fm->addr + FM_CLEAR_INTERRUPT_ENABLE);360 writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1),361 fm->addr + FM_SET_INTERRUPT_ENABLE);362 return 0;363 364err_out_irq:365 free_irq(dev->irq, fm);366err_out_unmap:367 iounmap(fm->addr);368err_out_free:369 tifm_free_adapter(fm);370err_out_int:371 pci_intx(dev, 0);372 pci_release_regions(dev);373err_out:374 if (!pci_dev_busy)375 pci_disable_device(dev);376 return rc;377}378 379static void tifm_7xx1_remove(struct pci_dev *dev)380{381 struct tifm_adapter *fm = pci_get_drvdata(dev);382 int cnt;383 384 fm->eject = tifm_7xx1_dummy_eject;385 fm->has_ms_pif = tifm_7xx1_dummy_has_ms_pif;386 writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);387 free_irq(dev->irq, fm);388 389 tifm_remove_adapter(fm);390 391 for (cnt = 0; cnt < fm->num_sockets; cnt++)392 tifm_7xx1_sock_power_off(tifm_7xx1_sock_addr(fm->addr, cnt));393 394 iounmap(fm->addr);395 pci_intx(dev, 0);396 pci_release_regions(dev);397 398 pci_disable_device(dev);399 tifm_free_adapter(fm);400}401 402static const struct pci_device_id tifm_7xx1_pci_tbl[] = {403 { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX21_XX11_FM, PCI_ANY_ID,404 PCI_ANY_ID, 0, 0, 0 }, /* xx21 - the one I have */405 { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX12_FM, PCI_ANY_ID,406 PCI_ANY_ID, 0, 0, 0 },407 { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX20_FM, PCI_ANY_ID,408 PCI_ANY_ID, 0, 0, 0 },409 { }410};411 412static SIMPLE_DEV_PM_OPS(tifm_7xx1_pm_ops, tifm_7xx1_suspend, tifm_7xx1_resume);413 414static struct pci_driver tifm_7xx1_driver = {415 .name = DRIVER_NAME,416 .id_table = tifm_7xx1_pci_tbl,417 .probe = tifm_7xx1_probe,418 .remove = tifm_7xx1_remove,419 .driver.pm = &tifm_7xx1_pm_ops,420};421 422module_pci_driver(tifm_7xx1_driver);423MODULE_AUTHOR("Alex Dubov");424MODULE_DESCRIPTION("TI FlashMedia host driver");425MODULE_LICENSE("GPL");426MODULE_DEVICE_TABLE(pci, tifm_7xx1_pci_tbl);427MODULE_VERSION(DRIVER_VERSION);428