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