2005-04-16 15:20:36 -07:00
/*
2005-05-20 22:33:25 +04:00
* matrox_w1 . c
2005-04-16 15:20:36 -07:00
*
* Copyright ( c ) 2004 Evgeniy Polyakov < johnpol @ 2 ka . mipt . ru >
2005-05-20 22:33:25 +04:00
*
2005-04-16 15:20:36 -07:00
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
# include <asm/atomic.h>
# include <asm/types.h>
# include <asm/io.h>
# include <linux/delay.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/list.h>
# include <linux/interrupt.h>
# include <linux/spinlock.h>
# include <linux/timer.h>
# include <linux/slab.h>
# include <linux/pci_ids.h>
# include <linux/pci.h>
# include <linux/timer.h>
# include "w1.h"
# include "w1_int.h"
# include "w1_log.h"
MODULE_LICENSE ( " GPL " ) ;
MODULE_AUTHOR ( " Evgeniy Polyakov <johnpol@2ka.mipt.ru> " ) ;
MODULE_DESCRIPTION ( " Driver for transport(Dallas 1-wire prtocol) over VGA DDC(matrox gpio). " ) ;
static struct pci_device_id matrox_w1_tbl [ ] = {
{ PCI_DEVICE ( PCI_VENDOR_ID_MATROX , PCI_DEVICE_ID_MATROX_G400 ) } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( pci , matrox_w1_tbl ) ;
static int __devinit matrox_w1_probe ( struct pci_dev * , const struct pci_device_id * ) ;
static void __devexit matrox_w1_remove ( struct pci_dev * ) ;
static struct pci_driver matrox_w1_pci_driver = {
. name = " matrox_w1 " ,
. id_table = matrox_w1_tbl ,
. probe = matrox_w1_probe ,
. remove = __devexit_p ( matrox_w1_remove ) ,
} ;
2005-05-20 22:33:25 +04:00
/*
2005-04-16 15:20:36 -07:00
* Matrox G400 DDC registers .
*/
# define MATROX_G400_DDC_CLK (1<<4)
# define MATROX_G400_DDC_DATA (1<<1)
# define MATROX_BASE 0x3C00
# define MATROX_STATUS 0x1e14
# define MATROX_PORT_INDEX_OFFSET 0x00
# define MATROX_PORT_DATA_OFFSET 0x0A
# define MATROX_GET_CONTROL 0x2A
# define MATROX_GET_DATA 0x2B
# define MATROX_CURSOR_CTL 0x06
struct matrox_device
{
void __iomem * base_addr ;
void __iomem * port_index ;
void __iomem * port_data ;
u8 data_mask ;
unsigned long phys_addr ;
void __iomem * virt_addr ;
unsigned long found ;
struct w1_bus_master * bus_master ;
} ;
static u8 matrox_w1_read_ddc_bit ( unsigned long ) ;
static void matrox_w1_write_ddc_bit ( unsigned long , u8 ) ;
/*
* These functions read and write DDC Data bit .
*
* Using tristate pins , since i can ' t find any open - drain pin in whole motherboard .
* Unfortunately we can ' t connect to Intel ' s 82801 xx IO controller
* since we don ' t know motherboard schema , wich has pretty unused ( may be not ) GPIO .
*
* I ' ve heard that PIIX also has open drain pin .
*
* Port mapping .
*/
static __inline__ u8 matrox_w1_read_reg ( struct matrox_device * dev , u8 reg )
{
u8 ret ;
writeb ( reg , dev - > port_index ) ;
ret = readb ( dev - > port_data ) ;
barrier ( ) ;
return ret ;
}
static __inline__ void matrox_w1_write_reg ( struct matrox_device * dev , u8 reg , u8 val )
{
writeb ( reg , dev - > port_index ) ;
writeb ( val , dev - > port_data ) ;
wmb ( ) ;
}
static void matrox_w1_write_ddc_bit ( unsigned long data , u8 bit )
{
u8 ret ;
struct matrox_device * dev = ( struct matrox_device * ) data ;
if ( bit )
bit = 0 ;
else
bit = dev - > data_mask ;
ret = matrox_w1_read_reg ( dev , MATROX_GET_CONTROL ) ;
matrox_w1_write_reg ( dev , MATROX_GET_CONTROL , ( ( ret & ~ dev - > data_mask ) | bit ) ) ;
matrox_w1_write_reg ( dev , MATROX_GET_DATA , 0x00 ) ;
}
static u8 matrox_w1_read_ddc_bit ( unsigned long data )
{
u8 ret ;
struct matrox_device * dev = ( struct matrox_device * ) data ;
ret = matrox_w1_read_reg ( dev , MATROX_GET_DATA ) ;
return ret ;
}
static void matrox_w1_hw_init ( struct matrox_device * dev )
{
matrox_w1_write_reg ( dev , MATROX_GET_DATA , 0xFF ) ;
matrox_w1_write_reg ( dev , MATROX_GET_CONTROL , 0x00 ) ;
}
static int __devinit matrox_w1_probe ( struct pci_dev * pdev , const struct pci_device_id * ent )
{
struct matrox_device * dev ;
int err ;
assert ( pdev ! = NULL ) ;
assert ( ent ! = NULL ) ;
if ( pdev - > vendor ! = PCI_VENDOR_ID_MATROX | | pdev - > device ! = PCI_DEVICE_ID_MATROX_G400 )
return - ENODEV ;
dev = kmalloc ( sizeof ( struct matrox_device ) +
sizeof ( struct w1_bus_master ) , GFP_KERNEL ) ;
if ( ! dev ) {
dev_err ( & pdev - > dev ,
" %s: Failed to create new matrox_device object. \n " ,
__func__ ) ;
return - ENOMEM ;
}
memset ( dev , 0 , sizeof ( struct matrox_device ) + sizeof ( struct w1_bus_master ) ) ;
dev - > bus_master = ( struct w1_bus_master * ) ( dev + 1 ) ;
2005-05-20 22:33:25 +04:00
/*
* True for G400 , for some other we need resource 0 , see drivers / video / matrox / matroxfb_base . c
2005-04-16 15:20:36 -07:00
*/
dev - > phys_addr = pci_resource_start ( pdev , 1 ) ;
dev - > virt_addr = ioremap_nocache ( dev - > phys_addr , 16384 ) ;
if ( ! dev - > virt_addr ) {
dev_err ( & pdev - > dev , " %s: failed to ioremap(0x%lx, %d). \n " ,
__func__ , dev - > phys_addr , 16384 ) ;
err = - EIO ;
goto err_out_free_device ;
}
dev - > base_addr = dev - > virt_addr + MATROX_BASE ;
dev - > port_index = dev - > base_addr + MATROX_PORT_INDEX_OFFSET ;
dev - > port_data = dev - > base_addr + MATROX_PORT_DATA_OFFSET ;
dev - > data_mask = ( MATROX_G400_DDC_DATA ) ;
matrox_w1_hw_init ( dev ) ;
dev - > bus_master - > data = ( unsigned long ) dev ;
dev - > bus_master - > read_bit = & matrox_w1_read_ddc_bit ;
dev - > bus_master - > write_bit = & matrox_w1_write_ddc_bit ;
err = w1_add_master_device ( dev - > bus_master ) ;
if ( err )
goto err_out_free_device ;
pci_set_drvdata ( pdev , dev ) ;
dev - > found = 1 ;
dev_info ( & pdev - > dev , " Matrox G400 GPIO transport layer for 1-wire. \n " ) ;
return 0 ;
err_out_free_device :
kfree ( dev ) ;
return err ;
}
static void __devexit matrox_w1_remove ( struct pci_dev * pdev )
{
struct matrox_device * dev = pci_get_drvdata ( pdev ) ;
assert ( dev ! = NULL ) ;
if ( dev - > found ) {
w1_remove_master_device ( dev - > bus_master ) ;
iounmap ( dev - > virt_addr ) ;
}
kfree ( dev ) ;
}
static int __init matrox_w1_init ( void )
{
return pci_register_driver ( & matrox_w1_pci_driver ) ;
}
static void __exit matrox_w1_fini ( void )
{
pci_unregister_driver ( & matrox_w1_pci_driver ) ;
}
module_init ( matrox_w1_init ) ;
module_exit ( matrox_w1_fini ) ;