18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci i2c Support for the Apple `Hydra' Mac I/O 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci Copyright (c) 1999-2004 Geert Uytterhoeven <geert@linux-m68k.org> 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci Based on i2c Support for Via Technologies 82C586B South Bridge 88c2ecf20Sopenharmony_ci Copyright (c) 1998, 1999 Kyösti Mälkki <kmalkki@cc.hut.fi> 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci*/ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/kernel.h> 138c2ecf20Sopenharmony_ci#include <linux/module.h> 148c2ecf20Sopenharmony_ci#include <linux/pci.h> 158c2ecf20Sopenharmony_ci#include <linux/types.h> 168c2ecf20Sopenharmony_ci#include <linux/i2c.h> 178c2ecf20Sopenharmony_ci#include <linux/i2c-algo-bit.h> 188c2ecf20Sopenharmony_ci#include <linux/io.h> 198c2ecf20Sopenharmony_ci#include <asm/hydra.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define HYDRA_CPD_PD0 0x00000001 /* CachePD lines */ 238c2ecf20Sopenharmony_ci#define HYDRA_CPD_PD1 0x00000002 248c2ecf20Sopenharmony_ci#define HYDRA_CPD_PD2 0x00000004 258c2ecf20Sopenharmony_ci#define HYDRA_CPD_PD3 0x00000008 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#define HYDRA_SCLK HYDRA_CPD_PD0 288c2ecf20Sopenharmony_ci#define HYDRA_SDAT HYDRA_CPD_PD1 298c2ecf20Sopenharmony_ci#define HYDRA_SCLK_OE 0x00000010 308c2ecf20Sopenharmony_ci#define HYDRA_SDAT_OE 0x00000020 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic inline void pdregw(void *data, u32 val) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci struct Hydra *hydra = (struct Hydra *)data; 358c2ecf20Sopenharmony_ci writel(val, &hydra->CachePD); 368c2ecf20Sopenharmony_ci} 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic inline u32 pdregr(void *data) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci struct Hydra *hydra = (struct Hydra *)data; 418c2ecf20Sopenharmony_ci return readl(&hydra->CachePD); 428c2ecf20Sopenharmony_ci} 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic void hydra_bit_setscl(void *data, int state) 458c2ecf20Sopenharmony_ci{ 468c2ecf20Sopenharmony_ci u32 val = pdregr(data); 478c2ecf20Sopenharmony_ci if (state) 488c2ecf20Sopenharmony_ci val &= ~HYDRA_SCLK_OE; 498c2ecf20Sopenharmony_ci else { 508c2ecf20Sopenharmony_ci val &= ~HYDRA_SCLK; 518c2ecf20Sopenharmony_ci val |= HYDRA_SCLK_OE; 528c2ecf20Sopenharmony_ci } 538c2ecf20Sopenharmony_ci pdregw(data, val); 548c2ecf20Sopenharmony_ci} 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic void hydra_bit_setsda(void *data, int state) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci u32 val = pdregr(data); 598c2ecf20Sopenharmony_ci if (state) 608c2ecf20Sopenharmony_ci val &= ~HYDRA_SDAT_OE; 618c2ecf20Sopenharmony_ci else { 628c2ecf20Sopenharmony_ci val &= ~HYDRA_SDAT; 638c2ecf20Sopenharmony_ci val |= HYDRA_SDAT_OE; 648c2ecf20Sopenharmony_ci } 658c2ecf20Sopenharmony_ci pdregw(data, val); 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic int hydra_bit_getscl(void *data) 698c2ecf20Sopenharmony_ci{ 708c2ecf20Sopenharmony_ci return (pdregr(data) & HYDRA_SCLK) != 0; 718c2ecf20Sopenharmony_ci} 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic int hydra_bit_getsda(void *data) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci return (pdregr(data) & HYDRA_SDAT) != 0; 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------------ */ 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistatic struct i2c_algo_bit_data hydra_bit_data = { 818c2ecf20Sopenharmony_ci .setsda = hydra_bit_setsda, 828c2ecf20Sopenharmony_ci .setscl = hydra_bit_setscl, 838c2ecf20Sopenharmony_ci .getsda = hydra_bit_getsda, 848c2ecf20Sopenharmony_ci .getscl = hydra_bit_getscl, 858c2ecf20Sopenharmony_ci .udelay = 5, 868c2ecf20Sopenharmony_ci .timeout = HZ 878c2ecf20Sopenharmony_ci}; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic struct i2c_adapter hydra_adap = { 908c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 918c2ecf20Sopenharmony_ci .name = "Hydra i2c", 928c2ecf20Sopenharmony_ci .algo_data = &hydra_bit_data, 938c2ecf20Sopenharmony_ci}; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic const struct pci_device_id hydra_ids[] = { 968c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_HYDRA) }, 978c2ecf20Sopenharmony_ci { 0, } 988c2ecf20Sopenharmony_ci}; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE (pci, hydra_ids); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cistatic int hydra_probe(struct pci_dev *dev, 1038c2ecf20Sopenharmony_ci const struct pci_device_id *id) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci unsigned long base = pci_resource_start(dev, 0); 1068c2ecf20Sopenharmony_ci int res; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci if (!request_mem_region(base+offsetof(struct Hydra, CachePD), 4, 1098c2ecf20Sopenharmony_ci hydra_adap.name)) 1108c2ecf20Sopenharmony_ci return -EBUSY; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci hydra_bit_data.data = pci_ioremap_bar(dev, 0); 1138c2ecf20Sopenharmony_ci if (hydra_bit_data.data == NULL) { 1148c2ecf20Sopenharmony_ci release_mem_region(base+offsetof(struct Hydra, CachePD), 4); 1158c2ecf20Sopenharmony_ci return -ENODEV; 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci pdregw(hydra_bit_data.data, 0); /* clear SCLK_OE and SDAT_OE */ 1198c2ecf20Sopenharmony_ci hydra_adap.dev.parent = &dev->dev; 1208c2ecf20Sopenharmony_ci res = i2c_bit_add_bus(&hydra_adap); 1218c2ecf20Sopenharmony_ci if (res < 0) { 1228c2ecf20Sopenharmony_ci iounmap(hydra_bit_data.data); 1238c2ecf20Sopenharmony_ci release_mem_region(base+offsetof(struct Hydra, CachePD), 4); 1248c2ecf20Sopenharmony_ci return res; 1258c2ecf20Sopenharmony_ci } 1268c2ecf20Sopenharmony_ci return 0; 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic void hydra_remove(struct pci_dev *dev) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci pdregw(hydra_bit_data.data, 0); /* clear SCLK_OE and SDAT_OE */ 1328c2ecf20Sopenharmony_ci i2c_del_adapter(&hydra_adap); 1338c2ecf20Sopenharmony_ci iounmap(hydra_bit_data.data); 1348c2ecf20Sopenharmony_ci release_mem_region(pci_resource_start(dev, 0)+ 1358c2ecf20Sopenharmony_ci offsetof(struct Hydra, CachePD), 4); 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cistatic struct pci_driver hydra_driver = { 1408c2ecf20Sopenharmony_ci .name = "hydra_smbus", 1418c2ecf20Sopenharmony_ci .id_table = hydra_ids, 1428c2ecf20Sopenharmony_ci .probe = hydra_probe, 1438c2ecf20Sopenharmony_ci .remove = hydra_remove, 1448c2ecf20Sopenharmony_ci}; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_cimodule_pci_driver(hydra_driver); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ciMODULE_AUTHOR("Geert Uytterhoeven <geert@linux-m68k.org>"); 1498c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("i2c for Apple Hydra Mac I/O"); 1508c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 151