2019-06-04 11:11:33 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2011-03-30 11:27:56 +04:00
/*
*
2016-12-20 21:57:55 +03:00
* Copyright ( C ) 2012 John Crispin < john @ phrozen . org >
2011-03-30 11:27:56 +04:00
*/
# include <linux/init.h>
2012-05-17 00:17:38 +04:00
# include <linux/module.h>
2011-03-30 11:27:56 +04:00
# include <linux/types.h>
# include <linux/platform_device.h>
# include <linux/mutex.h>
2018-04-13 16:21:15 +03:00
# include <linux/gpio/driver.h>
2012-05-17 00:17:38 +04:00
# include <linux/of.h>
# include <linux/of_gpio.h>
2011-03-30 11:27:56 +04:00
# include <linux/io.h>
2012-05-17 00:17:38 +04:00
# include <linux/slab.h>
2011-03-30 11:27:56 +04:00
# include <lantiq_soc.h>
/*
* By attaching hardware latches to the EBU it is possible to create output
* only gpios . This driver configures a special memory address , which when
* written to outputs 16 bit to the latches .
*/
# define LTQ_EBU_BUSCON 0x1e7ff /* 16 bit access, slowest timing */
# define LTQ_EBU_WP 0x80000000 /* write protect bit */
2012-05-17 00:17:38 +04:00
struct ltq_mm {
struct of_mm_gpio_chip mmchip ;
u16 shadow ; /* shadow the latches state */
} ;
2011-03-30 11:27:56 +04:00
2012-05-17 00:17:38 +04:00
/**
* ltq_mm_apply ( ) - write the shadow value to the ebu address .
* @ chip : Pointer to our private data structure .
*
* Write the shadow value to the EBU to set the gpios . We need to set the
2020-04-24 18:41:03 +03:00
* global EBU lock to make sure that PCI / MTD don ' t break .
2012-05-17 00:17:38 +04:00
*/
static void ltq_mm_apply ( struct ltq_mm * chip )
2011-03-30 11:27:56 +04:00
{
unsigned long flags ;
spin_lock_irqsave ( & ebu_lock , flags ) ;
ltq_ebu_w32 ( LTQ_EBU_BUSCON , LTQ_EBU_BUSCON1 ) ;
2012-05-17 00:17:38 +04:00
__raw_writew ( chip - > shadow , chip - > mmchip . regs ) ;
2011-03-30 11:27:56 +04:00
ltq_ebu_w32 ( LTQ_EBU_BUSCON | LTQ_EBU_WP , LTQ_EBU_BUSCON1 ) ;
spin_unlock_irqrestore ( & ebu_lock , flags ) ;
}
2012-05-17 00:17:38 +04:00
/**
* ltq_mm_set ( ) - gpio_chip - > set - set gpios .
* @ gc : Pointer to gpio_chip device structure .
* @ gpio : GPIO signal number .
* @ val : Value to be written to specified signal .
*
* Set the shadow value and call ltq_mm_apply .
*/
static void ltq_mm_set ( struct gpio_chip * gc , unsigned offset , int value )
2011-03-30 11:27:56 +04:00
{
2015-12-07 12:19:29 +03:00
struct ltq_mm * chip = gpiochip_get_data ( gc ) ;
2012-05-17 00:17:38 +04:00
2011-03-30 11:27:56 +04:00
if ( value )
2012-05-17 00:17:38 +04:00
chip - > shadow | = ( 1 < < offset ) ;
2011-03-30 11:27:56 +04:00
else
2012-05-17 00:17:38 +04:00
chip - > shadow & = ~ ( 1 < < offset ) ;
ltq_mm_apply ( chip ) ;
2011-03-30 11:27:56 +04:00
}
2012-05-17 00:17:38 +04:00
/**
* ltq_mm_dir_out ( ) - gpio_chip - > dir_out - set gpio direction .
* @ gc : Pointer to gpio_chip device structure .
* @ gpio : GPIO signal number .
* @ val : Value to be written to specified signal .
*
* Same as ltq_mm_set , always returns 0.
*/
static int ltq_mm_dir_out ( struct gpio_chip * gc , unsigned offset , int value )
2011-03-30 11:27:56 +04:00
{
2012-05-17 00:17:38 +04:00
ltq_mm_set ( gc , offset , value ) ;
2011-03-30 11:27:56 +04:00
return 0 ;
}
2012-05-17 00:17:38 +04:00
/**
* ltq_mm_save_regs ( ) - Set initial values of GPIO pins
* @ mm_gc : pointer to memory mapped GPIO chip structure
*/
static void ltq_mm_save_regs ( struct of_mm_gpio_chip * mm_gc )
{
2016-01-07 19:24:58 +03:00
struct ltq_mm * chip =
container_of ( mm_gc , struct ltq_mm , mmchip ) ;
2012-05-17 00:17:38 +04:00
/* tell the ebu controller which memory address we will be using */
ltq_ebu_w32 ( CPHYSADDR ( chip - > mmchip . regs ) | 0x1 , LTQ_EBU_ADDRSEL1 ) ;
ltq_mm_apply ( chip ) ;
}
2011-03-30 11:27:56 +04:00
2012-05-17 00:17:38 +04:00
static int ltq_mm_probe ( struct platform_device * pdev )
2011-03-30 11:27:56 +04:00
{
2012-05-17 00:17:38 +04:00
struct ltq_mm * chip ;
2015-01-19 14:27:24 +03:00
u32 shadow ;
2011-03-30 11:27:56 +04:00
2015-01-18 14:39:27 +03:00
chip = devm_kzalloc ( & pdev - > dev , sizeof ( * chip ) , GFP_KERNEL ) ;
2012-05-17 00:17:38 +04:00
if ( ! chip )
2011-03-30 11:27:56 +04:00
return - ENOMEM ;
2015-01-18 14:39:30 +03:00
platform_set_drvdata ( pdev , chip ) ;
2012-05-17 00:17:38 +04:00
chip - > mmchip . gc . ngpio = 16 ;
chip - > mmchip . gc . direction_output = ltq_mm_dir_out ;
chip - > mmchip . gc . set = ltq_mm_set ;
chip - > mmchip . save_regs = ltq_mm_save_regs ;
2011-03-30 11:27:56 +04:00
2012-05-17 00:17:38 +04:00
/* store the shadow value if one was passed by the devicetree */
2015-01-19 14:27:24 +03:00
if ( ! of_property_read_u32 ( pdev - > dev . of_node , " lantiq,shadow " , & shadow ) )
chip - > shadow = shadow ;
2011-03-30 11:27:56 +04:00
2015-12-07 12:19:29 +03:00
return of_mm_gpiochip_add_data ( pdev - > dev . of_node , & chip - > mmchip , chip ) ;
2011-03-30 11:27:56 +04:00
}
2015-01-18 14:39:30 +03:00
static int ltq_mm_remove ( struct platform_device * pdev )
{
struct ltq_mm * chip = platform_get_drvdata ( pdev ) ;
of_mm_gpiochip_remove ( & chip - > mmchip ) ;
return 0 ;
}
2012-05-17 00:17:38 +04:00
static const struct of_device_id ltq_mm_match [ ] = {
{ . compatible = " lantiq,gpio-mm " } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , ltq_mm_match ) ;
static struct platform_driver ltq_mm_driver = {
. probe = ltq_mm_probe ,
2015-01-18 14:39:30 +03:00
. remove = ltq_mm_remove ,
2011-03-30 11:27:56 +04:00
. driver = {
2012-05-17 00:17:38 +04:00
. name = " gpio-mm-ltq " ,
. of_match_table = ltq_mm_match ,
2011-03-30 11:27:56 +04:00
} ,
} ;
2012-05-17 00:17:38 +04:00
static int __init ltq_mm_init ( void )
2011-03-30 11:27:56 +04:00
{
2012-05-17 00:17:38 +04:00
return platform_driver_register ( & ltq_mm_driver ) ;
2011-03-30 11:27:56 +04:00
}
2012-05-17 00:17:38 +04:00
subsys_initcall ( ltq_mm_init ) ;
2015-01-18 14:39:30 +03:00
static void __exit ltq_mm_exit ( void )
{
platform_driver_unregister ( & ltq_mm_driver ) ;
}
module_exit ( ltq_mm_exit ) ;