2017-06-02 10:06:27 +03:00
/*
* Register map access API - W1 ( 1 - Wire ) support
*
2017-07-06 16:10:17 +03:00
* Copyright ( c ) 2017 Radioavionica Corporation
2017-06-02 10:06:27 +03:00
* Author : Alex A . Mihaylov < minimumlaw @ rambler . ru >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation
*/
# include <linux/regmap.h>
# include <linux/module.h>
2017-07-06 16:10:17 +03:00
# include <linux/w1.h>
2017-06-02 10:06:27 +03:00
# include "internal.h"
# define W1_CMD_READ_DATA 0x69
# define W1_CMD_WRITE_DATA 0x6C
/*
* 1 - Wire slaves registers with addess 8 bit and data 8 bit
*/
static int w1_reg_a8_v8_read ( void * context , unsigned int reg , unsigned int * val )
{
struct device * dev = context ;
struct w1_slave * sl = container_of ( dev , struct w1_slave , dev ) ;
int ret = 0 ;
if ( reg > 255 )
return - EINVAL ;
mutex_lock ( & sl - > master - > bus_mutex ) ;
if ( ! w1_reset_select_slave ( sl ) ) {
w1_write_8 ( sl - > master , W1_CMD_READ_DATA ) ;
w1_write_8 ( sl - > master , reg ) ;
* val = w1_read_8 ( sl - > master ) ;
} else {
ret = - ENODEV ;
}
mutex_unlock ( & sl - > master - > bus_mutex ) ;
return ret ;
}
static int w1_reg_a8_v8_write ( void * context , unsigned int reg , unsigned int val )
{
struct device * dev = context ;
struct w1_slave * sl = container_of ( dev , struct w1_slave , dev ) ;
int ret = 0 ;
if ( reg > 255 )
return - EINVAL ;
mutex_lock ( & sl - > master - > bus_mutex ) ;
if ( ! w1_reset_select_slave ( sl ) ) {
w1_write_8 ( sl - > master , W1_CMD_WRITE_DATA ) ;
w1_write_8 ( sl - > master , reg ) ;
w1_write_8 ( sl - > master , val ) ;
} else {
ret = - ENODEV ;
}
mutex_unlock ( & sl - > master - > bus_mutex ) ;
return ret ;
}
/*
* 1 - Wire slaves registers with addess 8 bit and data 16 bit
*/
static int w1_reg_a8_v16_read ( void * context , unsigned int reg ,
unsigned int * val )
{
struct device * dev = context ;
struct w1_slave * sl = container_of ( dev , struct w1_slave , dev ) ;
int ret = 0 ;
if ( reg > 255 )
return - EINVAL ;
mutex_lock ( & sl - > master - > bus_mutex ) ;
if ( ! w1_reset_select_slave ( sl ) ) {
w1_write_8 ( sl - > master , W1_CMD_READ_DATA ) ;
w1_write_8 ( sl - > master , reg ) ;
* val = w1_read_8 ( sl - > master ) ;
* val | = w1_read_8 ( sl - > master ) < < 8 ;
} else {
ret = - ENODEV ;
}
mutex_unlock ( & sl - > master - > bus_mutex ) ;
return ret ;
}
static int w1_reg_a8_v16_write ( void * context , unsigned int reg ,
unsigned int val )
{
struct device * dev = context ;
struct w1_slave * sl = container_of ( dev , struct w1_slave , dev ) ;
int ret = 0 ;
if ( reg > 255 )
return - EINVAL ;
mutex_lock ( & sl - > master - > bus_mutex ) ;
if ( ! w1_reset_select_slave ( sl ) ) {
w1_write_8 ( sl - > master , W1_CMD_WRITE_DATA ) ;
w1_write_8 ( sl - > master , reg ) ;
w1_write_8 ( sl - > master , val & 0x00FF ) ;
w1_write_8 ( sl - > master , val > > 8 & 0x00FF ) ;
} else {
ret = - ENODEV ;
}
mutex_unlock ( & sl - > master - > bus_mutex ) ;
return ret ;
}
/*
* 1 - Wire slaves registers with addess 16 bit and data 16 bit
*/
static int w1_reg_a16_v16_read ( void * context , unsigned int reg ,
unsigned int * val )
{
struct device * dev = context ;
struct w1_slave * sl = container_of ( dev , struct w1_slave , dev ) ;
int ret = 0 ;
if ( reg > 65535 )
return - EINVAL ;
mutex_lock ( & sl - > master - > bus_mutex ) ;
if ( ! w1_reset_select_slave ( sl ) ) {
w1_write_8 ( sl - > master , W1_CMD_READ_DATA ) ;
w1_write_8 ( sl - > master , reg & 0x00FF ) ;
w1_write_8 ( sl - > master , reg > > 8 & 0x00FF ) ;
* val = w1_read_8 ( sl - > master ) ;
* val | = w1_read_8 ( sl - > master ) < < 8 ;
} else {
ret = - ENODEV ;
}
mutex_unlock ( & sl - > master - > bus_mutex ) ;
return ret ;
}
static int w1_reg_a16_v16_write ( void * context , unsigned int reg ,
unsigned int val )
{
struct device * dev = context ;
struct w1_slave * sl = container_of ( dev , struct w1_slave , dev ) ;
int ret = 0 ;
if ( reg > 65535 )
return - EINVAL ;
mutex_lock ( & sl - > master - > bus_mutex ) ;
if ( ! w1_reset_select_slave ( sl ) ) {
w1_write_8 ( sl - > master , W1_CMD_WRITE_DATA ) ;
w1_write_8 ( sl - > master , reg & 0x00FF ) ;
w1_write_8 ( sl - > master , reg > > 8 & 0x00FF ) ;
w1_write_8 ( sl - > master , val & 0x00FF ) ;
w1_write_8 ( sl - > master , val > > 8 & 0x00FF ) ;
} else {
ret = - ENODEV ;
}
mutex_unlock ( & sl - > master - > bus_mutex ) ;
return ret ;
}
/*
* Various types of supported bus addressing
*/
static struct regmap_bus regmap_w1_bus_a8_v8 = {
. reg_read = w1_reg_a8_v8_read ,
. reg_write = w1_reg_a8_v8_write ,
} ;
static struct regmap_bus regmap_w1_bus_a8_v16 = {
. reg_read = w1_reg_a8_v16_read ,
. reg_write = w1_reg_a8_v16_write ,
} ;
static struct regmap_bus regmap_w1_bus_a16_v16 = {
. reg_read = w1_reg_a16_v16_read ,
. reg_write = w1_reg_a16_v16_write ,
} ;
static const struct regmap_bus * regmap_get_w1_bus ( struct device * w1_dev ,
const struct regmap_config * config )
{
if ( config - > reg_bits = = 8 & & config - > val_bits = = 8 )
return & regmap_w1_bus_a8_v8 ;
if ( config - > reg_bits = = 8 & & config - > val_bits = = 16 )
return & regmap_w1_bus_a8_v16 ;
if ( config - > reg_bits = = 16 & & config - > val_bits = = 16 )
return & regmap_w1_bus_a16_v16 ;
return ERR_PTR ( - ENOTSUPP ) ;
}
struct regmap * __regmap_init_w1 ( struct device * w1_dev ,
const struct regmap_config * config ,
struct lock_class_key * lock_key ,
const char * lock_name )
{
const struct regmap_bus * bus = regmap_get_w1_bus ( w1_dev , config ) ;
if ( IS_ERR ( bus ) )
return ERR_CAST ( bus ) ;
return __regmap_init ( w1_dev , bus , w1_dev , config ,
lock_key , lock_name ) ;
return NULL ;
}
EXPORT_SYMBOL_GPL ( __regmap_init_w1 ) ;
struct regmap * __devm_regmap_init_w1 ( struct device * w1_dev ,
const struct regmap_config * config ,
struct lock_class_key * lock_key ,
const char * lock_name )
{
const struct regmap_bus * bus = regmap_get_w1_bus ( w1_dev , config ) ;
if ( IS_ERR ( bus ) )
return ERR_CAST ( bus ) ;
return __devm_regmap_init ( w1_dev , bus , w1_dev , config ,
lock_key , lock_name ) ;
return NULL ;
}
EXPORT_SYMBOL_GPL ( __devm_regmap_init_w1 ) ;
MODULE_LICENSE ( " GPL " ) ;