2010-06-17 21:27:26 +04:00
/*
2013-03-25 12:35:17 +04:00
* Copyright ( C ) 2010 - 2013 Bluecherry , LLC < http : //www.bluecherrydvr.com>
*
* Original author :
* Ben Collins < bcollins @ ubuntu . com >
*
* Additional work by :
* John Brooks < john . brooks @ bluecherry . net >
2010-06-17 21:27:26 +04: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 .
*/
# include <linux/kernel.h>
# include <linux/fs.h>
2013-03-25 12:35:17 +04:00
# include <linux/delay.h>
# include <linux/uaccess.h>
2011-02-11 15:36:27 +03:00
# include "solo6x10.h"
2010-06-17 21:27:26 +04:00
2011-02-11 15:38:20 +03:00
static void solo_gpio_mode ( struct solo_dev * solo_dev ,
2010-06-17 21:27:26 +04:00
unsigned int port_mask , unsigned int mode )
{
int port ;
unsigned int ret ;
ret = solo_reg_read ( solo_dev , SOLO_GPIO_CONFIG_0 ) ;
/* To set gpio */
for ( port = 0 ; port < 16 ; port + + ) {
if ( ! ( ( 1 < < port ) & port_mask ) )
continue ;
ret & = ( ~ ( 3 < < ( port < < 1 ) ) ) ;
ret | = ( ( mode & 3 ) < < ( port < < 1 ) ) ;
}
solo_reg_write ( solo_dev , SOLO_GPIO_CONFIG_0 , ret ) ;
/* To set extended gpio - sensor */
ret = solo_reg_read ( solo_dev , SOLO_GPIO_CONFIG_1 ) ;
for ( port = 0 ; port < 16 ; port + + ) {
if ( ! ( ( 1 < < ( port + 16 ) ) & port_mask ) )
continue ;
if ( ! mode )
ret & = ~ ( 1 < < port ) ;
else
ret | = 1 < < port ;
}
2017-08-02 17:17:02 +03:00
/* Enable GPIO[31:16] */
ret | = 0xffff0000 ;
2010-06-17 21:27:26 +04:00
solo_reg_write ( solo_dev , SOLO_GPIO_CONFIG_1 , ret ) ;
}
2011-02-11 15:38:20 +03:00
static void solo_gpio_set ( struct solo_dev * solo_dev , unsigned int value )
2010-06-17 21:27:26 +04:00
{
solo_reg_write ( solo_dev , SOLO_GPIO_DATA_OUT ,
solo_reg_read ( solo_dev , SOLO_GPIO_DATA_OUT ) | value ) ;
}
2011-02-11 15:38:20 +03:00
static void solo_gpio_clear ( struct solo_dev * solo_dev , unsigned int value )
2010-06-17 21:27:26 +04:00
{
solo_reg_write ( solo_dev , SOLO_GPIO_DATA_OUT ,
solo_reg_read ( solo_dev , SOLO_GPIO_DATA_OUT ) & ~ value ) ;
}
2011-02-11 15:38:20 +03:00
static void solo_gpio_config ( struct solo_dev * solo_dev )
2010-06-17 21:27:26 +04:00
{
/* Video reset */
solo_gpio_mode ( solo_dev , 0x30 , 1 ) ;
solo_gpio_clear ( solo_dev , 0x30 ) ;
udelay ( 100 ) ;
solo_gpio_set ( solo_dev , 0x30 ) ;
udelay ( 100 ) ;
/* Warning: Don't touch the next line unless you're sure of what
* you ' re doing : first four gpio [ 0 - 3 ] are used for video . */
solo_gpio_mode ( solo_dev , 0x0f , 2 ) ;
/* We use bit 8-15 of SOLO_GPIO_CONFIG_0 for relay purposes */
solo_gpio_mode ( solo_dev , 0xff00 , 1 ) ;
/* Initially set relay status to 0 */
solo_gpio_clear ( solo_dev , 0xff00 ) ;
2017-08-02 17:17:02 +03:00
/* Set input pins direction */
solo_gpio_mode ( solo_dev , 0xffff0000 , 0 ) ;
}
# ifdef CONFIG_GPIOLIB
/* Pins 0-7 are not exported, because it seems from code above they are
* used for internal purposes . So offset 0 corresponds to pin 8 , therefore
* offsets 0 - 7 are relay GPIOs , 8 - 23 - input GPIOs .
*/
static int solo_gpiochip_get_direction ( struct gpio_chip * chip ,
unsigned int offset )
{
int ret , mode ;
struct solo_dev * solo_dev = gpiochip_get_data ( chip ) ;
if ( offset < 8 ) {
ret = solo_reg_read ( solo_dev , SOLO_GPIO_CONFIG_0 ) ;
mode = 3 & ( ret > > ( ( offset + 8 ) * 2 ) ) ;
} else {
ret = solo_reg_read ( solo_dev , SOLO_GPIO_CONFIG_1 ) ;
mode = 1 & ( ret > > ( offset - 8 ) ) ;
}
if ( ! mode )
return 1 ;
else if ( mode = = 1 )
return 0 ;
return - 1 ;
2010-06-17 21:27:26 +04:00
}
2017-08-02 17:17:02 +03:00
static int solo_gpiochip_direction_input ( struct gpio_chip * chip ,
unsigned int offset )
{
return - 1 ;
}
static int solo_gpiochip_direction_output ( struct gpio_chip * chip ,
unsigned int offset , int value )
{
return - 1 ;
}
static int solo_gpiochip_get ( struct gpio_chip * chip ,
unsigned int offset )
{
int ret ;
struct solo_dev * solo_dev = gpiochip_get_data ( chip ) ;
ret = solo_reg_read ( solo_dev , SOLO_GPIO_DATA_IN ) ;
return 1 & ( ret > > ( offset + 8 ) ) ;
}
static void solo_gpiochip_set ( struct gpio_chip * chip ,
unsigned int offset , int value )
{
struct solo_dev * solo_dev = gpiochip_get_data ( chip ) ;
if ( value )
solo_gpio_set ( solo_dev , 1 < < ( offset + 8 ) ) ;
else
solo_gpio_clear ( solo_dev , 1 < < ( offset + 8 ) ) ;
}
# endif
2011-02-11 15:38:20 +03:00
int solo_gpio_init ( struct solo_dev * solo_dev )
2010-06-17 21:27:26 +04:00
{
2017-09-15 22:52:04 +03:00
# ifdef CONFIG_GPIOLIB
2017-08-02 17:17:02 +03:00
int ret ;
2017-09-15 22:52:04 +03:00
# endif
2017-08-02 17:17:02 +03:00
2010-11-05 05:51:17 +03:00
solo_gpio_config ( solo_dev ) ;
2017-08-02 17:17:02 +03:00
# ifdef CONFIG_GPIOLIB
solo_dev - > gpio_dev . label = SOLO6X10_NAME " _gpio " ;
solo_dev - > gpio_dev . parent = & solo_dev - > pdev - > dev ;
solo_dev - > gpio_dev . owner = THIS_MODULE ;
solo_dev - > gpio_dev . base = - 1 ;
solo_dev - > gpio_dev . ngpio = 24 ;
solo_dev - > gpio_dev . can_sleep = 0 ;
solo_dev - > gpio_dev . get_direction = solo_gpiochip_get_direction ;
solo_dev - > gpio_dev . direction_input = solo_gpiochip_direction_input ;
solo_dev - > gpio_dev . direction_output = solo_gpiochip_direction_output ;
solo_dev - > gpio_dev . get = solo_gpiochip_get ;
solo_dev - > gpio_dev . set = solo_gpiochip_set ;
ret = gpiochip_add_data ( & solo_dev - > gpio_dev , solo_dev ) ;
if ( ret ) {
solo_dev - > gpio_dev . label = NULL ;
return - 1 ;
}
# endif
2010-11-05 05:51:17 +03:00
return 0 ;
2010-06-17 21:27:26 +04:00
}
2011-02-11 15:38:20 +03:00
void solo_gpio_exit ( struct solo_dev * solo_dev )
2010-06-17 21:27:26 +04:00
{
2017-08-02 17:17:02 +03:00
# ifdef CONFIG_GPIOLIB
if ( solo_dev - > gpio_dev . label ) {
gpiochip_remove ( & solo_dev - > gpio_dev ) ;
solo_dev - > gpio_dev . label = NULL ;
}
# endif
2010-06-17 21:27:26 +04:00
solo_gpio_clear ( solo_dev , 0x30 ) ;
solo_gpio_config ( solo_dev ) ;
}