2019-06-04 10:11:33 +02:00
// SPDX-License-Identifier: GPL-2.0-only
2005-04-16 15:20:36 -07:00
/*
* Support code for the SCOOP interface found on various Sharp PDAs
*
* Copyright ( c ) 2004 Richard Purdie
*
* Based on code written by Sharp / Lineo for 2.4 kernels
*/
# include <linux/device.h>
2019-08-20 12:34:29 +02:00
# include <linux/gpio/driver.h>
2005-10-30 15:03:48 -08:00
# include <linux/string.h>
2006-01-08 01:02:05 -08:00
# include <linux/slab.h>
2005-10-29 19:07:23 +01:00
# include <linux/platform_device.h>
2011-07-31 16:17:29 -04:00
# include <linux/export.h>
2008-09-06 12:10:45 +01:00
# include <linux/io.h>
2005-04-16 15:20:36 -07:00
# include <asm/hardware/scoop.h>
2006-04-18 23:18:53 +01:00
/* PCMCIA to Scoop linkage
There is no easy way to link multiple scoop devices into one
single entity for the pxa2xx_pcmcia device so this structure
is used which is setup by the platform code .
This file is never modular so this symbol is always
accessile to the board support files .
*/
struct scoop_pcmcia_config * platform_scoop_config ;
EXPORT_SYMBOL ( platform_scoop_config ) ;
2005-04-16 15:20:36 -07:00
struct scoop_dev {
2008-04-09 22:43:37 +01:00
void __iomem * base ;
2008-04-10 13:36:53 +01:00
struct gpio_chip gpio ;
2005-04-16 15:20:36 -07:00
spinlock_t scoop_lock ;
2005-10-10 10:20:06 +01:00
unsigned short suspend_clr ;
unsigned short suspend_set ;
2005-04-16 15:20:36 -07:00
u32 scoop_gpwr ;
} ;
void reset_scoop ( struct device * dev )
{
struct scoop_dev * sdev = dev_get_drvdata ( dev ) ;
2010-08-06 09:36:42 -07:00
iowrite16 ( 0x0100 , sdev - > base + SCOOP_MCR ) ; /* 00 */
iowrite16 ( 0x0000 , sdev - > base + SCOOP_CDR ) ; /* 04 */
iowrite16 ( 0x0000 , sdev - > base + SCOOP_CCR ) ; /* 10 */
iowrite16 ( 0x0000 , sdev - > base + SCOOP_IMR ) ; /* 18 */
iowrite16 ( 0x00FF , sdev - > base + SCOOP_IRM ) ; /* 14 */
iowrite16 ( 0x0000 , sdev - > base + SCOOP_ISR ) ; /* 1C */
2008-04-09 23:05:09 +01:00
iowrite16 ( 0x0000 , sdev - > base + SCOOP_IRM ) ;
2005-04-16 15:20:36 -07:00
}
2008-04-10 13:36:53 +01:00
static void __scoop_gpio_set ( struct scoop_dev * sdev ,
unsigned offset , int value )
{
unsigned short gpwr ;
gpwr = ioread16 ( sdev - > base + SCOOP_GPWR ) ;
if ( value )
gpwr | = 1 < < ( offset + 1 ) ;
else
gpwr & = ~ ( 1 < < ( offset + 1 ) ) ;
iowrite16 ( gpwr , sdev - > base + SCOOP_GPWR ) ;
}
static void scoop_gpio_set ( struct gpio_chip * chip , unsigned offset , int value )
{
2015-12-08 10:51:43 +01:00
struct scoop_dev * sdev = gpiochip_get_data ( chip ) ;
2008-04-10 13:36:53 +01:00
unsigned long flags ;
spin_lock_irqsave ( & sdev - > scoop_lock , flags ) ;
__scoop_gpio_set ( sdev , offset , value ) ;
spin_unlock_irqrestore ( & sdev - > scoop_lock , flags ) ;
}
static int scoop_gpio_get ( struct gpio_chip * chip , unsigned offset )
{
2015-12-08 10:51:43 +01:00
struct scoop_dev * sdev = gpiochip_get_data ( chip ) ;
2008-04-10 13:36:53 +01:00
tree-wide: fix assorted typos all over the place
That is "success", "unknown", "through", "performance", "[re|un]mapping"
, "access", "default", "reasonable", "[con]currently", "temperature"
, "channel", "[un]used", "application", "example","hierarchy", "therefore"
, "[over|under]flow", "contiguous", "threshold", "enough" and others.
Signed-off-by: André Goddard Rosa <andre.goddard@gmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
2009-11-14 13:09:05 -02:00
/* XXX: I'm unsure, but it seems so */
2015-12-22 15:35:47 +01:00
return ! ! ( ioread16 ( sdev - > base + SCOOP_GPRR ) & ( 1 < < ( offset + 1 ) ) ) ;
2008-04-10 13:36:53 +01:00
}
static int scoop_gpio_direction_input ( struct gpio_chip * chip ,
unsigned offset )
{
2015-12-08 10:51:43 +01:00
struct scoop_dev * sdev = gpiochip_get_data ( chip ) ;
2008-04-10 13:36:53 +01:00
unsigned long flags ;
unsigned short gpcr ;
spin_lock_irqsave ( & sdev - > scoop_lock , flags ) ;
gpcr = ioread16 ( sdev - > base + SCOOP_GPCR ) ;
gpcr & = ~ ( 1 < < ( offset + 1 ) ) ;
iowrite16 ( gpcr , sdev - > base + SCOOP_GPCR ) ;
spin_unlock_irqrestore ( & sdev - > scoop_lock , flags ) ;
return 0 ;
}
static int scoop_gpio_direction_output ( struct gpio_chip * chip ,
unsigned offset , int value )
{
2015-12-08 10:51:43 +01:00
struct scoop_dev * sdev = gpiochip_get_data ( chip ) ;
2008-04-10 13:36:53 +01:00
unsigned long flags ;
unsigned short gpcr ;
spin_lock_irqsave ( & sdev - > scoop_lock , flags ) ;
__scoop_gpio_set ( sdev , offset , value ) ;
gpcr = ioread16 ( sdev - > base + SCOOP_GPCR ) ;
gpcr | = 1 < < ( offset + 1 ) ;
iowrite16 ( gpcr , sdev - > base + SCOOP_GPCR ) ;
spin_unlock_irqrestore ( & sdev - > scoop_lock , flags ) ;
return 0 ;
}
2005-04-16 15:20:36 -07:00
unsigned short read_scoop_reg ( struct device * dev , unsigned short reg )
{
struct scoop_dev * sdev = dev_get_drvdata ( dev ) ;
2008-04-09 23:05:09 +01:00
return ioread16 ( sdev - > base + reg ) ;
2005-04-16 15:20:36 -07:00
}
void write_scoop_reg ( struct device * dev , unsigned short reg , unsigned short data )
{
struct scoop_dev * sdev = dev_get_drvdata ( dev ) ;
2008-04-09 23:05:09 +01:00
iowrite16 ( data , sdev - > base + reg ) ;
2005-04-16 15:20:36 -07:00
}
EXPORT_SYMBOL ( reset_scoop ) ;
EXPORT_SYMBOL ( read_scoop_reg ) ;
EXPORT_SYMBOL ( write_scoop_reg ) ;
2010-02-16 22:41:52 +01:00
# ifdef CONFIG_PM
2005-10-10 10:20:06 +01:00
static void check_scoop_reg ( struct scoop_dev * sdev )
{
unsigned short mcr ;
2008-04-09 23:05:09 +01:00
mcr = ioread16 ( sdev - > base + SCOOP_MCR ) ;
2005-10-10 10:20:06 +01:00
if ( ( mcr & 0x100 ) = = 0 )
2008-04-09 23:05:09 +01:00
iowrite16 ( 0x0101 , sdev - > base + SCOOP_MCR ) ;
2005-10-10 10:20:06 +01:00
}
2005-11-09 22:32:44 +00:00
static int scoop_suspend ( struct platform_device * dev , pm_message_t state )
2005-04-16 15:20:36 -07:00
{
2005-11-09 22:32:44 +00:00
struct scoop_dev * sdev = platform_get_drvdata ( dev ) ;
2005-10-28 09:52:56 -07:00
check_scoop_reg ( sdev ) ;
2008-04-09 23:05:09 +01:00
sdev - > scoop_gpwr = ioread16 ( sdev - > base + SCOOP_GPWR ) ;
iowrite16 ( ( sdev - > scoop_gpwr & ~ sdev - > suspend_clr ) | sdev - > suspend_set , sdev - > base + SCOOP_GPWR ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2005-11-09 22:32:44 +00:00
static int scoop_resume ( struct platform_device * dev )
2005-04-16 15:20:36 -07:00
{
2005-11-09 22:32:44 +00:00
struct scoop_dev * sdev = platform_get_drvdata ( dev ) ;
2005-10-28 09:52:56 -07:00
check_scoop_reg ( sdev ) ;
2008-04-09 23:05:09 +01:00
iowrite16 ( sdev - > scoop_gpwr , sdev - > base + SCOOP_GPWR ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
# else
# define scoop_suspend NULL
# define scoop_resume NULL
# endif
2012-12-21 14:02:24 -08:00
static int scoop_probe ( struct platform_device * pdev )
2005-04-16 15:20:36 -07:00
{
struct scoop_dev * devptr ;
struct scoop_config * inf ;
struct resource * mem = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
2008-04-10 13:36:53 +01:00
int ret ;
2005-04-16 15:20:36 -07:00
if ( ! mem )
return - EINVAL ;
2006-03-20 19:46:41 +00:00
devptr = kzalloc ( sizeof ( struct scoop_dev ) , GFP_KERNEL ) ;
2005-04-16 15:20:36 -07:00
if ( ! devptr )
2006-03-20 19:46:41 +00:00
return - ENOMEM ;
2005-04-16 15:20:36 -07:00
spin_lock_init ( & devptr - > scoop_lock ) ;
2005-11-09 22:32:44 +00:00
inf = pdev - > dev . platform_data ;
2011-06-09 09:13:32 -07:00
devptr - > base = ioremap ( mem - > start , resource_size ( mem ) ) ;
2005-04-16 15:20:36 -07:00
if ( ! devptr - > base ) {
2008-04-10 13:36:53 +01:00
ret = - ENOMEM ;
goto err_ioremap ;
2005-04-16 15:20:36 -07:00
}
2005-11-09 22:32:44 +00:00
platform_set_drvdata ( pdev , devptr ) ;
2005-04-16 15:20:36 -07:00
2008-04-09 22:43:37 +01:00
printk ( " Sharp Scoop Device found at 0x%08x -> 0x%8p \n " , ( unsigned int ) mem - > start , devptr - > base ) ;
2005-04-16 15:20:36 -07:00
2008-04-09 23:05:09 +01:00
iowrite16 ( 0x0140 , devptr - > base + SCOOP_MCR ) ;
2005-11-12 20:25:25 +00:00
reset_scoop ( & pdev - > dev ) ;
2008-04-09 23:05:09 +01:00
iowrite16 ( 0x0000 , devptr - > base + SCOOP_CPR ) ;
iowrite16 ( inf - > io_dir & 0xffff , devptr - > base + SCOOP_GPCR ) ;
iowrite16 ( inf - > io_out & 0xffff , devptr - > base + SCOOP_GPWR ) ;
2005-04-16 15:20:36 -07:00
2005-10-10 10:20:06 +01:00
devptr - > suspend_clr = inf - > suspend_clr ;
devptr - > suspend_set = inf - > suspend_set ;
2008-04-10 13:36:53 +01:00
devptr - > gpio . base = - 1 ;
if ( inf - > gpio_base ! = 0 ) {
2008-05-30 17:42:11 +02:00
devptr - > gpio . label = dev_name ( & pdev - > dev ) ;
2008-04-10 13:36:53 +01:00
devptr - > gpio . base = inf - > gpio_base ;
devptr - > gpio . ngpio = 12 ; /* PA11 = 0, PA12 = 1, etc. up to PA22 = 11 */
devptr - > gpio . set = scoop_gpio_set ;
devptr - > gpio . get = scoop_gpio_get ;
devptr - > gpio . direction_input = scoop_gpio_direction_input ;
devptr - > gpio . direction_output = scoop_gpio_direction_output ;
2015-12-08 10:51:43 +01:00
ret = gpiochip_add_data ( & devptr - > gpio , devptr ) ;
2008-04-10 13:36:53 +01:00
if ( ret )
goto err_gpio ;
}
2005-04-16 15:20:36 -07:00
return 0 ;
2008-04-10 13:36:53 +01:00
err_gpio :
platform_set_drvdata ( pdev , NULL ) ;
err_ioremap :
iounmap ( devptr - > base ) ;
kfree ( devptr ) ;
return ret ;
2005-04-16 15:20:36 -07:00
}
2012-12-21 14:02:24 -08:00
static int scoop_remove ( struct platform_device * pdev )
2005-04-16 15:20:36 -07:00
{
2005-11-09 22:32:44 +00:00
struct scoop_dev * sdev = platform_get_drvdata ( pdev ) ;
2008-04-10 13:36:53 +01:00
if ( ! sdev )
return - EINVAL ;
2014-07-12 22:30:14 +02:00
if ( sdev - > gpio . base ! = - 1 )
gpiochip_remove ( & sdev - > gpio ) ;
2008-04-10 13:36:53 +01:00
platform_set_drvdata ( pdev , NULL ) ;
iounmap ( sdev - > base ) ;
kfree ( sdev ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2005-11-09 22:32:44 +00:00
static struct platform_driver scoop_driver = {
2005-04-16 15:20:36 -07:00
. probe = scoop_probe ,
2012-12-21 14:02:24 -08:00
. remove = scoop_remove ,
2005-04-16 15:20:36 -07:00
. suspend = scoop_suspend ,
. resume = scoop_resume ,
2005-11-09 22:32:44 +00:00
. driver = {
. name = " sharp-scoop " ,
} ,
2005-04-16 15:20:36 -07:00
} ;
2008-04-09 22:43:37 +01:00
static int __init scoop_init ( void )
2005-04-16 15:20:36 -07:00
{
2005-11-09 22:32:44 +00:00
return platform_driver_register ( & scoop_driver ) ;
2005-04-16 15:20:36 -07:00
}
subsys_initcall ( scoop_init ) ;