File Index
Files and directories
Sign in
FILE

matrox_w1.c

File preview with syntax highlighting.

linux-6.19.14/drivers/w1/masters/matrox_w1.c C
  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
 42struct 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
 51	struct w1_bus_master *bus_master;
 52};
 53
 54/*
 55 * These functions read and write DDC Data bit.
 56 *
 57 * Using tristate pins, since i can't find any open-drain pin in whole motherboard.
 58 * Unfortunately we can't connect to Intel's 82801xx IO controller
 59 * since we don't know motherboard schema, which has pretty unused(may be not) GPIO.
 60 *
 61 * I've heard that PIIX also has open drain pin.
 62 *
 63 * Port mapping.
 64 */
 65static inline u8 matrox_w1_read_reg(struct matrox_device *dev, u8 reg)
 66{
 67	u8 ret;
 68
 69	writeb(reg, dev->port_index);
 70	ret = readb(dev->port_data);
 71	barrier();
 72
 73	return ret;
 74}
 75
 76static inline void matrox_w1_write_reg(struct matrox_device *dev, u8 reg, u8 val)
 77{
 78	writeb(reg, dev->port_index);
 79	writeb(val, dev->port_data);
 80	wmb();
 81}
 82
 83static void matrox_w1_write_ddc_bit(void *data, u8 bit)
 84{
 85	u8 ret;
 86	struct matrox_device *dev = data;
 87
 88	if (bit)
 89		bit = 0;
 90	else
 91		bit = dev->data_mask;
 92
 93	ret = matrox_w1_read_reg(dev, MATROX_GET_CONTROL);
 94	matrox_w1_write_reg(dev, MATROX_GET_CONTROL, ((ret & ~dev->data_mask) | bit));
 95	matrox_w1_write_reg(dev, MATROX_GET_DATA, 0x00);
 96}
 97
 98static u8 matrox_w1_read_ddc_bit(void *data)
 99{
100	u8 ret;
101	struct matrox_device *dev = data;
102
103	ret = matrox_w1_read_reg(dev, MATROX_GET_DATA);
104
105	return ret;
106}
107
108static void matrox_w1_hw_init(struct matrox_device *dev)
109{
110	matrox_w1_write_reg(dev, MATROX_GET_DATA, 0xFF);
111	matrox_w1_write_reg(dev, MATROX_GET_CONTROL, 0x00);
112}
113
114static int matrox_w1_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
115{
116	struct matrox_device *dev;
117	int err;
118
119	if (pdev->vendor != PCI_VENDOR_ID_MATROX || pdev->device != PCI_DEVICE_ID_MATROX_G400)
120		return -ENODEV;
121
122	dev = kzalloc(sizeof(struct matrox_device) +
123		       sizeof(struct w1_bus_master), GFP_KERNEL);
124	if (!dev)
125		return -ENOMEM;
126
127	dev->bus_master = (struct w1_bus_master *)(dev + 1);
128
129	/*
130	 * True for G400, for some other we need resource 0, see drivers/video/matrox/matroxfb_base.c
131	 */
132
133	dev->phys_addr = pci_resource_start(pdev, 1);
134
135	dev->virt_addr = ioremap(dev->phys_addr, 16384);
136	if (!dev->virt_addr) {
137		dev_err(&pdev->dev, "%s: failed to ioremap(0x%lx, %d).\n",
138			__func__, dev->phys_addr, 16384);
139		err = -EIO;
140		goto err_out_free_device;
141	}
142
143	dev->base_addr = dev->virt_addr + MATROX_BASE;
144	dev->port_index = dev->base_addr + MATROX_PORT_INDEX_OFFSET;
145	dev->port_data = dev->base_addr + MATROX_PORT_DATA_OFFSET;
146	dev->data_mask = (MATROX_G400_DDC_DATA);
147
148	matrox_w1_hw_init(dev);
149
150	dev->bus_master->data = dev;
151	dev->bus_master->read_bit = &matrox_w1_read_ddc_bit;
152	dev->bus_master->write_bit = &matrox_w1_write_ddc_bit;
153
154	err = w1_add_master_device(dev->bus_master);
155	if (err)
156		goto err_out_free_device;
157
158	pci_set_drvdata(pdev, dev);
159
160	dev_info(&pdev->dev, "Matrox G400 GPIO transport layer for 1-wire.\n");
161
162	return 0;
163
164err_out_free_device:
165	if (dev->virt_addr)
166		iounmap(dev->virt_addr);
167	kfree(dev);
168
169	return err;
170}
171
172static void matrox_w1_remove(struct pci_dev *pdev)
173{
174	struct matrox_device *dev = pci_get_drvdata(pdev);
175
176	w1_remove_master_device(dev->bus_master);
177	iounmap(dev->virt_addr);
178
179	kfree(dev);
180}
181
182static struct pci_device_id matrox_w1_tbl[] = {
183	{ PCI_DEVICE(PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400) },
184	{ },
185};
186MODULE_DEVICE_TABLE(pci, matrox_w1_tbl);
187
188static struct pci_driver matrox_w1_pci_driver = {
189	.name = "matrox_w1",
190	.id_table = matrox_w1_tbl,
191	.probe = matrox_w1_probe,
192	.remove = matrox_w1_remove,
193};
194module_pci_driver(matrox_w1_pci_driver);
195
196MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>");
197MODULE_DESCRIPTION("Driver for transport(Dallas 1-wire protocol) over VGA DDC(matrox gpio).");
198MODULE_LICENSE("GPL");
~/ Read-only file preview.