brintos

brintos / linux-shallow public Read only

0
0
Text · 10.7 KiB · 1d54680 Raw
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