162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Linux multi-function-device driver (MFD) for the integrated peripherals 462306a36Sopenharmony_ci * of the VIA VX855 chipset 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 2009 VIA Technologies, Inc. 762306a36Sopenharmony_ci * Copyright (C) 2010 One Laptop per Child 862306a36Sopenharmony_ci * Author: Harald Welte <HaraldWelte@viatech.com> 962306a36Sopenharmony_ci * All rights reserved. 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/kernel.h> 1362306a36Sopenharmony_ci#include <linux/module.h> 1462306a36Sopenharmony_ci#include <linux/device.h> 1562306a36Sopenharmony_ci#include <linux/platform_device.h> 1662306a36Sopenharmony_ci#include <linux/pci.h> 1762306a36Sopenharmony_ci#include <linux/mfd/core.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci/* offset into pci config space indicating the 16bit register containing 2062306a36Sopenharmony_ci * the power management IO space base */ 2162306a36Sopenharmony_ci#define VX855_CFG_PMIO_OFFSET 0x88 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci/* ACPI I/O Space registers */ 2462306a36Sopenharmony_ci#define VX855_PMIO_ACPI 0x00 2562306a36Sopenharmony_ci#define VX855_PMIO_ACPI_LEN 0x0b 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/* Processor Power Management */ 2862306a36Sopenharmony_ci#define VX855_PMIO_PPM 0x10 2962306a36Sopenharmony_ci#define VX855_PMIO_PPM_LEN 0x08 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci/* General Purpose Power Management */ 3262306a36Sopenharmony_ci#define VX855_PMIO_GPPM 0x20 3362306a36Sopenharmony_ci#define VX855_PMIO_R_GPI 0x48 3462306a36Sopenharmony_ci#define VX855_PMIO_R_GPO 0x4c 3562306a36Sopenharmony_ci#define VX855_PMIO_GPPM_LEN 0x33 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#define VSPIC_MMIO_SIZE 0x1000 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic struct resource vx855_gpio_resources[] = { 4062306a36Sopenharmony_ci { 4162306a36Sopenharmony_ci .flags = IORESOURCE_IO, 4262306a36Sopenharmony_ci }, 4362306a36Sopenharmony_ci { 4462306a36Sopenharmony_ci .flags = IORESOURCE_IO, 4562306a36Sopenharmony_ci }, 4662306a36Sopenharmony_ci}; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistatic const struct mfd_cell vx855_cells[] = { 4962306a36Sopenharmony_ci { 5062306a36Sopenharmony_ci .name = "vx855_gpio", 5162306a36Sopenharmony_ci .num_resources = ARRAY_SIZE(vx855_gpio_resources), 5262306a36Sopenharmony_ci .resources = vx855_gpio_resources, 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci /* we must ignore resource conflicts, for reasons outlined in 5562306a36Sopenharmony_ci * the vx855_gpio driver */ 5662306a36Sopenharmony_ci .ignore_resource_conflicts = true, 5762306a36Sopenharmony_ci }, 5862306a36Sopenharmony_ci}; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_cistatic int vx855_probe(struct pci_dev *pdev, 6162306a36Sopenharmony_ci const struct pci_device_id *id) 6262306a36Sopenharmony_ci{ 6362306a36Sopenharmony_ci int ret; 6462306a36Sopenharmony_ci u16 gpio_io_offset; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci ret = pci_enable_device(pdev); 6762306a36Sopenharmony_ci if (ret) 6862306a36Sopenharmony_ci return -ENODEV; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci pci_read_config_word(pdev, VX855_CFG_PMIO_OFFSET, &gpio_io_offset); 7162306a36Sopenharmony_ci if (!gpio_io_offset) { 7262306a36Sopenharmony_ci dev_warn(&pdev->dev, 7362306a36Sopenharmony_ci "BIOS did not assign PMIO base offset?!?\n"); 7462306a36Sopenharmony_ci ret = -ENODEV; 7562306a36Sopenharmony_ci goto out; 7662306a36Sopenharmony_ci } 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci /* mask out the lowest seven bits, as they are always zero, but 7962306a36Sopenharmony_ci * hardware returns them as 0x01 */ 8062306a36Sopenharmony_ci gpio_io_offset &= 0xff80; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci /* As the region identified here includes many non-GPIO things, we 8362306a36Sopenharmony_ci * only work with the specific registers that concern us. */ 8462306a36Sopenharmony_ci vx855_gpio_resources[0].start = gpio_io_offset + VX855_PMIO_R_GPI; 8562306a36Sopenharmony_ci vx855_gpio_resources[0].end = vx855_gpio_resources[0].start + 3; 8662306a36Sopenharmony_ci vx855_gpio_resources[1].start = gpio_io_offset + VX855_PMIO_R_GPO; 8762306a36Sopenharmony_ci vx855_gpio_resources[1].end = vx855_gpio_resources[1].start + 3; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci ret = mfd_add_devices(&pdev->dev, -1, vx855_cells, ARRAY_SIZE(vx855_cells), 9062306a36Sopenharmony_ci NULL, 0, NULL); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci /* we always return -ENODEV here in order to enable other 9362306a36Sopenharmony_ci * drivers like old, not-yet-platform_device ported i2c-viapro */ 9462306a36Sopenharmony_ci return -ENODEV; 9562306a36Sopenharmony_ciout: 9662306a36Sopenharmony_ci pci_disable_device(pdev); 9762306a36Sopenharmony_ci return ret; 9862306a36Sopenharmony_ci} 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cistatic void vx855_remove(struct pci_dev *pdev) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci mfd_remove_devices(&pdev->dev); 10362306a36Sopenharmony_ci pci_disable_device(pdev); 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic const struct pci_device_id vx855_pci_tbl[] = { 10762306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX855) }, 10862306a36Sopenharmony_ci { 0, } 10962306a36Sopenharmony_ci}; 11062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, vx855_pci_tbl); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cistatic struct pci_driver vx855_pci_driver = { 11362306a36Sopenharmony_ci .name = "vx855", 11462306a36Sopenharmony_ci .id_table = vx855_pci_tbl, 11562306a36Sopenharmony_ci .probe = vx855_probe, 11662306a36Sopenharmony_ci .remove = vx855_remove, 11762306a36Sopenharmony_ci}; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cimodule_pci_driver(vx855_pci_driver); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 12262306a36Sopenharmony_ciMODULE_AUTHOR("Harald Welte <HaraldWelte@viatech.com>"); 12362306a36Sopenharmony_ciMODULE_DESCRIPTION("Driver for the VIA VX855 chipset"); 124