2005-04-16 15:20:36 -07:00
/*
*
* Hardware accelerated Matrox Millennium I , II , Mystique , G100 , G200 , G400 and G450 .
*
* ( c ) 1998 - 2002 Petr Vandrovec < vandrove @ vc . cvut . cz >
*
* Version : 1.64 2002 / 06 / 10
*
* See matroxfb_base . c for contributors .
*
*/
# include "matroxfb_base.h"
# include "matroxfb_maven.h"
# include <linux/i2c.h>
# include <linux/i2c-algo-bit.h>
/* MGA-TVO I2C for G200, G400 */
# define MAT_CLK 0x20
# define MAT_DATA 0x10
/* primary head DDC for Mystique(?), G100, G200, G400 */
# define DDC1_CLK 0x08
# define DDC1_DATA 0x02
/* primary head DDC for Millennium, Millennium II */
# define DDC1B_CLK 0x10
# define DDC1B_DATA 0x04
/* secondary head DDC for G400 */
# define DDC2_CLK 0x04
# define DDC2_DATA 0x01
/******************************************************/
struct matroxfb_dh_maven_info {
struct i2c_bit_adapter maven ;
struct i2c_bit_adapter ddc1 ;
struct i2c_bit_adapter ddc2 ;
} ;
static int matroxfb_read_gpio ( struct matrox_fb_info * minfo ) {
unsigned long flags ;
int v ;
matroxfb_DAC_lock_irqsave ( flags ) ;
v = matroxfb_DAC_in ( PMINFO DAC_XGENIODATA ) ;
matroxfb_DAC_unlock_irqrestore ( flags ) ;
return v ;
}
static void matroxfb_set_gpio ( struct matrox_fb_info * minfo , int mask , int val ) {
unsigned long flags ;
int v ;
matroxfb_DAC_lock_irqsave ( flags ) ;
v = ( matroxfb_DAC_in ( PMINFO DAC_XGENIOCTRL ) & mask ) | val ;
matroxfb_DAC_out ( PMINFO DAC_XGENIOCTRL , v ) ;
/* We must reset GENIODATA very often... XFree plays with this register */
matroxfb_DAC_out ( PMINFO DAC_XGENIODATA , 0x00 ) ;
matroxfb_DAC_unlock_irqrestore ( flags ) ;
}
/* software I2C functions */
static inline void matroxfb_i2c_set ( struct matrox_fb_info * minfo , int mask , int state ) {
if ( state )
state = 0 ;
else
state = mask ;
matroxfb_set_gpio ( minfo , ~ mask , state ) ;
}
static void matroxfb_gpio_setsda ( void * data , int state ) {
struct i2c_bit_adapter * b = data ;
matroxfb_i2c_set ( b - > minfo , b - > mask . data , state ) ;
}
static void matroxfb_gpio_setscl ( void * data , int state ) {
struct i2c_bit_adapter * b = data ;
matroxfb_i2c_set ( b - > minfo , b - > mask . clock , state ) ;
}
static int matroxfb_gpio_getsda ( void * data ) {
struct i2c_bit_adapter * b = data ;
return ( matroxfb_read_gpio ( b - > minfo ) & b - > mask . data ) ? 1 : 0 ;
}
static int matroxfb_gpio_getscl ( void * data ) {
struct i2c_bit_adapter * b = data ;
return ( matroxfb_read_gpio ( b - > minfo ) & b - > mask . clock ) ? 1 : 0 ;
}
2008-08-12 15:08:54 -07:00
static const struct i2c_algo_bit_data matrox_i2c_algo_template =
2005-04-16 15:20:36 -07:00
{
2006-08-13 23:40:09 +02:00
. setsda = matroxfb_gpio_setsda ,
. setscl = matroxfb_gpio_setscl ,
. getsda = matroxfb_gpio_getsda ,
. getscl = matroxfb_gpio_getscl ,
. udelay = 10 ,
. timeout = 100 ,
2005-04-16 15:20:36 -07:00
} ;
static int i2c_bus_reg ( struct i2c_bit_adapter * b , struct matrox_fb_info * minfo ,
2008-07-14 22:38:28 +02:00
unsigned int data , unsigned int clock , const char * name ,
int class )
{
2005-04-16 15:20:36 -07:00
int err ;
b - > minfo = minfo ;
b - > mask . data = data ;
b - > mask . clock = clock ;
2008-08-12 15:08:54 -07:00
b - > adapter . owner = THIS_MODULE ;
2007-05-01 23:26:28 +02:00
snprintf ( b - > adapter . name , sizeof ( b - > adapter . name ) , name ,
2005-04-16 15:20:36 -07:00
minfo - > fbcon . node ) ;
i2c_set_adapdata ( & b - > adapter , b ) ;
2008-07-14 22:38:28 +02:00
b - > adapter . class = class ;
2005-04-16 15:20:36 -07:00
b - > adapter . algo_data = & b - > bac ;
2007-02-13 22:09:03 +01:00
b - > adapter . dev . parent = & ACCESS_FBINFO ( pcidev ) - > dev ;
2005-04-16 15:20:36 -07:00
b - > bac = matrox_i2c_algo_template ;
b - > bac . data = b ;
err = i2c_bit_add_bus ( & b - > adapter ) ;
b - > initialized = ! err ;
return err ;
}
static void i2c_bit_bus_del ( struct i2c_bit_adapter * b ) {
if ( b - > initialized ) {
2006-12-10 21:21:33 +01:00
i2c_del_adapter ( & b - > adapter ) ;
2005-04-16 15:20:36 -07:00
b - > initialized = 0 ;
}
}
static inline void i2c_maven_done ( struct matroxfb_dh_maven_info * minfo2 ) {
i2c_bit_bus_del ( & minfo2 - > maven ) ;
}
static inline void i2c_ddc1_done ( struct matroxfb_dh_maven_info * minfo2 ) {
i2c_bit_bus_del ( & minfo2 - > ddc1 ) ;
}
static inline void i2c_ddc2_done ( struct matroxfb_dh_maven_info * minfo2 ) {
i2c_bit_bus_del ( & minfo2 - > ddc2 ) ;
}
static void * i2c_matroxfb_probe ( struct matrox_fb_info * minfo ) {
int err ;
unsigned long flags ;
struct matroxfb_dh_maven_info * m2info ;
2007-02-12 00:55:07 -08:00
m2info = kzalloc ( sizeof ( * m2info ) , GFP_KERNEL ) ;
2005-04-16 15:20:36 -07:00
if ( ! m2info )
return NULL ;
matroxfb_DAC_lock_irqsave ( flags ) ;
matroxfb_DAC_out ( PMINFO DAC_XGENIODATA , 0xFF ) ;
matroxfb_DAC_out ( PMINFO DAC_XGENIOCTRL , 0x00 ) ;
matroxfb_DAC_unlock_irqrestore ( flags ) ;
switch ( ACCESS_FBINFO ( chip ) ) {
case MGA_2064 :
case MGA_2164 :
2008-07-14 22:38:28 +02:00
err = i2c_bus_reg ( & m2info - > ddc1 , minfo ,
DDC1B_DATA , DDC1B_CLK ,
" DDC:fb%u #0 " , I2C_CLASS_DDC ) ;
2005-04-16 15:20:36 -07:00
break ;
default :
2008-07-14 22:38:28 +02:00
err = i2c_bus_reg ( & m2info - > ddc1 , minfo ,
DDC1_DATA , DDC1_CLK ,
" DDC:fb%u #0 " , I2C_CLASS_DDC ) ;
2005-04-16 15:20:36 -07:00
break ;
}
if ( err )
goto fail_ddc1 ;
if ( ACCESS_FBINFO ( devflags . dualhead ) ) {
2008-07-14 22:38:28 +02:00
err = i2c_bus_reg ( & m2info - > ddc2 , minfo ,
DDC2_DATA , DDC2_CLK ,
" DDC:fb%u #1 " , I2C_CLASS_DDC ) ;
2005-04-16 15:20:36 -07:00
if ( err = = - ENODEV ) {
printk ( KERN_INFO " i2c-matroxfb: VGA->TV plug detected, DDC unavailable. \n " ) ;
} else if ( err )
printk ( KERN_INFO " i2c-matroxfb: Could not register secondary output i2c bus. Continuing anyway. \n " ) ;
/* Register maven bus even on G450/G550 */
2008-07-14 22:38:28 +02:00
err = i2c_bus_reg ( & m2info - > maven , minfo ,
MAT_DATA , MAT_CLK , " MAVEN:fb%u " , 0 ) ;
2005-04-16 15:20:36 -07:00
if ( err )
printk ( KERN_INFO " i2c-matroxfb: Could not register Maven i2c bus. Continuing anyway. \n " ) ;
2008-08-12 15:08:55 -07:00
else {
struct i2c_board_info maven_info = {
I2C_BOARD_INFO ( " maven " , 0x1b ) ,
} ;
unsigned short const addr_list [ 2 ] = {
0x1b , I2C_CLIENT_END
} ;
i2c_new_probed_device ( & m2info - > maven . adapter ,
& maven_info , addr_list ) ;
}
2005-04-16 15:20:36 -07:00
}
return m2info ;
fail_ddc1 : ;
kfree ( m2info ) ;
printk ( KERN_ERR " i2c-matroxfb: Could not register primary adapter DDC bus. \n " ) ;
return NULL ;
}
static void i2c_matroxfb_remove ( struct matrox_fb_info * minfo , void * data ) {
struct matroxfb_dh_maven_info * m2info = data ;
i2c_maven_done ( m2info ) ;
i2c_ddc2_done ( m2info ) ;
i2c_ddc1_done ( m2info ) ;
kfree ( m2info ) ;
}
static struct matroxfb_driver i2c_matroxfb = {
. node = LIST_HEAD_INIT ( i2c_matroxfb . node ) ,
. name = " i2c-matroxfb " ,
. probe = i2c_matroxfb_probe ,
. remove = i2c_matroxfb_remove ,
} ;
static int __init i2c_matroxfb_init ( void ) {
if ( matroxfb_register_driver ( & i2c_matroxfb ) ) {
printk ( KERN_ERR " i2c-matroxfb: failed to register driver \n " ) ;
return - ENXIO ;
}
return 0 ;
}
static void __exit i2c_matroxfb_exit ( void ) {
matroxfb_unregister_driver ( & i2c_matroxfb ) ;
}
MODULE_AUTHOR ( " (c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz> " ) ;
MODULE_DESCRIPTION ( " Support module providing I2C buses present on Matrox videocards " ) ;
module_init ( i2c_matroxfb_init ) ;
module_exit ( i2c_matroxfb_exit ) ;
/* no __setup required */
MODULE_LICENSE ( " GPL " ) ;