1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 i2c Support for the Apple `Hydra' Mac I/O 4 5 Copyright (c) 1999-2004 Geert Uytterhoeven <geert@linux-m68k.org> 6 7 Based on i2c Support for Via Technologies 82C586B South Bridge 8 Copyright (c) 1998, 1999 Kyösti Mälkki <kmalkki@cc.hut.fi> 9 10 */ 11 12 #include <linux/kernel.h> 13 #include <linux/module.h> 14 #include <linux/pci.h> 15 #include <linux/types.h> 16 #include <linux/i2c.h> 17 #include <linux/i2c-algo-bit.h> 18 #include <linux/io.h> 19 #include <asm/hydra.h> 20 21 22 #define HYDRA_CPD_PD0 0x00000001 /* CachePD lines */ 23 #define HYDRA_CPD_PD1 0x00000002 24 #define HYDRA_CPD_PD2 0x00000004 25 #define HYDRA_CPD_PD3 0x00000008 26 27 #define HYDRA_SCLK HYDRA_CPD_PD0 28 #define HYDRA_SDAT HYDRA_CPD_PD1 29 #define HYDRA_SCLK_OE 0x00000010 30 #define HYDRA_SDAT_OE 0x00000020 31 32 static inline void pdregw(void *data, u32 val) 33 { 34 struct Hydra *hydra = (struct Hydra *)data; 35 writel(val, &hydra->CachePD); 36 } 37 38 static inline u32 pdregr(void *data) 39 { 40 struct Hydra *hydra = (struct Hydra *)data; 41 return readl(&hydra->CachePD); 42 } 43 44 static void hydra_bit_setscl(void *data, int state) 45 { 46 u32 val = pdregr(data); 47 if (state) 48 val &= ~HYDRA_SCLK_OE; 49 else { 50 val &= ~HYDRA_SCLK; 51 val |= HYDRA_SCLK_OE; 52 } 53 pdregw(data, val); 54 } 55 56 static void hydra_bit_setsda(void *data, int state) 57 { 58 u32 val = pdregr(data); 59 if (state) 60 val &= ~HYDRA_SDAT_OE; 61 else { 62 val &= ~HYDRA_SDAT; 63 val |= HYDRA_SDAT_OE; 64 } 65 pdregw(data, val); 66 } 67 68 static int hydra_bit_getscl(void *data) 69 { 70 return (pdregr(data) & HYDRA_SCLK) != 0; 71 } 72 73 static int hydra_bit_getsda(void *data) 74 { 75 return (pdregr(data) & HYDRA_SDAT) != 0; 76 } 77 78 /* ------------------------------------------------------------------------ */ 79 80 static struct i2c_algo_bit_data hydra_bit_data = { 81 .setsda = hydra_bit_setsda, 82 .setscl = hydra_bit_setscl, 83 .getsda = hydra_bit_getsda, 84 .getscl = hydra_bit_getscl, 85 .udelay = 5, 86 .timeout = HZ 87 }; 88 89 static struct i2c_adapter hydra_adap = { 90 .owner = THIS_MODULE, 91 .name = "Hydra i2c", 92 .algo_data = &hydra_bit_data, 93 }; 94 95 static const struct pci_device_id hydra_ids[] = { 96 { PCI_DEVICE(PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_HYDRA) }, 97 { 0, } 98 }; 99 100 MODULE_DEVICE_TABLE (pci, hydra_ids); 101 102 static int hydra_probe(struct pci_dev *dev, 103 const struct pci_device_id *id) 104 { 105 unsigned long base = pci_resource_start(dev, 0); 106 int res; 107 108 if (!request_mem_region(base+offsetof(struct Hydra, CachePD), 4, 109 hydra_adap.name)) 110 return -EBUSY; 111 112 hydra_bit_data.data = pci_ioremap_bar(dev, 0); 113 if (hydra_bit_data.data == NULL) { 114 release_mem_region(base+offsetof(struct Hydra, CachePD), 4); 115 return -ENODEV; 116 } 117 118 pdregw(hydra_bit_data.data, 0); /* clear SCLK_OE and SDAT_OE */ 119 hydra_adap.dev.parent = &dev->dev; 120 res = i2c_bit_add_bus(&hydra_adap); 121 if (res < 0) { 122 iounmap(hydra_bit_data.data); 123 release_mem_region(base+offsetof(struct Hydra, CachePD), 4); 124 return res; 125 } 126 return 0; 127 } 128 129 static void hydra_remove(struct pci_dev *dev) 130 { 131 pdregw(hydra_bit_data.data, 0); /* clear SCLK_OE and SDAT_OE */ 132 i2c_del_adapter(&hydra_adap); 133 iounmap(hydra_bit_data.data); 134 release_mem_region(pci_resource_start(dev, 0)+ 135 offsetof(struct Hydra, CachePD), 4); 136 } 137 138 139 static struct pci_driver hydra_driver = { 140 .name = "hydra_smbus", 141 .id_table = hydra_ids, 142 .probe = hydra_probe, 143 .remove = hydra_remove, 144 }; 145 146 module_pci_driver(hydra_driver); 147 148 MODULE_AUTHOR("Geert Uytterhoeven <geert@linux-m68k.org>"); 149 MODULE_DESCRIPTION("i2c for Apple Hydra Mac I/O"); 150 MODULE_LICENSE("GPL"); 151