2019-05-19 15:08:20 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2006-06-24 09:22:13 +04:00
/* parport_sunbpp.c: Parallel-port routines for SBUS
2005-04-17 02:20:36 +04:00
*
* Author : Derrick J . Brashear < shadow @ dementia . org >
*
* based on work by :
* Phil Blundell < philb @ gnu . org >
* Tim Waugh < tim @ cyberelk . demon . co . uk >
* Jose Renau < renau @ acm . org >
* David Campbell < campbell @ tirian . che . curtin . edu . au >
* Grant Guenther < grant @ torque . net >
* Eddie C . Dost < ecd @ skynet . be >
* Stephen Williams ( steve @ icarus . com )
* Gus Baldauf ( gbaldauf @ ix . netcom . com )
* Peter Zaitcev
* Tom Dyas
2006-06-24 09:22:13 +04:00
*
* Updated to new SBUS device framework : David S . Miller < davem @ davemloft . net >
*
2005-04-17 02:20:36 +04:00
*/
# include <linux/string.h>
# include <linux/module.h>
# include <linux/delay.h>
# include <linux/errno.h>
# include <linux/ioport.h>
# include <linux/kernel.h>
# include <linux/slab.h>
# include <linux/init.h>
2008-08-27 11:17:50 +04:00
# include <linux/of.h>
# include <linux/of_device.h>
2005-04-17 02:20:36 +04:00
# include <linux/parport.h>
# include <asm/ptrace.h>
# include <linux/interrupt.h>
# include <asm/io.h>
# include <asm/oplib.h> /* OpenProm Library */
# include <asm/dma.h> /* BPP uses LSI 64854 for DMA */
# include <asm/irq.h>
# include <asm/sunbpp.h>
# undef __SUNBPP_DEBUG
# ifdef __SUNBPP_DEBUG
# define dprintk(x) printk x
# else
# define dprintk(x)
# endif
static void parport_sunbpp_disable_irq ( struct parport * p )
{
struct bpp_regs __iomem * regs = ( struct bpp_regs __iomem * ) p - > base ;
u32 tmp ;
tmp = sbus_readl ( & regs - > p_csr ) ;
tmp & = ~ DMA_INT_ENAB ;
sbus_writel ( tmp , & regs - > p_csr ) ;
}
static void parport_sunbpp_enable_irq ( struct parport * p )
{
struct bpp_regs __iomem * regs = ( struct bpp_regs __iomem * ) p - > base ;
u32 tmp ;
tmp = sbus_readl ( & regs - > p_csr ) ;
tmp | = DMA_INT_ENAB ;
sbus_writel ( tmp , & regs - > p_csr ) ;
}
static void parport_sunbpp_write_data ( struct parport * p , unsigned char d )
{
struct bpp_regs __iomem * regs = ( struct bpp_regs __iomem * ) p - > base ;
sbus_writeb ( d , & regs - > p_dr ) ;
dprintk ( ( KERN_DEBUG " wrote 0x%x \n " , d ) ) ;
}
static unsigned char parport_sunbpp_read_data ( struct parport * p )
{
struct bpp_regs __iomem * regs = ( struct bpp_regs __iomem * ) p - > base ;
return sbus_readb ( & regs - > p_dr ) ;
}
static unsigned char status_sunbpp_to_pc ( struct parport * p )
{
struct bpp_regs __iomem * regs = ( struct bpp_regs __iomem * ) p - > base ;
unsigned char bits = 0 ;
unsigned char value_tcr = sbus_readb ( & regs - > p_tcr ) ;
unsigned char value_ir = sbus_readb ( & regs - > p_ir ) ;
if ( ! ( value_ir & P_IR_ERR ) )
bits | = PARPORT_STATUS_ERROR ;
if ( ! ( value_ir & P_IR_SLCT ) )
bits | = PARPORT_STATUS_SELECT ;
if ( ! ( value_ir & P_IR_PE ) )
bits | = PARPORT_STATUS_PAPEROUT ;
if ( value_tcr & P_TCR_ACK )
bits | = PARPORT_STATUS_ACK ;
if ( ! ( value_tcr & P_TCR_BUSY ) )
bits | = PARPORT_STATUS_BUSY ;
2007-04-24 10:33:17 +04:00
dprintk ( ( KERN_DEBUG " tcr 0x%x ir 0x%x \n " , value_tcr , value_ir ) ) ;
2005-04-17 02:20:36 +04:00
dprintk ( ( KERN_DEBUG " read status 0x%x \n " , bits ) ) ;
return bits ;
}
static unsigned char control_sunbpp_to_pc ( struct parport * p )
{
struct bpp_regs __iomem * regs = ( struct bpp_regs __iomem * ) p - > base ;
unsigned char bits = 0 ;
unsigned char value_tcr = sbus_readb ( & regs - > p_tcr ) ;
unsigned char value_or = sbus_readb ( & regs - > p_or ) ;
if ( ! ( value_tcr & P_TCR_DS ) )
bits | = PARPORT_CONTROL_STROBE ;
if ( ! ( value_or & P_OR_AFXN ) )
bits | = PARPORT_CONTROL_AUTOFD ;
if ( ! ( value_or & P_OR_INIT ) )
bits | = PARPORT_CONTROL_INIT ;
if ( value_or & P_OR_SLCT_IN )
bits | = PARPORT_CONTROL_SELECT ;
2007-04-24 10:33:17 +04:00
dprintk ( ( KERN_DEBUG " tcr 0x%x or 0x%x \n " , value_tcr , value_or ) ) ;
2005-04-17 02:20:36 +04:00
dprintk ( ( KERN_DEBUG " read control 0x%x \n " , bits ) ) ;
return bits ;
}
static unsigned char parport_sunbpp_read_control ( struct parport * p )
{
return control_sunbpp_to_pc ( p ) ;
}
static unsigned char parport_sunbpp_frob_control ( struct parport * p ,
unsigned char mask ,
unsigned char val )
{
struct bpp_regs __iomem * regs = ( struct bpp_regs __iomem * ) p - > base ;
unsigned char value_tcr = sbus_readb ( & regs - > p_tcr ) ;
unsigned char value_or = sbus_readb ( & regs - > p_or ) ;
2007-04-24 10:33:17 +04:00
dprintk ( ( KERN_DEBUG " frob1: tcr 0x%x or 0x%x \n " ,
value_tcr , value_or ) ) ;
2005-04-17 02:20:36 +04:00
if ( mask & PARPORT_CONTROL_STROBE ) {
if ( val & PARPORT_CONTROL_STROBE ) {
value_tcr & = ~ P_TCR_DS ;
} else {
value_tcr | = P_TCR_DS ;
}
}
if ( mask & PARPORT_CONTROL_AUTOFD ) {
if ( val & PARPORT_CONTROL_AUTOFD ) {
value_or & = ~ P_OR_AFXN ;
} else {
value_or | = P_OR_AFXN ;
}
}
if ( mask & PARPORT_CONTROL_INIT ) {
if ( val & PARPORT_CONTROL_INIT ) {
value_or & = ~ P_OR_INIT ;
} else {
value_or | = P_OR_INIT ;
}
}
if ( mask & PARPORT_CONTROL_SELECT ) {
if ( val & PARPORT_CONTROL_SELECT ) {
value_or | = P_OR_SLCT_IN ;
} else {
value_or & = ~ P_OR_SLCT_IN ;
}
}
sbus_writeb ( value_or , & regs - > p_or ) ;
sbus_writeb ( value_tcr , & regs - > p_tcr ) ;
2007-04-24 10:33:17 +04:00
dprintk ( ( KERN_DEBUG " frob2: tcr 0x%x or 0x%x \n " ,
value_tcr , value_or ) ) ;
2005-04-17 02:20:36 +04:00
return parport_sunbpp_read_control ( p ) ;
}
static void parport_sunbpp_write_control ( struct parport * p , unsigned char d )
{
const unsigned char wm = ( PARPORT_CONTROL_STROBE |
PARPORT_CONTROL_AUTOFD |
PARPORT_CONTROL_INIT |
PARPORT_CONTROL_SELECT ) ;
parport_sunbpp_frob_control ( p , wm , d & wm ) ;
}
static unsigned char parport_sunbpp_read_status ( struct parport * p )
{
return status_sunbpp_to_pc ( p ) ;
}
static void parport_sunbpp_data_forward ( struct parport * p )
{
struct bpp_regs __iomem * regs = ( struct bpp_regs __iomem * ) p - > base ;
unsigned char value_tcr = sbus_readb ( & regs - > p_tcr ) ;
dprintk ( ( KERN_DEBUG " forward \n " ) ) ;
value_tcr & = ~ P_TCR_DIR ;
sbus_writeb ( value_tcr , & regs - > p_tcr ) ;
}
static void parport_sunbpp_data_reverse ( struct parport * p )
{
struct bpp_regs __iomem * regs = ( struct bpp_regs __iomem * ) p - > base ;
u8 val = sbus_readb ( & regs - > p_tcr ) ;
dprintk ( ( KERN_DEBUG " reverse \n " ) ) ;
val | = P_TCR_DIR ;
sbus_writeb ( val , & regs - > p_tcr ) ;
}
static void parport_sunbpp_init_state ( struct pardevice * dev , struct parport_state * s )
{
s - > u . pc . ctr = 0xc ;
s - > u . pc . ecr = 0x0 ;
}
static void parport_sunbpp_save_state ( struct parport * p , struct parport_state * s )
{
s - > u . pc . ctr = parport_sunbpp_read_control ( p ) ;
}
static void parport_sunbpp_restore_state ( struct parport * p , struct parport_state * s )
{
parport_sunbpp_write_control ( p , s - > u . pc . ctr ) ;
}
static struct parport_operations parport_sunbpp_ops =
{
. write_data = parport_sunbpp_write_data ,
. read_data = parport_sunbpp_read_data ,
. write_control = parport_sunbpp_write_control ,
. read_control = parport_sunbpp_read_control ,
. frob_control = parport_sunbpp_frob_control ,
. read_status = parport_sunbpp_read_status ,
. enable_irq = parport_sunbpp_enable_irq ,
. disable_irq = parport_sunbpp_disable_irq ,
. data_forward = parport_sunbpp_data_forward ,
. data_reverse = parport_sunbpp_data_reverse ,
. init_state = parport_sunbpp_init_state ,
. save_state = parport_sunbpp_save_state ,
. restore_state = parport_sunbpp_restore_state ,
. epp_write_data = parport_ieee1284_epp_write_data ,
. epp_read_data = parport_ieee1284_epp_read_data ,
. epp_write_addr = parport_ieee1284_epp_write_addr ,
. epp_read_addr = parport_ieee1284_epp_read_addr ,
. ecp_write_data = parport_ieee1284_ecp_write_data ,
. ecp_read_data = parport_ieee1284_ecp_read_data ,
. ecp_write_addr = parport_ieee1284_ecp_write_addr ,
. compat_write_data = parport_ieee1284_write_compat ,
. nibble_read_data = parport_ieee1284_read_nibble ,
. byte_read_data = parport_ieee1284_read_byte ,
. owner = THIS_MODULE ,
} ;
2012-12-22 01:23:14 +04:00
static int bpp_probe ( struct platform_device * op )
2005-04-17 02:20:36 +04:00
{
struct parport_operations * ops ;
struct bpp_regs __iomem * regs ;
2008-08-27 11:17:50 +04:00
int irq , dma , err = 0 , size ;
2005-04-17 02:20:36 +04:00
unsigned char value_tcr ;
2008-08-27 11:17:50 +04:00
void __iomem * base ;
struct parport * p ;
2005-04-17 02:20:36 +04:00
2010-06-18 21:09:58 +04:00
irq = op - > archdata . irqs [ 0 ] ;
2008-08-27 11:17:50 +04:00
base = of_ioremap ( & op - > resource [ 0 ] , 0 ,
resource_size ( & op - > resource [ 0 ] ) ,
" sunbpp " ) ;
2005-04-17 02:20:36 +04:00
if ( ! base )
2006-06-24 09:22:13 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
2008-08-27 11:17:50 +04:00
size = resource_size ( & op - > resource [ 0 ] ) ;
2005-04-17 02:20:36 +04:00
dma = PARPORT_DMA_NONE ;
2013-03-11 20:39:22 +04:00
ops = kmemdup ( & parport_sunbpp_ops , sizeof ( struct parport_operations ) ,
GFP_KERNEL ) ;
2018-07-13 00:29:55 +03:00
if ( ! ops ) {
err = - ENOMEM ;
2006-06-24 09:22:13 +04:00
goto out_unmap ;
2018-07-13 00:29:55 +03:00
}
2005-04-17 02:20:36 +04:00
dprintk ( ( " register_port \n " ) ) ;
2018-07-13 00:29:55 +03:00
if ( ! ( p = parport_register_port ( ( unsigned long ) base , irq , dma , ops ) ) ) {
err = - ENOMEM ;
2006-06-24 09:22:13 +04:00
goto out_free_ops ;
2018-07-13 00:29:55 +03:00
}
2005-04-17 02:20:36 +04:00
p - > size = size ;
2008-08-27 11:17:50 +04:00
p - > dev = & op - > dev ;
2005-04-17 02:20:36 +04:00
2007-10-19 09:42:14 +04:00
if ( ( err = request_irq ( p - > irq , parport_irq_handler ,
2006-07-02 06:29:38 +04:00
IRQF_SHARED , p - > name , p ) ) ! = 0 ) {
2006-06-24 09:22:13 +04:00
goto out_put_port ;
2005-04-17 02:20:36 +04:00
}
2006-06-24 09:22:13 +04:00
2005-04-17 02:20:36 +04:00
parport_sunbpp_enable_irq ( p ) ;
regs = ( struct bpp_regs __iomem * ) p - > base ;
2006-06-24 09:22:13 +04:00
2005-04-17 02:20:36 +04:00
value_tcr = sbus_readb ( & regs - > p_tcr ) ;
value_tcr & = ~ P_TCR_DIR ;
sbus_writeb ( value_tcr , & regs - > p_tcr ) ;
2020-04-03 16:43:16 +03:00
pr_info ( " %s: sunbpp at 0x%lx \n " , p - > name , p - > base ) ;
2005-04-17 02:20:36 +04:00
2008-08-27 11:17:50 +04:00
dev_set_drvdata ( & op - > dev , p ) ;
2006-06-24 09:22:13 +04:00
parport_announce_port ( p ) ;
return 0 ;
2005-04-17 02:20:36 +04:00
2006-06-24 09:22:13 +04:00
out_put_port :
2005-04-17 02:20:36 +04:00
parport_put_port ( p ) ;
2006-06-24 09:22:13 +04:00
out_free_ops :
2005-04-17 02:20:36 +04:00
kfree ( ops ) ;
2006-06-24 09:22:13 +04:00
out_unmap :
2008-08-27 11:17:50 +04:00
of_iounmap ( & op - > resource [ 0 ] , base , size ) ;
2006-06-24 09:22:13 +04:00
2005-04-17 02:20:36 +04:00
return err ;
}
2012-12-22 01:23:14 +04:00
static int bpp_remove ( struct platform_device * op )
2006-06-24 09:22:13 +04:00
{
2008-08-27 11:17:50 +04:00
struct parport * p = dev_get_drvdata ( & op - > dev ) ;
2006-06-24 09:22:13 +04:00
struct parport_operations * ops = p - > ops ;
parport_remove_port ( p ) ;
if ( p - > irq ! = PARPORT_IRQ_NONE ) {
parport_sunbpp_disable_irq ( p ) ;
free_irq ( p - > irq , p ) ;
2005-04-17 02:20:36 +04:00
}
2006-06-24 09:22:13 +04:00
2008-08-27 11:17:50 +04:00
of_iounmap ( & op - > resource [ 0 ] , ( void __iomem * ) p - > base , p - > size ) ;
2006-06-24 09:22:13 +04:00
parport_put_port ( p ) ;
kfree ( ops ) ;
2008-08-27 11:17:50 +04:00
dev_set_drvdata ( & op - > dev , NULL ) ;
2006-06-24 09:22:13 +04:00
return 0 ;
}
2008-08-31 12:23:17 +04:00
static const struct of_device_id bpp_match [ ] = {
2006-06-24 09:22:13 +04:00
{
. name = " SUNW,bpp " ,
} ,
{ } ,
} ;
2006-06-25 11:04:43 +04:00
MODULE_DEVICE_TABLE ( of , bpp_match ) ;
2006-06-24 09:22:13 +04:00
2011-02-23 06:01:33 +03:00
static struct platform_driver bpp_sbus_driver = {
2010-04-14 03:13:02 +04:00
. driver = {
. name = " bpp " ,
. of_match_table = bpp_match ,
} ,
2006-06-24 09:22:13 +04:00
. probe = bpp_probe ,
2012-12-22 01:23:14 +04:00
. remove = bpp_remove ,
2006-06-24 09:22:13 +04:00
} ;
2011-11-27 08:43:49 +04:00
module_platform_driver ( bpp_sbus_driver ) ;
2005-04-17 02:20:36 +04:00
MODULE_AUTHOR ( " Derrick J Brashear " ) ;
MODULE_DESCRIPTION ( " Parport Driver for Sparc bidirectional Port " ) ;
2006-06-24 09:22:13 +04:00
MODULE_VERSION ( " 2.0 " ) ;
2005-04-17 02:20:36 +04:00
MODULE_LICENSE ( " GPL " ) ;