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, addr: &hydra->CachePD); |
36 | } |
37 | |
38 | static inline u32 pdregr(void *data) |
39 | { |
40 | struct Hydra *hydra = (struct Hydra *)data; |
41 | return readl(addr: &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(pdev: dev, bar: 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(data: hydra_bit_data.data, val: 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(addr: 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(data: hydra_bit_data.data, val: 0); /* clear SCLK_OE and SDAT_OE */ |
132 | i2c_del_adapter(adap: &hydra_adap); |
133 | iounmap(addr: 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 | |