Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  matrox_w1.c
0004  *
0005  * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net>
0006  */
0007 
0008 #include <asm/types.h>
0009 #include <linux/atomic.h>
0010 #include <asm/io.h>
0011 
0012 #include <linux/delay.h>
0013 #include <linux/kernel.h>
0014 #include <linux/module.h>
0015 #include <linux/list.h>
0016 #include <linux/interrupt.h>
0017 #include <linux/spinlock.h>
0018 #include <linux/timer.h>
0019 #include <linux/slab.h>
0020 #include <linux/pci_ids.h>
0021 #include <linux/pci.h>
0022 
0023 #include <linux/w1.h>
0024 
0025 /*
0026  * Matrox G400 DDC registers.
0027  */
0028 
0029 #define MATROX_G400_DDC_CLK     (1<<4)
0030 #define MATROX_G400_DDC_DATA        (1<<1)
0031 
0032 #define MATROX_BASE         0x3C00
0033 #define MATROX_STATUS           0x1e14
0034 
0035 #define MATROX_PORT_INDEX_OFFSET    0x00
0036 #define MATROX_PORT_DATA_OFFSET     0x0A
0037 
0038 #define MATROX_GET_CONTROL      0x2A
0039 #define MATROX_GET_DATA         0x2B
0040 #define MATROX_CURSOR_CTL       0x06
0041 
0042 struct matrox_device
0043 {
0044     void __iomem *base_addr;
0045     void __iomem *port_index;
0046     void __iomem *port_data;
0047     u8 data_mask;
0048 
0049     unsigned long phys_addr;
0050     void __iomem *virt_addr;
0051     unsigned long found;
0052 
0053     struct w1_bus_master *bus_master;
0054 };
0055 
0056 /*
0057  * These functions read and write DDC Data bit.
0058  *
0059  * Using tristate pins, since i can't find any open-drain pin in whole motherboard.
0060  * Unfortunately we can't connect to Intel's 82801xx IO controller
0061  * since we don't know motherboard schema, which has pretty unused(may be not) GPIO.
0062  *
0063  * I've heard that PIIX also has open drain pin.
0064  *
0065  * Port mapping.
0066  */
0067 static __inline__ u8 matrox_w1_read_reg(struct matrox_device *dev, u8 reg)
0068 {
0069     u8 ret;
0070 
0071     writeb(reg, dev->port_index);
0072     ret = readb(dev->port_data);
0073     barrier();
0074 
0075     return ret;
0076 }
0077 
0078 static __inline__ void matrox_w1_write_reg(struct matrox_device *dev, u8 reg, u8 val)
0079 {
0080     writeb(reg, dev->port_index);
0081     writeb(val, dev->port_data);
0082     wmb();
0083 }
0084 
0085 static void matrox_w1_write_ddc_bit(void *data, u8 bit)
0086 {
0087     u8 ret;
0088     struct matrox_device *dev = data;
0089 
0090     if (bit)
0091         bit = 0;
0092     else
0093         bit = dev->data_mask;
0094 
0095     ret = matrox_w1_read_reg(dev, MATROX_GET_CONTROL);
0096     matrox_w1_write_reg(dev, MATROX_GET_CONTROL, ((ret & ~dev->data_mask) | bit));
0097     matrox_w1_write_reg(dev, MATROX_GET_DATA, 0x00);
0098 }
0099 
0100 static u8 matrox_w1_read_ddc_bit(void *data)
0101 {
0102     u8 ret;
0103     struct matrox_device *dev = data;
0104 
0105     ret = matrox_w1_read_reg(dev, MATROX_GET_DATA);
0106 
0107     return ret;
0108 }
0109 
0110 static void matrox_w1_hw_init(struct matrox_device *dev)
0111 {
0112     matrox_w1_write_reg(dev, MATROX_GET_DATA, 0xFF);
0113     matrox_w1_write_reg(dev, MATROX_GET_CONTROL, 0x00);
0114 }
0115 
0116 static int matrox_w1_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
0117 {
0118     struct matrox_device *dev;
0119     int err;
0120 
0121     if (pdev->vendor != PCI_VENDOR_ID_MATROX || pdev->device != PCI_DEVICE_ID_MATROX_G400)
0122         return -ENODEV;
0123 
0124     dev = kzalloc(sizeof(struct matrox_device) +
0125                sizeof(struct w1_bus_master), GFP_KERNEL);
0126     if (!dev) {
0127         dev_err(&pdev->dev,
0128             "%s: Failed to create new matrox_device object.\n",
0129             __func__);
0130         return -ENOMEM;
0131     }
0132 
0133 
0134     dev->bus_master = (struct w1_bus_master *)(dev + 1);
0135 
0136     /*
0137      * True for G400, for some other we need resource 0, see drivers/video/matrox/matroxfb_base.c
0138      */
0139 
0140     dev->phys_addr = pci_resource_start(pdev, 1);
0141 
0142     dev->virt_addr = ioremap(dev->phys_addr, 16384);
0143     if (!dev->virt_addr) {
0144         dev_err(&pdev->dev, "%s: failed to ioremap(0x%lx, %d).\n",
0145             __func__, dev->phys_addr, 16384);
0146         err = -EIO;
0147         goto err_out_free_device;
0148     }
0149 
0150     dev->base_addr = dev->virt_addr + MATROX_BASE;
0151     dev->port_index = dev->base_addr + MATROX_PORT_INDEX_OFFSET;
0152     dev->port_data = dev->base_addr + MATROX_PORT_DATA_OFFSET;
0153     dev->data_mask = (MATROX_G400_DDC_DATA);
0154 
0155     matrox_w1_hw_init(dev);
0156 
0157     dev->bus_master->data = dev;
0158     dev->bus_master->read_bit = &matrox_w1_read_ddc_bit;
0159     dev->bus_master->write_bit = &matrox_w1_write_ddc_bit;
0160 
0161     err = w1_add_master_device(dev->bus_master);
0162     if (err)
0163         goto err_out_free_device;
0164 
0165     pci_set_drvdata(pdev, dev);
0166 
0167     dev->found = 1;
0168 
0169     dev_info(&pdev->dev, "Matrox G400 GPIO transport layer for 1-wire.\n");
0170 
0171     return 0;
0172 
0173 err_out_free_device:
0174     if (dev->virt_addr)
0175         iounmap(dev->virt_addr);
0176     kfree(dev);
0177 
0178     return err;
0179 }
0180 
0181 static void matrox_w1_remove(struct pci_dev *pdev)
0182 {
0183     struct matrox_device *dev = pci_get_drvdata(pdev);
0184 
0185     if (dev->found) {
0186         w1_remove_master_device(dev->bus_master);
0187         iounmap(dev->virt_addr);
0188     }
0189     kfree(dev);
0190 }
0191 
0192 static struct pci_device_id matrox_w1_tbl[] = {
0193     { PCI_DEVICE(PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400) },
0194     { },
0195 };
0196 MODULE_DEVICE_TABLE(pci, matrox_w1_tbl);
0197 
0198 static struct pci_driver matrox_w1_pci_driver = {
0199     .name = "matrox_w1",
0200     .id_table = matrox_w1_tbl,
0201     .probe = matrox_w1_probe,
0202     .remove = matrox_w1_remove,
0203 };
0204 module_pci_driver(matrox_w1_pci_driver);
0205 
0206 MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>");
0207 MODULE_DESCRIPTION("Driver for transport(Dallas 1-wire protocol) over VGA DDC(matrox gpio).");
0208 MODULE_LICENSE("GPL");