OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [mmc/] [host/] [ricoh_mmc.c] - Rev 62

Compare with Previous | Blame | View Log

/*
 *  ricoh_mmc.c - Dummy driver to disable the Rioch MMC controller.
 *
 *  Copyright (C) 2007 Philip Langdale, All Rights Reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or (at
 * your option) any later version.
 */
 
/*
 * This is a conceptually ridiculous driver, but it is required by the way
 * the Ricoh multi-function R5C832 works. This chip implements firewire
 * and four different memory card controllers. Two of those controllers are
 * an SDHCI controller and a proprietary MMC controller. The linux SDHCI
 * driver supports MMC cards but the chip detects MMC cards in hardware
 * and directs them to the MMC controller - so the SDHCI driver never sees
 * them. To get around this, we must disable the useless MMC controller.
 * At that point, the SDHCI controller will start seeing them. As a bonus,
 * a detection event occurs immediately, even if the MMC card is already
 * in the reader.
 *
 * The relevant registers live on the firewire function, so this is unavoidably
 * ugly. Such is life.
 */
 
#include <linux/pci.h>
 
#define DRIVER_NAME "ricoh-mmc"
 
static const struct pci_device_id pci_ids[] __devinitdata = {
	{
		.vendor		= PCI_VENDOR_ID_RICOH,
		.device		= PCI_DEVICE_ID_RICOH_R5C843,
		.subvendor	= PCI_ANY_ID,
		.subdevice	= PCI_ANY_ID,
	},
	{ /* end: all zeroes */ },
};
 
MODULE_DEVICE_TABLE(pci, pci_ids);
 
static int __devinit ricoh_mmc_probe(struct pci_dev *pdev,
				     const struct pci_device_id *ent)
{
	u8 rev;
 
	struct pci_dev *fw_dev = NULL;
 
	BUG_ON(pdev == NULL);
	BUG_ON(ent == NULL);
 
	pci_read_config_byte(pdev, PCI_CLASS_REVISION, &rev);
 
	printk(KERN_INFO DRIVER_NAME
		": Ricoh MMC controller found at %s [%04x:%04x] (rev %x)\n",
		pci_name(pdev), (int)pdev->vendor, (int)pdev->device,
		(int)rev);
 
	while ((fw_dev = pci_get_device(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_R5C832, fw_dev))) {
		if (PCI_SLOT(pdev->devfn) == PCI_SLOT(fw_dev->devfn) &&
		    pdev->bus == fw_dev->bus) {
			u8 write_enable;
			u8 disable;
 
			pci_read_config_byte(fw_dev, 0xCB, &disable);
			if (disable & 0x02) {
				printk(KERN_INFO DRIVER_NAME
				       ": Controller already disabled. Nothing to do.\n");
				return -ENODEV;
			}
 
			pci_read_config_byte(fw_dev, 0xCA, &write_enable);
			pci_write_config_byte(fw_dev, 0xCA, 0x57);
			pci_write_config_byte(fw_dev, 0xCB, disable | 0x02);
			pci_write_config_byte(fw_dev, 0xCA, write_enable);
 
			pci_set_drvdata(pdev, fw_dev);
 
			printk(KERN_INFO DRIVER_NAME
			       ": Controller is now disabled.\n");
 
			break;
		}
	}
 
	if (pci_get_drvdata(pdev) == NULL) {
		printk(KERN_WARNING DRIVER_NAME
		       ": Main firewire function not found. Cannot disable controller.\n");
		return -ENODEV;
	}
 
	return 0;
}
 
static void __devexit ricoh_mmc_remove(struct pci_dev *pdev)
{
	u8 write_enable;
	u8 disable;
	struct pci_dev *fw_dev = NULL;
 
	fw_dev = pci_get_drvdata(pdev);
	BUG_ON(fw_dev == NULL);
 
	pci_read_config_byte(fw_dev, 0xCA, &write_enable);
	pci_read_config_byte(fw_dev, 0xCB, &disable);
	pci_write_config_byte(fw_dev, 0xCA, 0x57);
	pci_write_config_byte(fw_dev, 0xCB, disable & ~0x02);
	pci_write_config_byte(fw_dev, 0xCA, write_enable);
 
	printk(KERN_INFO DRIVER_NAME
	       ": Controller is now re-enabled.\n");
 
	pci_set_drvdata(pdev, NULL);
}
 
static struct pci_driver ricoh_mmc_driver = {
	.name = 	DRIVER_NAME,
	.id_table =	pci_ids,
	.probe = 	ricoh_mmc_probe,
	.remove =	__devexit_p(ricoh_mmc_remove),
};
 
/*****************************************************************************\
 *                                                                           *
 * Driver init/exit                                                          *
 *                                                                           *
\*****************************************************************************/
 
static int __init ricoh_mmc_drv_init(void)
{
	printk(KERN_INFO DRIVER_NAME
		": Ricoh MMC Controller disabling driver\n");
	printk(KERN_INFO DRIVER_NAME ": Copyright(c) Philip Langdale\n");
 
	return pci_register_driver(&ricoh_mmc_driver);
}
 
static void __exit ricoh_mmc_drv_exit(void)
{
	pci_unregister_driver(&ricoh_mmc_driver);
}
 
module_init(ricoh_mmc_drv_init);
module_exit(ricoh_mmc_drv_exit);
 
MODULE_AUTHOR("Philip Langdale <philipl@alumni.utexas.net>");
MODULE_DESCRIPTION("Ricoh MMC Controller disabling driver");
MODULE_LICENSE("GPL");
 
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.