1 // SPDX-License-Identifier: GPL-2.0-only
3 * cs5535-mfd.c - core MFD driver for CS5535/CS5536 southbridges
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.
10 * Copyright (c) 2010 Andres Salomon <dilinger@queued.net>
13 #include <linux/kernel.h>
14 #include <linux/mfd/core.h>
15 #include <linux/module.h>
16 #include <linux/pci.h>
19 #define DRV_NAME "cs5535-mfd"
21 enum cs5535_mfd_bars
{
30 static struct resource cs5535_mfd_resources
[NR_BARS
];
32 static struct mfd_cell cs5535_mfd_cells
[] = {
36 .resources
= &cs5535_mfd_resources
[SMB_BAR
],
39 .name
= "cs5535-gpio",
41 .resources
= &cs5535_mfd_resources
[GPIO_BAR
],
44 .name
= "cs5535-mfgpt",
46 .resources
= &cs5535_mfd_resources
[MFGPT_BAR
],
51 .resources
= &cs5535_mfd_resources
[PMS_BAR
],
55 static struct mfd_cell cs5535_olpc_mfd_cells
[] = {
57 .name
= "olpc-xo1-pm-acpi",
59 .resources
= &cs5535_mfd_resources
[ACPI_BAR
],
62 .name
= "olpc-xo1-sci-acpi",
64 .resources
= &cs5535_mfd_resources
[ACPI_BAR
],
68 static int cs5535_mfd_probe(struct pci_dev
*pdev
,
69 const struct pci_device_id
*id
)
73 err
= pci_enable_device(pdev
);
77 for (bar
= 0; bar
< NR_BARS
; bar
++) {
78 struct resource
*r
= &cs5535_mfd_resources
[bar
];
80 r
->flags
= IORESOURCE_IO
;
81 r
->start
= pci_resource_start(pdev
, bar
);
82 r
->end
= pci_resource_end(pdev
, bar
);
85 err
= pci_request_region(pdev
, PMS_BAR
, DRV_NAME
);
87 dev_err(&pdev
->dev
, "Failed to request PMS_BAR's IO region\n");
91 err
= mfd_add_devices(&pdev
->dev
, PLATFORM_DEVID_NONE
, cs5535_mfd_cells
,
92 ARRAY_SIZE(cs5535_mfd_cells
), NULL
, 0, NULL
);
95 "Failed to add CS5535 sub-devices: %d\n", err
);
99 if (machine_is_olpc()) {
100 err
= pci_request_region(pdev
, ACPI_BAR
, DRV_NAME
);
103 "Failed to request ACPI_BAR's IO region\n");
104 goto err_remove_devices
;
107 err
= mfd_add_devices(&pdev
->dev
, PLATFORM_DEVID_NONE
,
108 cs5535_olpc_mfd_cells
,
109 ARRAY_SIZE(cs5535_olpc_mfd_cells
),
113 "Failed to add CS5535 OLPC sub-devices: %d\n",
115 goto err_release_acpi
;
119 dev_info(&pdev
->dev
, "%zu devices registered.\n",
120 ARRAY_SIZE(cs5535_mfd_cells
));
125 pci_release_region(pdev
, ACPI_BAR
);
127 mfd_remove_devices(&pdev
->dev
);
129 pci_release_region(pdev
, PMS_BAR
);
131 pci_disable_device(pdev
);
135 static void cs5535_mfd_remove(struct pci_dev
*pdev
)
137 mfd_remove_devices(&pdev
->dev
);
139 if (machine_is_olpc())
140 pci_release_region(pdev
, ACPI_BAR
);
142 pci_release_region(pdev
, PMS_BAR
);
143 pci_disable_device(pdev
);
146 static 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
) },
151 MODULE_DEVICE_TABLE(pci
, cs5535_mfd_pci_tbl
);
153 static struct pci_driver cs5535_mfd_driver
= {
155 .id_table
= cs5535_mfd_pci_tbl
,
156 .probe
= cs5535_mfd_probe
,
157 .remove
= cs5535_mfd_remove
,
160 module_pci_driver(cs5535_mfd_driver
);
162 MODULE_AUTHOR("Andres Salomon <dilinger@queued.net>");
163 MODULE_DESCRIPTION("MFD driver for CS5535/CS5536 southbridge's ISA PCI device");
164 MODULE_LICENSE("GPL");