cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

cs5535-mfd.c (3863B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * cs5535-mfd.c - core MFD driver for CS5535/CS5536 southbridges
      4 *
      5 * The CS5535 and CS5536 has an ISA bridge on the PCI bus that is
      6 * used for accessing GPIOs, MFGPTs, ACPI, etc.  Each subdevice has
      7 * an IO range that's specified in a single BAR.  The BAR order is
      8 * hardcoded in the CS553x specifications.
      9 *
     10 * Copyright (c) 2010  Andres Salomon <dilinger@queued.net>
     11 */
     12
     13#include <linux/kernel.h>
     14#include <linux/mfd/core.h>
     15#include <linux/module.h>
     16#include <linux/pci.h>
     17#include <asm/olpc.h>
     18
     19#define DRV_NAME "cs5535-mfd"
     20
     21enum cs5535_mfd_bars {
     22	SMB_BAR = 0,
     23	GPIO_BAR = 1,
     24	MFGPT_BAR = 2,
     25	PMS_BAR = 4,
     26	ACPI_BAR = 5,
     27	NR_BARS,
     28};
     29
     30static struct resource cs5535_mfd_resources[NR_BARS];
     31
     32static struct mfd_cell cs5535_mfd_cells[] = {
     33	{
     34		.name = "cs5535-smb",
     35		.num_resources = 1,
     36		.resources = &cs5535_mfd_resources[SMB_BAR],
     37	},
     38	{
     39		.name = "cs5535-gpio",
     40		.num_resources = 1,
     41		.resources = &cs5535_mfd_resources[GPIO_BAR],
     42	},
     43	{
     44		.name = "cs5535-mfgpt",
     45		.num_resources = 1,
     46		.resources = &cs5535_mfd_resources[MFGPT_BAR],
     47	},
     48	{
     49		.name = "cs5535-pms",
     50		.num_resources = 1,
     51		.resources = &cs5535_mfd_resources[PMS_BAR],
     52	},
     53};
     54
     55static struct mfd_cell cs5535_olpc_mfd_cells[] = {
     56	{
     57		.name = "olpc-xo1-pm-acpi",
     58		.num_resources = 1,
     59		.resources = &cs5535_mfd_resources[ACPI_BAR],
     60	},
     61	{
     62		.name = "olpc-xo1-sci-acpi",
     63		.num_resources = 1,
     64		.resources = &cs5535_mfd_resources[ACPI_BAR],
     65	},
     66};
     67
     68static int cs5535_mfd_probe(struct pci_dev *pdev,
     69		const struct pci_device_id *id)
     70{
     71	int err, bar;
     72
     73	err = pci_enable_device(pdev);
     74	if (err)
     75		return err;
     76
     77	for (bar = 0; bar < NR_BARS; bar++) {
     78		struct resource *r = &cs5535_mfd_resources[bar];
     79
     80		r->flags = IORESOURCE_IO;
     81		r->start = pci_resource_start(pdev, bar);
     82		r->end = pci_resource_end(pdev, bar);
     83	}
     84
     85	err = pci_request_region(pdev, PMS_BAR, DRV_NAME);
     86	if (err) {
     87		dev_err(&pdev->dev, "Failed to request PMS_BAR's IO region\n");
     88		goto err_disable;
     89	}
     90
     91	err = mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE, cs5535_mfd_cells,
     92			      ARRAY_SIZE(cs5535_mfd_cells), NULL, 0, NULL);
     93	if (err) {
     94		dev_err(&pdev->dev,
     95			"Failed to add CS5535 sub-devices: %d\n", err);
     96		goto err_release_pms;
     97	}
     98
     99	if (machine_is_olpc()) {
    100		err = pci_request_region(pdev, ACPI_BAR, DRV_NAME);
    101		if (err) {
    102			dev_err(&pdev->dev,
    103				"Failed to request ACPI_BAR's IO region\n");
    104			goto err_remove_devices;
    105		}
    106
    107		err = mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE,
    108				      cs5535_olpc_mfd_cells,
    109				      ARRAY_SIZE(cs5535_olpc_mfd_cells),
    110				      NULL, 0, NULL);
    111		if (err) {
    112			dev_err(&pdev->dev,
    113				"Failed to add CS5535 OLPC sub-devices: %d\n",
    114				err);
    115			goto err_release_acpi;
    116		}
    117	}
    118
    119	dev_info(&pdev->dev, "%zu devices registered.\n",
    120			ARRAY_SIZE(cs5535_mfd_cells));
    121
    122	return 0;
    123
    124err_release_acpi:
    125	pci_release_region(pdev, ACPI_BAR);
    126err_remove_devices:
    127	mfd_remove_devices(&pdev->dev);
    128err_release_pms:
    129	pci_release_region(pdev, PMS_BAR);
    130err_disable:
    131	pci_disable_device(pdev);
    132	return err;
    133}
    134
    135static void cs5535_mfd_remove(struct pci_dev *pdev)
    136{
    137	mfd_remove_devices(&pdev->dev);
    138
    139	if (machine_is_olpc())
    140		pci_release_region(pdev, ACPI_BAR);
    141
    142	pci_release_region(pdev, PMS_BAR);
    143	pci_disable_device(pdev);
    144}
    145
    146static const struct pci_device_id cs5535_mfd_pci_tbl[] = {
    147	{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA) },
    148	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) },
    149	{ 0, }
    150};
    151MODULE_DEVICE_TABLE(pci, cs5535_mfd_pci_tbl);
    152
    153static struct pci_driver cs5535_mfd_driver = {
    154	.name = DRV_NAME,
    155	.id_table = cs5535_mfd_pci_tbl,
    156	.probe = cs5535_mfd_probe,
    157	.remove = cs5535_mfd_remove,
    158};
    159
    160module_pci_driver(cs5535_mfd_driver);
    161
    162MODULE_AUTHOR("Andres Salomon <dilinger@queued.net>");
    163MODULE_DESCRIPTION("MFD driver for CS5535/CS5536 southbridge's ISA PCI device");
    164MODULE_LICENSE("GPL");