linux/drivers/video/matrox/i2c-matroxfb.c
<<
>>
Prefs
   1/*
   2 *
   3 * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450.
   4 *
   5 * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
   6 *
   7 * Version: 1.64 2002/06/10
   8 *
   9 * See matroxfb_base.c for contributors.
  10 *
  11 */
  12
  13#include "matroxfb_base.h"
  14#include "matroxfb_maven.h"
  15#include <linux/i2c.h>
  16#include <linux/slab.h>
  17#include <linux/i2c-algo-bit.h>
  18
  19/* MGA-TVO I2C for G200, G400 */
  20#define MAT_CLK         0x20
  21#define MAT_DATA        0x10
  22/* primary head DDC for Mystique(?), G100, G200, G400 */
  23#define DDC1_CLK        0x08
  24#define DDC1_DATA       0x02
  25/* primary head DDC for Millennium, Millennium II */
  26#define DDC1B_CLK       0x10
  27#define DDC1B_DATA      0x04
  28/* secondary head DDC for G400 */
  29#define DDC2_CLK        0x04
  30#define DDC2_DATA       0x01
  31
  32/******************************************************/
  33
  34struct matroxfb_dh_maven_info {
  35        struct i2c_bit_adapter  maven;
  36        struct i2c_bit_adapter  ddc1;
  37        struct i2c_bit_adapter  ddc2;
  38};
  39
  40static int matroxfb_read_gpio(struct matrox_fb_info* minfo) {
  41        unsigned long flags;
  42        int v;
  43
  44        matroxfb_DAC_lock_irqsave(flags);
  45        v = matroxfb_DAC_in(minfo, DAC_XGENIODATA);
  46        matroxfb_DAC_unlock_irqrestore(flags);
  47        return v;
  48}
  49
  50static void matroxfb_set_gpio(struct matrox_fb_info* minfo, int mask, int val) {
  51        unsigned long flags;
  52        int v;
  53
  54        matroxfb_DAC_lock_irqsave(flags);
  55        v = (matroxfb_DAC_in(minfo, DAC_XGENIOCTRL) & mask) | val;
  56        matroxfb_DAC_out(minfo, DAC_XGENIOCTRL, v);
  57        /* We must reset GENIODATA very often... XFree plays with this register */
  58        matroxfb_DAC_out(minfo, DAC_XGENIODATA, 0x00);
  59        matroxfb_DAC_unlock_irqrestore(flags);
  60}
  61
  62/* software I2C functions */
  63static inline void matroxfb_i2c_set(struct matrox_fb_info* minfo, int mask, int state) {
  64        if (state)
  65                state = 0;
  66        else
  67                state = mask;
  68        matroxfb_set_gpio(minfo, ~mask, state);
  69}
  70
  71static void matroxfb_gpio_setsda(void* data, int state) {
  72        struct i2c_bit_adapter* b = data;
  73        matroxfb_i2c_set(b->minfo, b->mask.data, state);
  74}
  75
  76static void matroxfb_gpio_setscl(void* data, int state) {
  77        struct i2c_bit_adapter* b = data;
  78        matroxfb_i2c_set(b->minfo, b->mask.clock, state);
  79}
  80
  81static int matroxfb_gpio_getsda(void* data) {
  82        struct i2c_bit_adapter* b = data;
  83        return (matroxfb_read_gpio(b->minfo) & b->mask.data) ? 1 : 0;
  84}
  85
  86static int matroxfb_gpio_getscl(void* data) {
  87        struct i2c_bit_adapter* b = data;
  88        return (matroxfb_read_gpio(b->minfo) & b->mask.clock) ? 1 : 0;
  89}
  90
  91static const struct i2c_algo_bit_data matrox_i2c_algo_template =
  92{
  93        .setsda         = matroxfb_gpio_setsda,
  94        .setscl         = matroxfb_gpio_setscl,
  95        .getsda         = matroxfb_gpio_getsda,
  96        .getscl         = matroxfb_gpio_getscl,
  97        .udelay         = 10,
  98        .timeout        = 100,
  99};
 100
 101static int i2c_bus_reg(struct i2c_bit_adapter* b, struct matrox_fb_info* minfo, 
 102                unsigned int data, unsigned int clock, const char *name,
 103                int class)
 104{
 105        int err;
 106
 107        b->minfo = minfo;
 108        b->mask.data = data;
 109        b->mask.clock = clock;
 110        b->adapter.owner = THIS_MODULE;
 111        snprintf(b->adapter.name, sizeof(b->adapter.name), name,
 112                minfo->fbcon.node);
 113        i2c_set_adapdata(&b->adapter, b);
 114        b->adapter.class = class;
 115        b->adapter.algo_data = &b->bac;
 116        b->adapter.dev.parent = &minfo->pcidev->dev;
 117        b->bac = matrox_i2c_algo_template;
 118        b->bac.data = b;
 119        err = i2c_bit_add_bus(&b->adapter);
 120        b->initialized = !err;
 121        return err;
 122}
 123
 124static void i2c_bit_bus_del(struct i2c_bit_adapter* b) {
 125        if (b->initialized) {
 126                i2c_del_adapter(&b->adapter);
 127                b->initialized = 0;
 128        }
 129}
 130
 131static inline void i2c_maven_done(struct matroxfb_dh_maven_info* minfo2) {
 132        i2c_bit_bus_del(&minfo2->maven);
 133}
 134
 135static inline void i2c_ddc1_done(struct matroxfb_dh_maven_info* minfo2) {
 136        i2c_bit_bus_del(&minfo2->ddc1);
 137}
 138
 139static inline void i2c_ddc2_done(struct matroxfb_dh_maven_info* minfo2) {
 140        i2c_bit_bus_del(&minfo2->ddc2);
 141}
 142
 143static void* i2c_matroxfb_probe(struct matrox_fb_info* minfo) {
 144        int err;
 145        unsigned long flags;
 146        struct matroxfb_dh_maven_info* m2info;
 147
 148        m2info = kzalloc(sizeof(*m2info), GFP_KERNEL);
 149        if (!m2info)
 150                return NULL;
 151
 152        matroxfb_DAC_lock_irqsave(flags);
 153        matroxfb_DAC_out(minfo, DAC_XGENIODATA, 0xFF);
 154        matroxfb_DAC_out(minfo, DAC_XGENIOCTRL, 0x00);
 155        matroxfb_DAC_unlock_irqrestore(flags);
 156
 157        switch (minfo->chip) {
 158                case MGA_2064:
 159                case MGA_2164:
 160                        err = i2c_bus_reg(&m2info->ddc1, minfo,
 161                                          DDC1B_DATA, DDC1B_CLK,
 162                                          "DDC:fb%u #0", I2C_CLASS_DDC);
 163                        break;
 164                default:
 165                        err = i2c_bus_reg(&m2info->ddc1, minfo,
 166                                          DDC1_DATA, DDC1_CLK,
 167                                          "DDC:fb%u #0", I2C_CLASS_DDC);
 168                        break;
 169        }
 170        if (err)
 171                goto fail_ddc1;
 172        if (minfo->devflags.dualhead) {
 173                err = i2c_bus_reg(&m2info->ddc2, minfo,
 174                                  DDC2_DATA, DDC2_CLK,
 175                                  "DDC:fb%u #1", I2C_CLASS_DDC);
 176                if (err == -ENODEV) {
 177                        printk(KERN_INFO "i2c-matroxfb: VGA->TV plug detected, DDC unavailable.\n");
 178                } else if (err)
 179                        printk(KERN_INFO "i2c-matroxfb: Could not register secondary output i2c bus. Continuing anyway.\n");
 180                /* Register maven bus even on G450/G550 */
 181                err = i2c_bus_reg(&m2info->maven, minfo,
 182                                  MAT_DATA, MAT_CLK, "MAVEN:fb%u", 0);
 183                if (err)
 184                        printk(KERN_INFO "i2c-matroxfb: Could not register Maven i2c bus. Continuing anyway.\n");
 185                else {
 186                        struct i2c_board_info maven_info = {
 187                                I2C_BOARD_INFO("maven", 0x1b),
 188                        };
 189                        unsigned short const addr_list[2] = {
 190                                0x1b, I2C_CLIENT_END
 191                        };
 192
 193                        i2c_new_probed_device(&m2info->maven.adapter,
 194                                              &maven_info, addr_list, NULL);
 195                }
 196        }
 197        return m2info;
 198fail_ddc1:;
 199        kfree(m2info);
 200        printk(KERN_ERR "i2c-matroxfb: Could not register primary adapter DDC bus.\n");
 201        return NULL;
 202}
 203
 204static void i2c_matroxfb_remove(struct matrox_fb_info* minfo, void* data) {
 205        struct matroxfb_dh_maven_info* m2info = data;
 206
 207        i2c_maven_done(m2info);
 208        i2c_ddc2_done(m2info);
 209        i2c_ddc1_done(m2info);
 210        kfree(m2info);
 211}
 212
 213static struct matroxfb_driver i2c_matroxfb = {
 214        .node =         LIST_HEAD_INIT(i2c_matroxfb.node),
 215        .name =         "i2c-matroxfb",
 216        .probe =        i2c_matroxfb_probe,
 217        .remove =       i2c_matroxfb_remove,
 218};
 219
 220static int __init i2c_matroxfb_init(void) {
 221        if (matroxfb_register_driver(&i2c_matroxfb)) {
 222                printk(KERN_ERR "i2c-matroxfb: failed to register driver\n");
 223                return -ENXIO;
 224        }
 225        return 0;
 226}
 227
 228static void __exit i2c_matroxfb_exit(void) {
 229        matroxfb_unregister_driver(&i2c_matroxfb);
 230}
 231
 232MODULE_AUTHOR("(c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
 233MODULE_DESCRIPTION("Support module providing I2C buses present on Matrox videocards");
 234
 235module_init(i2c_matroxfb_init);
 236module_exit(i2c_matroxfb_exit);
 237/* no __setup required */
 238MODULE_LICENSE("GPL");
 239