2011-04-18 11:40:58 +04:00
/*
2011-12-09 20:12:42 +04:00
* AD5760 , AD5780 , AD5781 , AD5790 , AD5791 Voltage Output Digital to Analog
* Converter
2011-04-18 11:40:58 +04:00
*
* Copyright 2011 Analog Devices Inc .
*
* Licensed under the GPL - 2.
*/
# include <linux/interrupt.h>
# include <linux/fs.h>
# include <linux/device.h>
# include <linux/kernel.h>
# include <linux/spi/spi.h>
# include <linux/slab.h>
# include <linux/sysfs.h>
# include <linux/regulator/consumer.h>
2011-07-03 23:49:50 +04:00
# include <linux/module.h>
2014-12-06 09:00:00 +03:00
# include <linux/bitops.h>
2011-04-18 11:40:58 +04:00
2012-04-25 18:54:58 +04:00
# include <linux/iio/iio.h>
# include <linux/iio/sysfs.h>
2012-06-04 13:36:28 +04:00
# include <linux/iio/dac/ad5791.h>
2011-04-18 11:40:58 +04:00
2014-12-06 09:00:00 +03:00
# define AD5791_DAC_MASK GENMASK(19, 0)
2012-06-04 13:36:27 +04:00
2014-12-06 09:00:00 +03:00
# define AD5791_CMD_READ BIT(23)
# define AD5791_CMD_WRITE 0
2012-06-04 13:36:27 +04:00
# define AD5791_ADDR(addr) ((addr) << 20)
/* Registers */
# define AD5791_ADDR_NOOP 0
# define AD5791_ADDR_DAC0 1
# define AD5791_ADDR_CTRL 2
# define AD5791_ADDR_CLRCODE 3
# define AD5791_ADDR_SW_CTRL 4
/* Control Register */
2014-12-06 09:00:00 +03:00
# define AD5791_CTRL_RBUF BIT(1)
# define AD5791_CTRL_OPGND BIT(2)
# define AD5791_CTRL_DACTRI BIT(3)
# define AD5791_CTRL_BIN2SC BIT(4)
# define AD5791_CTRL_SDODIS BIT(5)
2012-06-04 13:36:27 +04:00
# define AD5761_CTRL_LINCOMP(x) ((x) << 6)
# define AD5791_LINCOMP_0_10 0
# define AD5791_LINCOMP_10_12 1
# define AD5791_LINCOMP_12_16 2
# define AD5791_LINCOMP_16_19 3
# define AD5791_LINCOMP_19_20 12
# define AD5780_LINCOMP_0_10 0
# define AD5780_LINCOMP_10_20 12
/* Software Control Register */
2014-12-06 09:00:00 +03:00
# define AD5791_SWCTRL_LDAC BIT(0)
# define AD5791_SWCTRL_CLR BIT(1)
# define AD5791_SWCTRL_RESET BIT(2)
2012-06-04 13:36:27 +04:00
# define AD5791_DAC_PWRDN_6K 0
# define AD5791_DAC_PWRDN_3STATE 1
/**
* struct ad5791_chip_info - chip specific information
* @ get_lin_comp : function pointer to the device specific function
*/
struct ad5791_chip_info {
int ( * get_lin_comp ) ( unsigned int span ) ;
} ;
/**
* struct ad5791_state - driver instance specific data
2014-12-06 09:00:00 +03:00
* @ spi : spi_device
2012-06-04 13:36:27 +04:00
* @ reg_vdd : positive supply regulator
* @ reg_vss : negative supply regulator
* @ chip_info : chip model specific constants
* @ vref_mv : actual reference voltage used
* @ vref_neg_mv : voltage of the negative supply
* @ pwr_down_mode current power down mode
*/
struct ad5791_state {
struct spi_device * spi ;
struct regulator * reg_vdd ;
struct regulator * reg_vss ;
const struct ad5791_chip_info * chip_info ;
unsigned short vref_mv ;
unsigned int vref_neg_mv ;
unsigned ctrl ;
unsigned pwr_down_mode ;
bool pwr_down ;
2013-11-25 16:41:00 +04:00
union {
__be32 d32 ;
u8 d8 [ 4 ] ;
} data [ 3 ] ____cacheline_aligned ;
2012-06-04 13:36:27 +04:00
} ;
/**
* ad5791_supported_device_ids :
*/
enum ad5791_supported_device_ids {
ID_AD5760 ,
ID_AD5780 ,
ID_AD5781 ,
ID_AD5791 ,
} ;
2013-11-25 16:41:00 +04:00
static int ad5791_spi_write ( struct ad5791_state * st , u8 addr , u32 val )
2011-04-18 11:40:58 +04:00
{
2013-11-25 16:41:00 +04:00
st - > data [ 0 ] . d32 = cpu_to_be32 ( AD5791_CMD_WRITE |
2011-04-18 11:40:58 +04:00
AD5791_ADDR ( addr ) |
( val & AD5791_DAC_MASK ) ) ;
2013-11-25 16:41:00 +04:00
return spi_write ( st - > spi , & st - > data [ 0 ] . d8 [ 1 ] , 3 ) ;
2011-04-18 11:40:58 +04:00
}
2013-11-25 16:41:00 +04:00
static int ad5791_spi_read ( struct ad5791_state * st , u8 addr , u32 * val )
2011-04-18 11:40:58 +04:00
{
int ret ;
struct spi_transfer xfers [ ] = {
{
2013-11-25 16:41:00 +04:00
. tx_buf = & st - > data [ 0 ] . d8 [ 1 ] ,
2011-04-18 11:40:58 +04:00
. bits_per_word = 8 ,
. len = 3 ,
. cs_change = 1 ,
} , {
2013-11-25 16:41:00 +04:00
. tx_buf = & st - > data [ 1 ] . d8 [ 1 ] ,
. rx_buf = & st - > data [ 2 ] . d8 [ 1 ] ,
2011-04-18 11:40:58 +04:00
. bits_per_word = 8 ,
. len = 3 ,
} ,
} ;
2013-11-25 16:41:00 +04:00
st - > data [ 0 ] . d32 = cpu_to_be32 ( AD5791_CMD_READ |
2011-04-18 11:40:58 +04:00
AD5791_ADDR ( addr ) ) ;
2013-11-25 16:41:00 +04:00
st - > data [ 1 ] . d32 = cpu_to_be32 ( AD5791_ADDR ( AD5791_ADDR_NOOP ) ) ;
2011-04-18 11:40:58 +04:00
2013-11-25 16:41:00 +04:00
ret = spi_sync_transfer ( st - > spi , xfers , ARRAY_SIZE ( xfers ) ) ;
2011-04-18 11:40:58 +04:00
2013-11-25 16:41:00 +04:00
* val = be32_to_cpu ( st - > data [ 2 ] . d32 ) ;
2011-04-18 11:40:58 +04:00
return ret ;
}
2012-06-04 13:36:18 +04:00
static const char * const ad5791_powerdown_modes [ ] = {
" 6kohm_to_gnd " ,
" three_state " ,
2011-09-02 20:25:19 +04:00
} ;
2011-04-18 11:40:58 +04:00
2012-06-04 13:36:18 +04:00
static int ad5791_get_powerdown_mode ( struct iio_dev * indio_dev ,
const struct iio_chan_spec * chan )
2011-04-18 11:40:58 +04:00
{
2011-06-27 16:07:34 +04:00
struct ad5791_state * st = iio_priv ( indio_dev ) ;
2011-04-18 11:40:58 +04:00
2012-06-04 13:36:18 +04:00
return st - > pwr_down_mode ;
2011-04-18 11:40:58 +04:00
}
2012-06-04 13:36:18 +04:00
static int ad5791_set_powerdown_mode ( struct iio_dev * indio_dev ,
const struct iio_chan_spec * chan , unsigned int mode )
2011-04-18 11:40:58 +04:00
{
2011-06-27 16:07:34 +04:00
struct ad5791_state * st = iio_priv ( indio_dev ) ;
2011-04-18 11:40:58 +04:00
2012-06-04 13:36:18 +04:00
st - > pwr_down_mode = mode ;
2011-04-18 11:40:58 +04:00
2012-06-04 13:36:18 +04:00
return 0 ;
2011-04-18 11:40:58 +04:00
}
2012-06-04 13:36:18 +04:00
static const struct iio_enum ad5791_powerdown_mode_enum = {
. items = ad5791_powerdown_modes ,
. num_items = ARRAY_SIZE ( ad5791_powerdown_modes ) ,
. get = ad5791_get_powerdown_mode ,
. set = ad5791_set_powerdown_mode ,
} ;
static ssize_t ad5791_read_dac_powerdown ( struct iio_dev * indio_dev ,
uintptr_t private , const struct iio_chan_spec * chan , char * buf )
2011-04-18 11:40:58 +04:00
{
2011-06-27 16:07:34 +04:00
struct ad5791_state * st = iio_priv ( indio_dev ) ;
2011-04-18 11:40:58 +04:00
return sprintf ( buf , " %d \n " , st - > pwr_down ) ;
}
2012-06-04 13:36:18 +04:00
static ssize_t ad5791_write_dac_powerdown ( struct iio_dev * indio_dev ,
uintptr_t private , const struct iio_chan_spec * chan , const char * buf ,
size_t len )
2011-04-18 11:40:58 +04:00
{
2012-06-04 13:36:24 +04:00
bool pwr_down ;
2011-04-18 11:40:58 +04:00
int ret ;
2011-06-27 16:07:34 +04:00
struct ad5791_state * st = iio_priv ( indio_dev ) ;
2011-04-18 11:40:58 +04:00
2012-06-04 13:36:24 +04:00
ret = strtobool ( buf , & pwr_down ) ;
2011-04-18 11:40:58 +04:00
if ( ret )
return ret ;
2012-06-04 13:36:24 +04:00
if ( ! pwr_down ) {
2011-04-18 11:40:58 +04:00
st - > ctrl & = ~ ( AD5791_CTRL_OPGND | AD5791_CTRL_DACTRI ) ;
2012-06-04 13:36:24 +04:00
} else {
2011-04-18 11:40:58 +04:00
if ( st - > pwr_down_mode = = AD5791_DAC_PWRDN_6K )
st - > ctrl | = AD5791_CTRL_OPGND ;
else if ( st - > pwr_down_mode = = AD5791_DAC_PWRDN_3STATE )
st - > ctrl | = AD5791_CTRL_DACTRI ;
2012-06-04 13:36:24 +04:00
}
st - > pwr_down = pwr_down ;
2011-04-18 11:40:58 +04:00
2013-11-25 16:41:00 +04:00
ret = ad5791_spi_write ( st , AD5791_ADDR_CTRL , st - > ctrl ) ;
2011-04-18 11:40:58 +04:00
return ret ? ret : len ;
}
static int ad5791_get_lin_comp ( unsigned int span )
{
if ( span < = 10000 )
return AD5791_LINCOMP_0_10 ;
else if ( span < = 12000 )
return AD5791_LINCOMP_10_12 ;
else if ( span < = 16000 )
return AD5791_LINCOMP_12_16 ;
else if ( span < = 19000 )
return AD5791_LINCOMP_16_19 ;
else
return AD5791_LINCOMP_19_20 ;
}
2011-04-27 19:13:58 +04:00
static int ad5780_get_lin_comp ( unsigned int span )
{
if ( span < = 10000 )
return AD5780_LINCOMP_0_10 ;
else
return AD5780_LINCOMP_10_20 ;
}
static const struct ad5791_chip_info ad5791_chip_info_tbl [ ] = {
[ ID_AD5760 ] = {
. get_lin_comp = ad5780_get_lin_comp ,
} ,
[ ID_AD5780 ] = {
. get_lin_comp = ad5780_get_lin_comp ,
} ,
[ ID_AD5781 ] = {
. get_lin_comp = ad5791_get_lin_comp ,
} ,
[ ID_AD5791 ] = {
. get_lin_comp = ad5791_get_lin_comp ,
} ,
} ;
2011-09-02 20:25:19 +04:00
static int ad5791_read_raw ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan ,
int * val ,
int * val2 ,
long m )
{
struct ad5791_state * st = iio_priv ( indio_dev ) ;
2011-10-19 19:47:50 +04:00
u64 val64 ;
2011-09-02 20:25:19 +04:00
int ret ;
switch ( m ) {
2012-04-15 20:41:19 +04:00
case IIO_CHAN_INFO_RAW :
2013-11-25 16:41:00 +04:00
ret = ad5791_spi_read ( st , chan - > address , val ) ;
2011-09-02 20:25:19 +04:00
if ( ret )
return ret ;
* val & = AD5791_DAC_MASK ;
* val > > = chan - > scan_type . shift ;
return IIO_VAL_INT ;
2011-10-26 20:41:36 +04:00
case IIO_CHAN_INFO_SCALE :
2013-09-28 13:31:00 +04:00
* val = st - > vref_mv ;
* val2 = ( 1 < < chan - > scan_type . realbits ) - 1 ;
return IIO_VAL_FRACTIONAL ;
2011-10-26 20:41:36 +04:00
case IIO_CHAN_INFO_OFFSET :
2011-10-19 19:47:50 +04:00
val64 = ( ( ( u64 ) st - > vref_neg_mv ) < < chan - > scan_type . realbits ) ;
do_div ( val64 , st - > vref_mv ) ;
* val = - val64 ;
return IIO_VAL_INT ;
2011-09-02 20:25:19 +04:00
default :
return - EINVAL ;
}
} ;
2012-06-04 13:36:18 +04:00
static const struct iio_chan_spec_ext_info ad5791_ext_info [ ] = {
{
. name = " powerdown " ,
2013-09-08 17:57:00 +04:00
. shared = IIO_SHARED_BY_TYPE ,
2012-06-04 13:36:18 +04:00
. read = ad5791_read_dac_powerdown ,
. write = ad5791_write_dac_powerdown ,
} ,
2013-09-08 17:57:00 +04:00
IIO_ENUM ( " powerdown_mode " , IIO_SHARED_BY_TYPE ,
& ad5791_powerdown_mode_enum ) ,
2012-06-04 13:36:18 +04:00
IIO_ENUM_AVAILABLE ( " powerdown_mode " , & ad5791_powerdown_mode_enum ) ,
{ } ,
} ;
2013-12-11 22:45:00 +04:00
# define AD5791_CHAN(bits, _shift) { \
2012-06-04 13:36:18 +04:00
. type = IIO_VOLTAGE , \
. output = 1 , \
. indexed = 1 , \
. address = AD5791_ADDR_DAC0 , \
. channel = 0 , \
2013-02-27 23:28:12 +04:00
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) , \
. info_mask_shared_by_type = BIT ( IIO_CHAN_INFO_SCALE ) | \
BIT ( IIO_CHAN_INFO_OFFSET ) , \
2013-12-11 22:45:00 +04:00
. scan_type = { \
. sign = ' u ' , \
. realbits = ( bits ) , \
. storagebits = 24 , \
. shift = ( _shift ) , \
} , \
2012-06-04 13:36:18 +04:00
. ext_info = ad5791_ext_info , \
}
static const struct iio_chan_spec ad5791_channels [ ] = {
[ ID_AD5760 ] = AD5791_CHAN ( 16 , 4 ) ,
[ ID_AD5780 ] = AD5791_CHAN ( 18 , 2 ) ,
[ ID_AD5781 ] = AD5791_CHAN ( 18 , 2 ) ,
[ ID_AD5791 ] = AD5791_CHAN ( 20 , 0 )
} ;
2011-09-02 20:25:19 +04:00
static int ad5791_write_raw ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan ,
int val ,
int val2 ,
long mask )
{
struct ad5791_state * st = iio_priv ( indio_dev ) ;
switch ( mask ) {
2012-04-15 20:41:19 +04:00
case IIO_CHAN_INFO_RAW :
2014-12-06 09:00:00 +03:00
val & = GENMASK ( chan - > scan_type . realbits - 1 , 0 ) ;
2011-09-02 20:25:19 +04:00
val < < = chan - > scan_type . shift ;
2013-11-25 16:41:00 +04:00
return ad5791_spi_write ( st , chan - > address , val ) ;
2011-09-02 20:25:19 +04:00
default :
return - EINVAL ;
}
}
2011-05-18 17:42:37 +04:00
static const struct iio_info ad5791_info = {
2011-09-02 20:25:19 +04:00
. read_raw = & ad5791_read_raw ,
. write_raw = & ad5791_write_raw ,
2011-05-18 17:42:37 +04:00
. driver_module = THIS_MODULE ,
} ;
2012-12-22 01:21:43 +04:00
static int ad5791_probe ( struct spi_device * spi )
2011-04-18 11:40:58 +04:00
{
struct ad5791_platform_data * pdata = spi - > dev . platform_data ;
2011-06-27 16:07:34 +04:00
struct iio_dev * indio_dev ;
2011-04-18 11:40:58 +04:00
struct ad5791_state * st ;
int ret , pos_voltage_uv = 0 , neg_voltage_uv = 0 ;
2013-08-19 15:38:00 +04:00
indio_dev = devm_iio_device_alloc ( & spi - > dev , sizeof ( * st ) ) ;
if ( ! indio_dev )
return - ENOMEM ;
2011-08-30 15:41:19 +04:00
st = iio_priv ( indio_dev ) ;
2013-08-19 15:38:00 +04:00
st - > reg_vdd = devm_regulator_get ( & spi - > dev , " vdd " ) ;
2011-08-30 15:41:19 +04:00
if ( ! IS_ERR ( st - > reg_vdd ) ) {
ret = regulator_enable ( st - > reg_vdd ) ;
2011-04-18 11:40:58 +04:00
if ( ret )
2013-08-19 15:38:00 +04:00
return ret ;
2011-04-18 11:40:58 +04:00
2012-12-14 11:55:00 +04:00
ret = regulator_get_voltage ( st - > reg_vdd ) ;
if ( ret < 0 )
goto error_disable_reg_pos ;
pos_voltage_uv = ret ;
2011-04-18 11:40:58 +04:00
}
2013-08-19 15:38:00 +04:00
st - > reg_vss = devm_regulator_get ( & spi - > dev , " vss " ) ;
2011-08-30 15:41:19 +04:00
if ( ! IS_ERR ( st - > reg_vss ) ) {
ret = regulator_enable ( st - > reg_vss ) ;
2011-04-18 11:40:58 +04:00
if ( ret )
2013-08-19 15:38:00 +04:00
goto error_disable_reg_pos ;
2011-04-18 11:40:58 +04:00
2012-12-14 11:55:00 +04:00
ret = regulator_get_voltage ( st - > reg_vss ) ;
if ( ret < 0 )
goto error_disable_reg_neg ;
neg_voltage_uv = ret ;
2011-04-18 11:40:58 +04:00
}
2011-06-27 16:07:34 +04:00
st - > pwr_down = true ;
st - > spi = spi ;
2011-10-19 19:47:50 +04:00
if ( ! IS_ERR ( st - > reg_vss ) & & ! IS_ERR ( st - > reg_vdd ) ) {
st - > vref_mv = ( pos_voltage_uv + neg_voltage_uv ) / 1000 ;
st - > vref_neg_mv = neg_voltage_uv / 1000 ;
} else if ( pdata ) {
st - > vref_mv = pdata - > vref_pos_mv + pdata - > vref_neg_mv ;
st - > vref_neg_mv = pdata - > vref_neg_mv ;
} else {
2011-04-18 11:40:58 +04:00
dev_warn ( & spi - > dev , " reference voltage unspecified \n " ) ;
2011-10-19 19:47:50 +04:00
}
2011-04-18 11:40:58 +04:00
2013-11-25 16:41:00 +04:00
ret = ad5791_spi_write ( st , AD5791_ADDR_SW_CTRL , AD5791_SWCTRL_RESET ) ;
2011-04-18 11:40:58 +04:00
if ( ret )
2011-08-30 15:41:19 +04:00
goto error_disable_reg_neg ;
2011-04-18 11:40:58 +04:00
2011-09-02 20:25:19 +04:00
st - > chip_info = & ad5791_chip_info_tbl [ spi_get_device_id ( spi )
- > driver_data ] ;
2011-04-18 11:40:58 +04:00
2011-04-27 19:13:58 +04:00
st - > ctrl = AD5761_CTRL_LINCOMP ( st - > chip_info - > get_lin_comp ( st - > vref_mv ) )
| ( ( pdata & & pdata - > use_rbuf_gain2 ) ? 0 : AD5791_CTRL_RBUF ) |
2011-04-18 11:40:58 +04:00
AD5791_CTRL_BIN2SC ;
2013-11-25 16:41:00 +04:00
ret = ad5791_spi_write ( st , AD5791_ADDR_CTRL , st - > ctrl |
2011-04-18 11:40:58 +04:00
AD5791_CTRL_OPGND | AD5791_CTRL_DACTRI ) ;
if ( ret )
2011-08-30 15:41:19 +04:00
goto error_disable_reg_neg ;
2011-04-18 11:40:58 +04:00
2011-06-27 16:07:34 +04:00
spi_set_drvdata ( spi , indio_dev ) ;
indio_dev - > dev . parent = & spi - > dev ;
indio_dev - > info = & ad5791_info ;
indio_dev - > modes = INDIO_DIRECT_MODE ;
2011-09-02 20:25:19 +04:00
indio_dev - > channels
= & ad5791_channels [ spi_get_device_id ( spi ) - > driver_data ] ;
indio_dev - > num_channels = 1 ;
indio_dev - > name = spi_get_device_id ( st - > spi ) - > name ;
2011-06-27 16:07:34 +04:00
ret = iio_device_register ( indio_dev ) ;
2011-04-18 11:40:58 +04:00
if ( ret )
2011-08-30 15:41:19 +04:00
goto error_disable_reg_neg ;
2011-04-18 11:40:58 +04:00
return 0 ;
error_disable_reg_neg :
2011-08-30 15:41:19 +04:00
if ( ! IS_ERR ( st - > reg_vss ) )
regulator_disable ( st - > reg_vss ) ;
2012-12-14 11:55:00 +04:00
error_disable_reg_pos :
2011-08-30 15:41:19 +04:00
if ( ! IS_ERR ( st - > reg_vdd ) )
regulator_disable ( st - > reg_vdd ) ;
2011-04-18 11:40:58 +04:00
return ret ;
}
2012-12-22 01:21:43 +04:00
static int ad5791_remove ( struct spi_device * spi )
2011-04-18 11:40:58 +04:00
{
2011-06-27 16:07:34 +04:00
struct iio_dev * indio_dev = spi_get_drvdata ( spi ) ;
struct ad5791_state * st = iio_priv ( indio_dev ) ;
2011-04-18 11:40:58 +04:00
2011-10-14 17:46:58 +04:00
iio_device_unregister ( indio_dev ) ;
2013-08-19 15:38:00 +04:00
if ( ! IS_ERR ( st - > reg_vdd ) )
2011-08-30 15:41:19 +04:00
regulator_disable ( st - > reg_vdd ) ;
2011-04-18 11:40:58 +04:00
2013-08-19 15:38:00 +04:00
if ( ! IS_ERR ( st - > reg_vss ) )
2011-08-30 15:41:19 +04:00
regulator_disable ( st - > reg_vss ) ;
2011-09-02 20:14:40 +04:00
2011-04-18 11:40:58 +04:00
return 0 ;
}
static const struct spi_device_id ad5791_id [ ] = {
2011-04-27 19:13:58 +04:00
{ " ad5760 " , ID_AD5760 } ,
{ " ad5780 " , ID_AD5780 } ,
2011-04-18 11:40:58 +04:00
{ " ad5781 " , ID_AD5781 } ,
2011-12-09 20:12:42 +04:00
{ " ad5790 " , ID_AD5791 } ,
2011-04-27 19:13:58 +04:00
{ " ad5791 " , ID_AD5791 } ,
2011-04-18 11:40:58 +04:00
{ }
} ;
2011-11-16 11:53:31 +04:00
MODULE_DEVICE_TABLE ( spi , ad5791_id ) ;
2011-04-18 11:40:58 +04:00
static struct spi_driver ad5791_driver = {
. driver = {
. name = " ad5791 " ,
. owner = THIS_MODULE ,
} ,
. probe = ad5791_probe ,
2012-12-22 01:21:43 +04:00
. remove = ad5791_remove ,
2011-04-18 11:40:58 +04:00
. id_table = ad5791_id ,
} ;
2011-11-16 13:13:39 +04:00
module_spi_driver ( ad5791_driver ) ;
2011-04-18 11:40:58 +04:00
MODULE_AUTHOR ( " Michael Hennerich <hennerich@blackfin.uclinux.org> " ) ;
2011-12-09 20:12:42 +04:00
MODULE_DESCRIPTION ( " Analog Devices AD5760/AD5780/AD5781/AD5790/AD5791 DAC " ) ;
2011-04-18 11:40:58 +04:00
MODULE_LICENSE ( " GPL v2 " ) ;