blob: 550f6a62afbc7d76551d1fc65cb5d9ae21a24f30 [file] [log] [blame]
/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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.
*/
#ifndef _CAM_SOC_UTIL_H_
#define _CAM_SOC_UTIL_H_
#include <linux/clk.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include "cam_io_util.h"
#define NO_SET_RATE -1
#define INIT_RATE -2
/* maximum number of device block */
#define CAM_SOC_MAX_BLOCK 4
/* maximum number of device base */
#define CAM_SOC_MAX_BASE CAM_SOC_MAX_BLOCK
/* maximum number of device regulator */
#define CAM_SOC_MAX_REGULATOR 4
/* maximum number of device clock */
#define CAM_SOC_MAX_CLK 32
/**
* enum cam_vote_level - Enum for voting level
*
* @CAM_SUSPEND_VOTE : Suspend vote
* @CAM_MINSVS_VOTE : Min SVS vote
* @CAM_LOWSVS_VOTE : Low SVS vote
* @CAM_SVS_VOTE : SVS vote
* @CAM_SVSL1_VOTE : SVS Plus vote
* @CAM_NOMINAL_VOTE : Nominal vote
* @CAM_TURBO_VOTE : Turbo vote
* @CAM_MAX_VOTE : Max voting level, This is invalid level.
*/
enum cam_vote_level {
CAM_SUSPEND_VOTE,
CAM_MINSVS_VOTE,
CAM_LOWSVS_VOTE,
CAM_SVS_VOTE,
CAM_SVSL1_VOTE,
CAM_NOMINAL_VOTE,
CAM_TURBO_VOTE,
CAM_MAX_VOTE,
};
/**
* struct cam_soc_reg_map: Information about the mapped register space
*
* @mem_base: Starting location of MAPPED register space
* @mem_cam_base: Starting offset of this register space compared
* to ENTIRE Camera register space
* @size: Size of register space
**/
struct cam_soc_reg_map {
void __iomem *mem_base;
uint32_t mem_cam_base;
resource_size_t size;
};
/**
* struct cam_hw_soc_info: Soc information pertaining to specific instance of
* Camera hardware driver module
*
* @pdev: Platform device pointer
* @hw_version: Camera device version
* @index: Instance id for the camera device
* @irq_name: Name of the irq associated with the device
* @irq_line: Irq resource
* @irq_data: Private data that is passed when IRQ is requested
* @num_mem_block: Number of entry in the "reg-names"
* @mem_block_name: Array of the reg block name
* @mem_block_cam_base: Array of offset of this register space compared
* to ENTIRE Camera register space
* @mem_block: Associated resource structs
* @reg_map: Array of Mapped register info for the "reg-names"
* @num_reg_map: Number of mapped register space associated
* with mem_block. num_reg_map = num_mem_block in
* most cases
* @num_rgltr: Number of regulators
* @rgltr_name: Array of regulator names
* @rgltr: Array of associated regulator resources
* @num_clk: Number of clocks
* @clk_name: Array of clock names
* @clk: Array of associated clock resources
* @clk_rate: 2D array of clock rates representing clock rate
* values at different vote levels
* @src_clk_idx: Source clock index that is rate-controllable
* @clk_level_valid: Indicates whether corresponding level is valid
* @soc_private: Soc private data
*
*/
struct cam_hw_soc_info {
struct platform_device *pdev;
uint32_t hw_version;
uint32_t index;
const char *irq_name;
struct resource *irq_line;
void *irq_data;
uint32_t num_mem_block;
const char *mem_block_name[CAM_SOC_MAX_BLOCK];
uint32_t mem_block_cam_base[CAM_SOC_MAX_BLOCK];
struct resource *mem_block[CAM_SOC_MAX_BLOCK];
struct cam_soc_reg_map reg_map[CAM_SOC_MAX_BASE];
uint32_t num_reg_map;
uint32_t num_rgltr;
const char *rgltr_name[CAM_SOC_MAX_REGULATOR];
struct regulator *rgltr[CAM_SOC_MAX_REGULATOR];
uint32_t num_clk;
const char *clk_name[CAM_SOC_MAX_CLK];
struct clk *clk[CAM_SOC_MAX_CLK];
int32_t clk_rate[CAM_MAX_VOTE][CAM_SOC_MAX_CLK];
int32_t src_clk_idx;
bool clk_level_valid[CAM_MAX_VOTE];
void *soc_private;
};
/*
* CAM_SOC_GET_REG_MAP_START
*
* @brief: This MACRO will get the mapped starting address
* where the register space can be accessed
*
* @__soc_info: Device soc information
* @__base_index: Index of register space in the HW block
*
* @return: Returns a pointer to the mapped register memory
*/
#define CAM_SOC_GET_REG_MAP_START(__soc_info, __base_index) \
((!__soc_info || __base_index >= __soc_info->num_reg_map) ? \
NULL : __soc_info->reg_map[__base_index].mem_base)
/*
* CAM_SOC_GET_REG_MAP_CAM_BASE
*
* @brief: This MACRO will get the cam_base of the
* register space
*
* @__soc_info: Device soc information
* @__base_index: Index of register space in the HW block
*
* @return: Returns an int32_t value.
* Failure: -1
* Success: Starting offset of register space compared
* to entire Camera Register Map
*/
#define CAM_SOC_GET_REG_MAP_CAM_BASE(__soc_info, __base_index) \
((!__soc_info || __base_index >= __soc_info->num_reg_map) ? \
-1 : __soc_info->reg_map[__base_index].mem_cam_base)
/*
* CAM_SOC_GET_REG_MAP_SIZE
*
* @brief: This MACRO will get the size of the mapped
* register space
*
* @__soc_info: Device soc information
* @__base_index: Index of register space in the HW block
*
* @return: Returns a uint32_t value.
* Failure: 0
* Success: Non-zero size of mapped register space
*/
#define CAM_SOC_GET_REG_MAP_SIZE(__soc_info, __base_index) \
((!__soc_info || __base_index >= __soc_info->num_reg_map) ? \
0 : __soc_info->reg_map[__base_index].size)
/**
* cam_soc_util_get_level_from_string()
*
* @brief: Get the associated vote level for the input string
*
* @string: Input string to compare with.
* @level: Vote level corresponds to input string.
*
* @return: Success or failure
*/
int cam_soc_util_get_level_from_string(const char *string,
enum cam_vote_level *level);
/**
* cam_soc_util_get_dt_properties()
*
* @brief: Parse the DT and populate the common properties that
* are part of the soc_info structure - register map,
* clocks, regulators, irq, etc.
*
* @soc_info: Device soc struct to be populated
*
* @return: Success or failure
*/
int cam_soc_util_get_dt_properties(struct cam_hw_soc_info *soc_info);
/**
* cam_soc_util_request_platform_resource()
*
* @brief: Request regulator, irq, and clock resources
*
* @soc_info: Device soc information
* @handler: Irq handler function pointer
* @irq_data: Irq handler function CB data
*
* @return: Success or failure
*/
int cam_soc_util_request_platform_resource(struct cam_hw_soc_info *soc_info,
irq_handler_t handler, void *irq_data);
/**
* cam_soc_util_release_platform_resource()
*
* @brief: Release regulator, irq, and clock resources
*
* @soc_info: Device soc information
*
* @return: Success or failure
*/
int cam_soc_util_release_platform_resource(struct cam_hw_soc_info *soc_info);
/**
* cam_soc_util_enable_platform_resource()
*
* @brief: Enable regulator, irq resources
*
* @soc_info: Device soc information
* @enable_clocks: Boolean flag:
* TRUE: Enable all clocks in soc_info Now.
* False: Don't enable clocks Now. Driver will
* enable independently.
* @clk_level: Clock level to be applied.
* Applicable only if enable_clocks is true
* Valid range : 0 to (CAM_MAX_VOTE - 1)
* @enable_irq: Boolean flag:
* TRUE: Enable IRQ in soc_info Now.
* False: Don't enable IRQ Now. Driver will
* enable independently.
*
* @return: Success or failure
*/
int cam_soc_util_enable_platform_resource(struct cam_hw_soc_info *soc_info,
bool enable_clocks, enum cam_vote_level clk_level, bool enable_irq);
/**
* cam_soc_util_disable_platform_resource()
*
* @brief: Disable regulator, irq resources
*
* @soc_info: Device soc information
* @disable_irq: Boolean flag:
* TRUE: Disable IRQ in soc_info Now.
* False: Don't disble IRQ Now. Driver will
* disable independently.
*
* @return: Success or failure
*/
int cam_soc_util_disable_platform_resource(struct cam_hw_soc_info *soc_info,
bool disable_clocks, bool disable_irq);
/**
* cam_soc_util_clk_enable()
*
* @brief: Enable clock specified in params
*
* @clk: Clock that needs to be turned ON
* @clk_name: Clocks name associated with clk
* @clk_rate: Clocks rate associated with clk
*
* @return: Success or failure
*/
int cam_soc_util_clk_enable(struct clk *clk, const char *clk_name,
int32_t clk_rate);
/**
* cam_soc_util_set_clk_rate_level()
*
* @brief: Apply clock rates for the requested level.
* This applies the new requested level for all
* the clocks listed in DT based on their values.
*
* @soc_info: Device soc information
* @clk_level: Clock level number to set
*
* @return: Success or failure
*/
int cam_soc_util_set_clk_rate_level(struct cam_hw_soc_info *soc_info,
enum cam_vote_level clk_level);
/**
* cam_soc_util_clk_disable()
*
* @brief: Disable clock specified in params
*
* @clk: Clock that needs to be turned OFF
* @clk_name: Clocks name associated with clk
*
* @return: Success or failure
*/
int cam_soc_util_clk_disable(struct clk *clk, const char *clk_name);
/**
* cam_soc_util_irq_enable()
*
* @brief: Enable IRQ in SOC
*
* @soc_info: Device soc information
*
* @return: Success or failure
*/
int cam_soc_util_irq_enable(struct cam_hw_soc_info *soc_info);
/**
* cam_soc_util_irq_disable()
*
* @brief: Disable IRQ in SOC
*
* @soc_info: Device soc information
*
* @return: Success or failure
*/
int cam_soc_util_irq_disable(struct cam_hw_soc_info *soc_info);
/**
* cam_soc_util_w()
*
* @brief: Camera SOC util for register write
*
* @soc_info: Device soc information
* @base_index: Index of register space in the HW block
* @offset: Offset of register to be read
* @data: Value to be written
*
* @return: Success or Failure
*/
static inline int cam_soc_util_w(struct cam_hw_soc_info *soc_info,
uint32_t base_index, uint32_t offset, uint32_t data)
{
if (!CAM_SOC_GET_REG_MAP_START(soc_info, base_index))
return -EINVAL;
return cam_io_w(data,
CAM_SOC_GET_REG_MAP_START(soc_info, base_index) + offset);
}
/**
* cam_soc_util_w_mb()
*
* @brief: Camera SOC util for register write with memory barrier.
* Memory Barrier is only before the write to ensure the
* order. If need to ensure this write is also flushed
* call wmb() independently in the caller.
*
* @soc_info: Device soc information
* @base_index: Index of register space in the HW block
* @offset: Offset of register to be read
* @data: Value to be written
*
* @return: Success or Failure
*/
static inline int cam_soc_util_w_mb(struct cam_hw_soc_info *soc_info,
uint32_t base_index, uint32_t offset, uint32_t data)
{
if (!CAM_SOC_GET_REG_MAP_START(soc_info, base_index))
return -EINVAL;
return cam_io_w_mb(data,
CAM_SOC_GET_REG_MAP_START(soc_info, base_index) + offset);
}
/**
* cam_soc_util_r()
*
* @brief: Camera SOC util for register read
*
* @soc_info: Device soc information
* @base_index: Index of register space in the HW block
* @offset: Offset of register to be read
*
* @return: Value read from the register address
*/
static inline uint32_t cam_soc_util_r(struct cam_hw_soc_info *soc_info,
uint32_t base_index, uint32_t offset)
{
if (!CAM_SOC_GET_REG_MAP_START(soc_info, base_index))
return 0;
return cam_io_r(
CAM_SOC_GET_REG_MAP_START(soc_info, base_index) + offset);
}
/**
* cam_soc_util_r_mb()
*
* @brief: Camera SOC util for register read with memory barrier.
* Memory Barrier is only before the write to ensure the
* order. If need to ensure this write is also flushed
* call rmb() independently in the caller.
*
* @soc_info: Device soc information
* @base_index: Index of register space in the HW block
* @offset: Offset of register to be read
*
* @return: Value read from the register address
*/
static inline uint32_t cam_soc_util_r_mb(struct cam_hw_soc_info *soc_info,
uint32_t base_index, uint32_t offset)
{
if (!CAM_SOC_GET_REG_MAP_START(soc_info, base_index))
return 0;
return cam_io_r_mb(
CAM_SOC_GET_REG_MAP_START(soc_info, base_index) + offset);
}
/**
* cam_soc_util_reg_dump()
*
* @brief: Camera SOC util for dumping a range of register
*
* @soc_info: Device soc information
* @base_index: Index of register space in the HW block
* @offset: Start register offset for the dump
* @size: Size specifying the range for dump
*
* @return: Success or Failure
*/
int cam_soc_util_reg_dump(struct cam_hw_soc_info *soc_info,
uint32_t base_index, uint32_t offset, int size);
#endif /* _CAM_SOC_UTIL_H_ */