1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * matrox_w1.c |
4 | * |
5 | * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net> |
6 | */ |
7 | |
8 | #include <asm/types.h> |
9 | #include <linux/atomic.h> |
10 | #include <linux/io.h> |
11 | |
12 | #include <linux/delay.h> |
13 | #include <linux/kernel.h> |
14 | #include <linux/module.h> |
15 | #include <linux/list.h> |
16 | #include <linux/interrupt.h> |
17 | #include <linux/spinlock.h> |
18 | #include <linux/timer.h> |
19 | #include <linux/slab.h> |
20 | #include <linux/pci_ids.h> |
21 | #include <linux/pci.h> |
22 | |
23 | #include <linux/w1.h> |
24 | |
25 | /* |
26 | * Matrox G400 DDC registers. |
27 | */ |
28 | |
29 | #define MATROX_G400_DDC_CLK (1<<4) |
30 | #define MATROX_G400_DDC_DATA (1<<1) |
31 | |
32 | #define MATROX_BASE 0x3C00 |
33 | #define MATROX_STATUS 0x1e14 |
34 | |
35 | #define MATROX_PORT_INDEX_OFFSET 0x00 |
36 | #define MATROX_PORT_DATA_OFFSET 0x0A |
37 | |
38 | #define MATROX_GET_CONTROL 0x2A |
39 | #define MATROX_GET_DATA 0x2B |
40 | #define MATROX_CURSOR_CTL 0x06 |
41 | |
42 | struct matrox_device { |
43 | void __iomem *base_addr; |
44 | void __iomem *port_index; |
45 | void __iomem *port_data; |
46 | u8 data_mask; |
47 | |
48 | unsigned long phys_addr; |
49 | void __iomem *virt_addr; |
50 | unsigned long found; |
51 | |
52 | struct w1_bus_master *bus_master; |
53 | }; |
54 | |
55 | /* |
56 | * These functions read and write DDC Data bit. |
57 | * |
58 | * Using tristate pins, since i can't find any open-drain pin in whole motherboard. |
59 | * Unfortunately we can't connect to Intel's 82801xx IO controller |
60 | * since we don't know motherboard schema, which has pretty unused(may be not) GPIO. |
61 | * |
62 | * I've heard that PIIX also has open drain pin. |
63 | * |
64 | * Port mapping. |
65 | */ |
66 | static inline u8 matrox_w1_read_reg(struct matrox_device *dev, u8 reg) |
67 | { |
68 | u8 ret; |
69 | |
70 | writeb(val: reg, addr: dev->port_index); |
71 | ret = readb(addr: dev->port_data); |
72 | barrier(); |
73 | |
74 | return ret; |
75 | } |
76 | |
77 | static inline void matrox_w1_write_reg(struct matrox_device *dev, u8 reg, u8 val) |
78 | { |
79 | writeb(val: reg, addr: dev->port_index); |
80 | writeb(val, addr: dev->port_data); |
81 | wmb(); |
82 | } |
83 | |
84 | static void matrox_w1_write_ddc_bit(void *data, u8 bit) |
85 | { |
86 | u8 ret; |
87 | struct matrox_device *dev = data; |
88 | |
89 | if (bit) |
90 | bit = 0; |
91 | else |
92 | bit = dev->data_mask; |
93 | |
94 | ret = matrox_w1_read_reg(dev, MATROX_GET_CONTROL); |
95 | matrox_w1_write_reg(dev, MATROX_GET_CONTROL, val: ((ret & ~dev->data_mask) | bit)); |
96 | matrox_w1_write_reg(dev, MATROX_GET_DATA, val: 0x00); |
97 | } |
98 | |
99 | static u8 matrox_w1_read_ddc_bit(void *data) |
100 | { |
101 | u8 ret; |
102 | struct matrox_device *dev = data; |
103 | |
104 | ret = matrox_w1_read_reg(dev, MATROX_GET_DATA); |
105 | |
106 | return ret; |
107 | } |
108 | |
109 | static void matrox_w1_hw_init(struct matrox_device *dev) |
110 | { |
111 | matrox_w1_write_reg(dev, MATROX_GET_DATA, val: 0xFF); |
112 | matrox_w1_write_reg(dev, MATROX_GET_CONTROL, val: 0x00); |
113 | } |
114 | |
115 | static int matrox_w1_probe(struct pci_dev *pdev, const struct pci_device_id *ent) |
116 | { |
117 | struct matrox_device *dev; |
118 | int err; |
119 | |
120 | if (pdev->vendor != PCI_VENDOR_ID_MATROX || pdev->device != PCI_DEVICE_ID_MATROX_G400) |
121 | return -ENODEV; |
122 | |
123 | dev = kzalloc(size: sizeof(struct matrox_device) + |
124 | sizeof(struct w1_bus_master), GFP_KERNEL); |
125 | if (!dev) |
126 | return -ENOMEM; |
127 | |
128 | dev->bus_master = (struct w1_bus_master *)(dev + 1); |
129 | |
130 | /* |
131 | * True for G400, for some other we need resource 0, see drivers/video/matrox/matroxfb_base.c |
132 | */ |
133 | |
134 | dev->phys_addr = pci_resource_start(pdev, 1); |
135 | |
136 | dev->virt_addr = ioremap(offset: dev->phys_addr, size: 16384); |
137 | if (!dev->virt_addr) { |
138 | dev_err(&pdev->dev, "%s: failed to ioremap(0x%lx, %d).\n" , |
139 | __func__, dev->phys_addr, 16384); |
140 | err = -EIO; |
141 | goto err_out_free_device; |
142 | } |
143 | |
144 | dev->base_addr = dev->virt_addr + MATROX_BASE; |
145 | dev->port_index = dev->base_addr + MATROX_PORT_INDEX_OFFSET; |
146 | dev->port_data = dev->base_addr + MATROX_PORT_DATA_OFFSET; |
147 | dev->data_mask = (MATROX_G400_DDC_DATA); |
148 | |
149 | matrox_w1_hw_init(dev); |
150 | |
151 | dev->bus_master->data = dev; |
152 | dev->bus_master->read_bit = &matrox_w1_read_ddc_bit; |
153 | dev->bus_master->write_bit = &matrox_w1_write_ddc_bit; |
154 | |
155 | err = w1_add_master_device(master: dev->bus_master); |
156 | if (err) |
157 | goto err_out_free_device; |
158 | |
159 | pci_set_drvdata(pdev, data: dev); |
160 | |
161 | dev->found = 1; |
162 | |
163 | dev_info(&pdev->dev, "Matrox G400 GPIO transport layer for 1-wire.\n" ); |
164 | |
165 | return 0; |
166 | |
167 | err_out_free_device: |
168 | if (dev->virt_addr) |
169 | iounmap(addr: dev->virt_addr); |
170 | kfree(objp: dev); |
171 | |
172 | return err; |
173 | } |
174 | |
175 | static void matrox_w1_remove(struct pci_dev *pdev) |
176 | { |
177 | struct matrox_device *dev = pci_get_drvdata(pdev); |
178 | |
179 | if (dev->found) { |
180 | w1_remove_master_device(master: dev->bus_master); |
181 | iounmap(addr: dev->virt_addr); |
182 | } |
183 | kfree(objp: dev); |
184 | } |
185 | |
186 | static struct pci_device_id matrox_w1_tbl[] = { |
187 | { PCI_DEVICE(PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400) }, |
188 | { }, |
189 | }; |
190 | MODULE_DEVICE_TABLE(pci, matrox_w1_tbl); |
191 | |
192 | static struct pci_driver matrox_w1_pci_driver = { |
193 | .name = "matrox_w1" , |
194 | .id_table = matrox_w1_tbl, |
195 | .probe = matrox_w1_probe, |
196 | .remove = matrox_w1_remove, |
197 | }; |
198 | module_pci_driver(matrox_w1_pci_driver); |
199 | |
200 | MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>" ); |
201 | MODULE_DESCRIPTION("Driver for transport(Dallas 1-wire protocol) over VGA DDC(matrox gpio)." ); |
202 | MODULE_LICENSE("GPL" ); |
203 | |