brintos

brintos / linux-shallow public Read only

0
0
Text · 2.8 KiB · ffa379e Raw
134 lines · c
1/*2 * Broadcom 43xx PCMCIA-SSB bridge module3 *4 * Copyright (c) 2007 Michael Buesch <m@bues.ch>5 *6 * Licensed under the GNU/GPL. See COPYING for details.7 */8 9#include "ssb_private.h"10 11#include <linux/ssb/ssb.h>12#include <linux/slab.h>13#include <linux/module.h>14 15#include <pcmcia/cistpl.h>16#include <pcmcia/ciscode.h>17#include <pcmcia/ds.h>18#include <pcmcia/cisreg.h>19 20static const struct pcmcia_device_id ssb_host_pcmcia_tbl[] = {21	PCMCIA_DEVICE_MANF_CARD(0x2D0, 0x448),22	PCMCIA_DEVICE_MANF_CARD(0x2D0, 0x476),23	PCMCIA_DEVICE_NULL,24};25 26MODULE_DEVICE_TABLE(pcmcia, ssb_host_pcmcia_tbl);27 28static int ssb_host_pcmcia_probe(struct pcmcia_device *dev)29{30	struct ssb_bus *ssb;31	int err = -ENOMEM;32	int res = 0;33 34	ssb = kzalloc(sizeof(*ssb), GFP_KERNEL);35	if (!ssb)36		goto out_error;37 38	err = -ENODEV;39 40	dev->config_flags |= CONF_ENABLE_IRQ;41 42	dev->resource[2]->flags |=  WIN_ENABLE | WIN_DATA_WIDTH_16 |43			 WIN_USE_WAIT;44	dev->resource[2]->start = 0;45	dev->resource[2]->end = SSB_CORE_SIZE;46	res = pcmcia_request_window(dev, dev->resource[2], 250);47	if (res != 0)48		goto err_kfree_ssb;49 50	res = pcmcia_map_mem_page(dev, dev->resource[2], 0);51	if (res != 0)52		goto err_disable;53 54	if (!dev->irq)55		goto err_disable;56 57	res = pcmcia_enable_device(dev);58	if (res != 0)59		goto err_disable;60 61	err = ssb_bus_pcmciabus_register(ssb, dev, dev->resource[2]->start);62	if (err)63		goto err_disable;64	dev->priv = ssb;65 66	return 0;67 68err_disable:69	pcmcia_disable_device(dev);70err_kfree_ssb:71	kfree(ssb);72out_error:73	dev_err(&dev->dev, "Initialization failed (%d, %d)\n", res, err);74	return err;75}76 77static void ssb_host_pcmcia_remove(struct pcmcia_device *dev)78{79	struct ssb_bus *ssb = dev->priv;80 81	ssb_bus_unregister(ssb);82	pcmcia_disable_device(dev);83	kfree(ssb);84	dev->priv = NULL;85}86 87#ifdef CONFIG_PM88static int ssb_host_pcmcia_suspend(struct pcmcia_device *dev)89{90	struct ssb_bus *ssb = dev->priv;91 92	return ssb_bus_suspend(ssb);93}94 95static int ssb_host_pcmcia_resume(struct pcmcia_device *dev)96{97	struct ssb_bus *ssb = dev->priv;98 99	return ssb_bus_resume(ssb);100}101#else /* CONFIG_PM */102# define ssb_host_pcmcia_suspend		NULL103# define ssb_host_pcmcia_resume		NULL104#endif /* CONFIG_PM */105 106static struct pcmcia_driver ssb_host_pcmcia_driver = {107	.owner		= THIS_MODULE,108	.name		= "ssb-pcmcia",109	.id_table	= ssb_host_pcmcia_tbl,110	.probe		= ssb_host_pcmcia_probe,111	.remove		= ssb_host_pcmcia_remove,112	.suspend	= ssb_host_pcmcia_suspend,113	.resume		= ssb_host_pcmcia_resume,114};115 116static int pcmcia_init_failed;117 118/*119 * These are not module init/exit functions!120 * The module_pcmcia_driver() helper cannot be used here.121 */122int ssb_host_pcmcia_init(void)123{124	pcmcia_init_failed = pcmcia_register_driver(&ssb_host_pcmcia_driver);125 126	return pcmcia_init_failed;127}128 129void ssb_host_pcmcia_exit(void)130{131	if (!pcmcia_init_failed)132		pcmcia_unregister_driver(&ssb_host_pcmcia_driver);133}134