2022-04-22 23:52:14 +03:00
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright ( c ) 2021 - 2022 NVIDIA Corporation
*
* Author : Dipen Patel < dipenp @ nvidia . com >
*/
# include <linux/err.h>
# include <linux/io.h>
# include <linux/module.h>
# include <linux/slab.h>
# include <linux/stat.h>
# include <linux/interrupt.h>
# include <linux/of.h>
# include <linux/platform_device.h>
# include <linux/hte.h>
# include <linux/uaccess.h>
# include <linux/gpio/driver.h>
# include <linux/gpio/consumer.h>
# define HTE_SUSPEND 0
/* HTE source clock TSC is 31.25MHz */
# define HTE_TS_CLK_RATE_HZ 31250000ULL
# define HTE_CLK_RATE_NS 32
# define HTE_TS_NS_SHIFT __builtin_ctz(HTE_CLK_RATE_NS)
# define NV_AON_SLICE_INVALID -1
# define NV_LINES_IN_SLICE 32
/* AON HTE line map For slice 1 */
# define NV_AON_HTE_SLICE1_IRQ_GPIO_28 12
# define NV_AON_HTE_SLICE1_IRQ_GPIO_29 13
/* AON HTE line map For slice 2 */
# define NV_AON_HTE_SLICE2_IRQ_GPIO_0 0
# define NV_AON_HTE_SLICE2_IRQ_GPIO_1 1
# define NV_AON_HTE_SLICE2_IRQ_GPIO_2 2
# define NV_AON_HTE_SLICE2_IRQ_GPIO_3 3
# define NV_AON_HTE_SLICE2_IRQ_GPIO_4 4
# define NV_AON_HTE_SLICE2_IRQ_GPIO_5 5
# define NV_AON_HTE_SLICE2_IRQ_GPIO_6 6
# define NV_AON_HTE_SLICE2_IRQ_GPIO_7 7
# define NV_AON_HTE_SLICE2_IRQ_GPIO_8 8
# define NV_AON_HTE_SLICE2_IRQ_GPIO_9 9
# define NV_AON_HTE_SLICE2_IRQ_GPIO_10 10
# define NV_AON_HTE_SLICE2_IRQ_GPIO_11 11
# define NV_AON_HTE_SLICE2_IRQ_GPIO_12 12
# define NV_AON_HTE_SLICE2_IRQ_GPIO_13 13
# define NV_AON_HTE_SLICE2_IRQ_GPIO_14 14
# define NV_AON_HTE_SLICE2_IRQ_GPIO_15 15
# define NV_AON_HTE_SLICE2_IRQ_GPIO_16 16
# define NV_AON_HTE_SLICE2_IRQ_GPIO_17 17
# define NV_AON_HTE_SLICE2_IRQ_GPIO_18 18
# define NV_AON_HTE_SLICE2_IRQ_GPIO_19 19
# define NV_AON_HTE_SLICE2_IRQ_GPIO_20 20
# define NV_AON_HTE_SLICE2_IRQ_GPIO_21 21
# define NV_AON_HTE_SLICE2_IRQ_GPIO_22 22
# define NV_AON_HTE_SLICE2_IRQ_GPIO_23 23
# define NV_AON_HTE_SLICE2_IRQ_GPIO_24 24
# define NV_AON_HTE_SLICE2_IRQ_GPIO_25 25
# define NV_AON_HTE_SLICE2_IRQ_GPIO_26 26
# define NV_AON_HTE_SLICE2_IRQ_GPIO_27 27
2023-04-14 03:44:52 +03:00
# define NV_AON_HTE_SLICE2_IRQ_GPIO_28 28
# define NV_AON_HTE_SLICE2_IRQ_GPIO_29 29
# define NV_AON_HTE_SLICE2_IRQ_GPIO_30 30
# define NV_AON_HTE_SLICE2_IRQ_GPIO_31 31
2022-04-22 23:52:14 +03:00
# define HTE_TECTRL 0x0
# define HTE_TETSCH 0x4
# define HTE_TETSCL 0x8
# define HTE_TESRC 0xC
# define HTE_TECCV 0x10
# define HTE_TEPCV 0x14
# define HTE_TECMD 0x1C
# define HTE_TESTATUS 0x20
# define HTE_SLICE0_TETEN 0x40
# define HTE_SLICE1_TETEN 0x60
# define HTE_SLICE_SIZE (HTE_SLICE1_TETEN - HTE_SLICE0_TETEN)
# define HTE_TECTRL_ENABLE_ENABLE 0x1
# define HTE_TECTRL_OCCU_SHIFT 0x8
# define HTE_TECTRL_INTR_SHIFT 0x1
# define HTE_TECTRL_INTR_ENABLE 0x1
# define HTE_TESRC_SLICE_SHIFT 16
# define HTE_TESRC_SLICE_DEFAULT_MASK 0xFF
# define HTE_TECMD_CMD_POP 0x1
# define HTE_TESTATUS_OCCUPANCY_SHIFT 8
# define HTE_TESTATUS_OCCUPANCY_MASK 0xFF
enum tegra_hte_type {
HTE_TEGRA_TYPE_GPIO = 1U < < 0 ,
HTE_TEGRA_TYPE_LIC = 1U < < 1 ,
} ;
struct hte_slices {
u32 r_val ;
unsigned long flags ;
/* to prevent lines mapped to same slice updating its register */
spinlock_t s_lock ;
} ;
struct tegra_hte_line_mapped {
int slice ;
u32 bit_index ;
} ;
struct tegra_hte_line_data {
unsigned long flags ;
void * data ;
} ;
struct tegra_hte_data {
enum tegra_hte_type type ;
2023-04-14 03:44:53 +03:00
u32 slices ;
2022-04-22 23:52:14 +03:00
u32 map_sz ;
u32 sec_map_sz ;
const struct tegra_hte_line_mapped * map ;
const struct tegra_hte_line_mapped * sec_map ;
} ;
struct tegra_hte_soc {
int hte_irq ;
u32 itr_thrshld ;
u32 conf_rval ;
struct hte_slices * sl ;
const struct tegra_hte_data * prov_data ;
struct tegra_hte_line_data * line_data ;
struct hte_chip * chip ;
struct gpio_chip * c ;
void __iomem * regs ;
} ;
static const struct tegra_hte_line_mapped tegra194_aon_gpio_map [ ] = {
/* gpio, slice, bit_index */
/* AA port */
[ 0 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_11 } ,
[ 1 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_10 } ,
[ 2 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_9 } ,
[ 3 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_8 } ,
[ 4 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_7 } ,
[ 5 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_6 } ,
[ 6 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_5 } ,
[ 7 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_4 } ,
/* BB port */
[ 8 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_3 } ,
[ 9 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_2 } ,
[ 10 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_1 } ,
[ 11 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_0 } ,
/* CC port */
[ 12 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_22 } ,
[ 13 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_21 } ,
[ 14 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_20 } ,
[ 15 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_19 } ,
[ 16 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_18 } ,
[ 17 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_17 } ,
[ 18 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_16 } ,
[ 19 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_15 } ,
/* DD port */
[ 20 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_14 } ,
[ 21 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_13 } ,
[ 22 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_12 } ,
/* EE port */
[ 23 ] = { 1 , NV_AON_HTE_SLICE1_IRQ_GPIO_29 } ,
[ 24 ] = { 1 , NV_AON_HTE_SLICE1_IRQ_GPIO_28 } ,
[ 25 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_27 } ,
[ 26 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_26 } ,
[ 27 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_25 } ,
[ 28 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_24 } ,
[ 29 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_23 } ,
} ;
static const struct tegra_hte_line_mapped tegra194_aon_gpio_sec_map [ ] = {
/* gpio, slice, bit_index */
/* AA port */
[ 0 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_11 } ,
[ 1 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_10 } ,
[ 2 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_9 } ,
[ 3 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_8 } ,
[ 4 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_7 } ,
[ 5 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_6 } ,
[ 6 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_5 } ,
[ 7 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_4 } ,
/* BB port */
[ 8 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_3 } ,
[ 9 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_2 } ,
[ 10 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_1 } ,
[ 11 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_0 } ,
[ 12 ] = { NV_AON_SLICE_INVALID , 0 } ,
[ 13 ] = { NV_AON_SLICE_INVALID , 0 } ,
[ 14 ] = { NV_AON_SLICE_INVALID , 0 } ,
[ 15 ] = { NV_AON_SLICE_INVALID , 0 } ,
/* CC port */
[ 16 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_22 } ,
[ 17 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_21 } ,
[ 18 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_20 } ,
[ 19 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_19 } ,
[ 20 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_18 } ,
[ 21 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_17 } ,
[ 22 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_16 } ,
[ 23 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_15 } ,
/* DD port */
[ 24 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_14 } ,
[ 25 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_13 } ,
[ 26 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_12 } ,
[ 27 ] = { NV_AON_SLICE_INVALID , 0 } ,
[ 28 ] = { NV_AON_SLICE_INVALID , 0 } ,
[ 29 ] = { NV_AON_SLICE_INVALID , 0 } ,
[ 30 ] = { NV_AON_SLICE_INVALID , 0 } ,
[ 31 ] = { NV_AON_SLICE_INVALID , 0 } ,
/* EE port */
[ 32 ] = { 1 , NV_AON_HTE_SLICE1_IRQ_GPIO_29 } ,
[ 33 ] = { 1 , NV_AON_HTE_SLICE1_IRQ_GPIO_28 } ,
[ 34 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_27 } ,
[ 35 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_26 } ,
[ 36 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_25 } ,
[ 37 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_24 } ,
[ 38 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_23 } ,
[ 39 ] = { NV_AON_SLICE_INVALID , 0 } ,
} ;
2023-04-14 03:44:52 +03:00
static const struct tegra_hte_line_mapped tegra234_aon_gpio_map [ ] = {
/* gpio, slice, bit_index */
/* AA port */
[ 0 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_11 } ,
[ 1 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_10 } ,
[ 2 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_9 } ,
[ 3 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_8 } ,
[ 4 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_7 } ,
[ 5 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_6 } ,
[ 6 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_5 } ,
[ 7 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_4 } ,
/* BB port */
[ 8 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_3 } ,
[ 9 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_2 } ,
[ 10 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_1 } ,
[ 11 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_0 } ,
/* CC port */
[ 12 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_22 } ,
[ 13 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_21 } ,
[ 14 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_20 } ,
[ 15 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_19 } ,
[ 16 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_18 } ,
[ 17 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_17 } ,
[ 18 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_16 } ,
[ 19 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_15 } ,
/* DD port */
[ 20 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_14 } ,
[ 21 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_13 } ,
[ 22 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_12 } ,
/* EE port */
[ 23 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_31 } ,
[ 24 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_30 } ,
[ 25 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_29 } ,
[ 26 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_28 } ,
[ 27 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_27 } ,
[ 28 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_26 } ,
[ 29 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_25 } ,
[ 30 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_24 } ,
/* GG port */
[ 31 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_23 } ,
} ;
static const struct tegra_hte_line_mapped tegra234_aon_gpio_sec_map [ ] = {
/* gpio, slice, bit_index */
/* AA port */
[ 0 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_11 } ,
[ 1 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_10 } ,
[ 2 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_9 } ,
[ 3 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_8 } ,
[ 4 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_7 } ,
[ 5 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_6 } ,
[ 6 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_5 } ,
[ 7 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_4 } ,
/* BB port */
[ 8 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_3 } ,
[ 9 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_2 } ,
[ 10 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_1 } ,
[ 11 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_0 } ,
[ 12 ] = { NV_AON_SLICE_INVALID , 0 } ,
[ 13 ] = { NV_AON_SLICE_INVALID , 0 } ,
[ 14 ] = { NV_AON_SLICE_INVALID , 0 } ,
[ 15 ] = { NV_AON_SLICE_INVALID , 0 } ,
/* CC port */
[ 16 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_22 } ,
[ 17 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_21 } ,
[ 18 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_20 } ,
[ 19 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_19 } ,
[ 20 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_18 } ,
[ 21 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_17 } ,
[ 22 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_16 } ,
[ 23 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_15 } ,
/* DD port */
[ 24 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_14 } ,
[ 25 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_13 } ,
[ 26 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_12 } ,
[ 27 ] = { NV_AON_SLICE_INVALID , 0 } ,
[ 28 ] = { NV_AON_SLICE_INVALID , 0 } ,
[ 29 ] = { NV_AON_SLICE_INVALID , 0 } ,
[ 30 ] = { NV_AON_SLICE_INVALID , 0 } ,
[ 31 ] = { NV_AON_SLICE_INVALID , 0 } ,
/* EE port */
[ 32 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_31 } ,
[ 33 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_30 } ,
[ 34 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_29 } ,
[ 35 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_28 } ,
[ 36 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_27 } ,
[ 37 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_26 } ,
[ 38 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_25 } ,
[ 39 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_24 } ,
/* GG port */
[ 40 ] = { 2 , NV_AON_HTE_SLICE2_IRQ_GPIO_23 } ,
} ;
static const struct tegra_hte_data t194_aon_hte = {
2022-04-22 23:52:14 +03:00
. map_sz = ARRAY_SIZE ( tegra194_aon_gpio_map ) ,
. map = tegra194_aon_gpio_map ,
. sec_map_sz = ARRAY_SIZE ( tegra194_aon_gpio_sec_map ) ,
. sec_map = tegra194_aon_gpio_sec_map ,
. type = HTE_TEGRA_TYPE_GPIO ,
2023-04-14 03:44:53 +03:00
. slices = 3 ,
2022-04-22 23:52:14 +03:00
} ;
2023-04-14 03:44:52 +03:00
static const struct tegra_hte_data t234_aon_hte = {
. map_sz = ARRAY_SIZE ( tegra234_aon_gpio_map ) ,
. map = tegra234_aon_gpio_map ,
. sec_map_sz = ARRAY_SIZE ( tegra234_aon_gpio_sec_map ) ,
. sec_map = tegra234_aon_gpio_sec_map ,
. type = HTE_TEGRA_TYPE_GPIO ,
2023-04-14 03:44:53 +03:00
. slices = 3 ,
2023-04-14 03:44:52 +03:00
} ;
2023-04-14 03:44:53 +03:00
static const struct tegra_hte_data t194_lic_hte = {
2022-04-22 23:52:14 +03:00
. map_sz = 0 ,
. map = NULL ,
. type = HTE_TEGRA_TYPE_LIC ,
2023-04-14 03:44:53 +03:00
. slices = 11 ,
} ;
static const struct tegra_hte_data t234_lic_hte = {
. map_sz = 0 ,
. map = NULL ,
. type = HTE_TEGRA_TYPE_LIC ,
. slices = 17 ,
2022-04-22 23:52:14 +03:00
} ;
static inline u32 tegra_hte_readl ( struct tegra_hte_soc * hte , u32 reg )
{
return readl ( hte - > regs + reg ) ;
}
static inline void tegra_hte_writel ( struct tegra_hte_soc * hte , u32 reg ,
u32 val )
{
writel ( val , hte - > regs + reg ) ;
}
static int tegra_hte_map_to_line_id ( u32 eid ,
const struct tegra_hte_line_mapped * m ,
u32 map_sz , u32 * mapped )
{
if ( m ) {
2023-04-19 17:30:00 +03:00
if ( eid > = map_sz )
2022-04-22 23:52:14 +03:00
return - EINVAL ;
if ( m [ eid ] . slice = = NV_AON_SLICE_INVALID )
return - EINVAL ;
* mapped = ( m [ eid ] . slice < < 5 ) + m [ eid ] . bit_index ;
} else {
* mapped = eid ;
}
return 0 ;
}
static int tegra_hte_line_xlate ( struct hte_chip * gc ,
const struct of_phandle_args * args ,
struct hte_ts_desc * desc , u32 * xlated_id )
{
int ret = 0 ;
u32 line_id ;
struct tegra_hte_soc * gs ;
const struct tegra_hte_line_mapped * map = NULL ;
u32 map_sz = 0 ;
if ( ! gc | | ! desc | | ! xlated_id )
return - EINVAL ;
if ( args ) {
if ( gc - > of_hte_n_cells < 1 )
return - EINVAL ;
if ( args - > args_count ! = gc - > of_hte_n_cells )
return - EINVAL ;
desc - > attr . line_id = args - > args [ 0 ] ;
}
gs = gc - > data ;
if ( ! gs | | ! gs - > prov_data )
return - EINVAL ;
/*
*
* There are two paths GPIO consumers can take as follows :
* 1 ) The consumer ( gpiolib - cdev for example ) which uses GPIO global
* number which gets assigned run time .
* 2 ) The consumer passing GPIO from the DT which is assigned
* statically for example by using TEGRA194_AON_GPIO gpio DT binding .
*
* The code below addresses both the consumer use cases and maps into
* HTE / GTE namespace .
*/
if ( gs - > prov_data - > type = = HTE_TEGRA_TYPE_GPIO & & ! args ) {
line_id = desc - > attr . line_id - gs - > c - > base ;
map = gs - > prov_data - > map ;
map_sz = gs - > prov_data - > map_sz ;
} else if ( gs - > prov_data - > type = = HTE_TEGRA_TYPE_GPIO & & args ) {
line_id = desc - > attr . line_id ;
map = gs - > prov_data - > sec_map ;
map_sz = gs - > prov_data - > sec_map_sz ;
} else {
line_id = desc - > attr . line_id ;
}
ret = tegra_hte_map_to_line_id ( line_id , map , map_sz , xlated_id ) ;
if ( ret < 0 ) {
dev_err ( gc - > dev , " line_id:%u mapping failed \n " ,
desc - > attr . line_id ) ;
return ret ;
}
if ( * xlated_id > gc - > nlines )
return - EINVAL ;
dev_dbg ( gc - > dev , " requested id:%u, xlated id:%u \n " ,
desc - > attr . line_id , * xlated_id ) ;
return 0 ;
}
static int tegra_hte_line_xlate_plat ( struct hte_chip * gc ,
struct hte_ts_desc * desc , u32 * xlated_id )
{
return tegra_hte_line_xlate ( gc , NULL , desc , xlated_id ) ;
}
static int tegra_hte_en_dis_common ( struct hte_chip * chip , u32 line_id , bool en )
{
u32 slice , sl_bit_shift , line_bit , val , reg ;
struct tegra_hte_soc * gs ;
sl_bit_shift = __builtin_ctz ( HTE_SLICE_SIZE ) ;
if ( ! chip )
return - EINVAL ;
gs = chip - > data ;
if ( line_id > chip - > nlines ) {
dev_err ( chip - > dev ,
" line id: %u is not supported by this controller \n " ,
line_id ) ;
return - EINVAL ;
}
slice = line_id > > sl_bit_shift ;
line_bit = line_id & ( HTE_SLICE_SIZE - 1 ) ;
reg = ( slice < < sl_bit_shift ) + HTE_SLICE0_TETEN ;
spin_lock ( & gs - > sl [ slice ] . s_lock ) ;
if ( test_bit ( HTE_SUSPEND , & gs - > sl [ slice ] . flags ) ) {
spin_unlock ( & gs - > sl [ slice ] . s_lock ) ;
dev_dbg ( chip - > dev , " device suspended " ) ;
return - EBUSY ;
}
val = tegra_hte_readl ( gs , reg ) ;
if ( en )
val = val | ( 1 < < line_bit ) ;
else
val = val & ( ~ ( 1 < < line_bit ) ) ;
tegra_hte_writel ( gs , reg , val ) ;
spin_unlock ( & gs - > sl [ slice ] . s_lock ) ;
dev_dbg ( chip - > dev , " line: %u, slice %u, line_bit %u, reg:0x%x \n " ,
line_id , slice , line_bit , reg ) ;
return 0 ;
}
static int tegra_hte_enable ( struct hte_chip * chip , u32 line_id )
{
if ( ! chip )
return - EINVAL ;
return tegra_hte_en_dis_common ( chip , line_id , true ) ;
}
static int tegra_hte_disable ( struct hte_chip * chip , u32 line_id )
{
if ( ! chip )
return - EINVAL ;
return tegra_hte_en_dis_common ( chip , line_id , false ) ;
}
static int tegra_hte_request ( struct hte_chip * chip , struct hte_ts_desc * desc ,
u32 line_id )
{
int ret ;
struct tegra_hte_soc * gs ;
struct hte_line_attr * attr ;
if ( ! chip | | ! chip - > data | | ! desc )
return - EINVAL ;
gs = chip - > data ;
attr = & desc - > attr ;
if ( gs - > prov_data - > type = = HTE_TEGRA_TYPE_GPIO ) {
if ( ! attr - > line_data )
return - EINVAL ;
ret = gpiod_enable_hw_timestamp_ns ( attr - > line_data ,
attr - > edge_flags ) ;
if ( ret )
return ret ;
gs - > line_data [ line_id ] . data = attr - > line_data ;
gs - > line_data [ line_id ] . flags = attr - > edge_flags ;
}
return tegra_hte_en_dis_common ( chip , line_id , true ) ;
}
static int tegra_hte_release ( struct hte_chip * chip , struct hte_ts_desc * desc ,
u32 line_id )
{
struct tegra_hte_soc * gs ;
struct hte_line_attr * attr ;
int ret ;
if ( ! chip | | ! chip - > data | | ! desc )
return - EINVAL ;
gs = chip - > data ;
attr = & desc - > attr ;
if ( gs - > prov_data - > type = = HTE_TEGRA_TYPE_GPIO ) {
ret = gpiod_disable_hw_timestamp_ns ( attr - > line_data ,
gs - > line_data [ line_id ] . flags ) ;
if ( ret )
return ret ;
gs - > line_data [ line_id ] . data = NULL ;
gs - > line_data [ line_id ] . flags = 0 ;
}
return tegra_hte_en_dis_common ( chip , line_id , false ) ;
}
static int tegra_hte_clk_src_info ( struct hte_chip * chip ,
struct hte_clk_info * ci )
{
( void ) chip ;
if ( ! ci )
return - EINVAL ;
ci - > hz = HTE_TS_CLK_RATE_HZ ;
ci - > type = CLOCK_MONOTONIC ;
return 0 ;
}
static int tegra_hte_get_level ( struct tegra_hte_soc * gs , u32 line_id )
{
struct gpio_desc * desc ;
if ( gs - > prov_data - > type = = HTE_TEGRA_TYPE_GPIO ) {
desc = gs - > line_data [ line_id ] . data ;
if ( desc )
return gpiod_get_raw_value ( desc ) ;
}
return - 1 ;
}
static void tegra_hte_read_fifo ( struct tegra_hte_soc * gs )
{
u32 tsh , tsl , src , pv , cv , acv , slice , bit_index , line_id ;
u64 tsc ;
struct hte_ts_data el ;
while ( ( tegra_hte_readl ( gs , HTE_TESTATUS ) > >
HTE_TESTATUS_OCCUPANCY_SHIFT ) &
HTE_TESTATUS_OCCUPANCY_MASK ) {
tsh = tegra_hte_readl ( gs , HTE_TETSCH ) ;
tsl = tegra_hte_readl ( gs , HTE_TETSCL ) ;
tsc = ( ( ( u64 ) tsh < < 32 ) | tsl ) ;
src = tegra_hte_readl ( gs , HTE_TESRC ) ;
slice = ( src > > HTE_TESRC_SLICE_SHIFT ) &
HTE_TESRC_SLICE_DEFAULT_MASK ;
pv = tegra_hte_readl ( gs , HTE_TEPCV ) ;
cv = tegra_hte_readl ( gs , HTE_TECCV ) ;
acv = pv ^ cv ;
while ( acv ) {
bit_index = __builtin_ctz ( acv ) ;
line_id = bit_index + ( slice < < 5 ) ;
el . tsc = tsc < < HTE_TS_NS_SHIFT ;
el . raw_level = tegra_hte_get_level ( gs , line_id ) ;
hte_push_ts_ns ( gs - > chip , line_id , & el ) ;
acv & = ~ BIT ( bit_index ) ;
}
tegra_hte_writel ( gs , HTE_TECMD , HTE_TECMD_CMD_POP ) ;
}
}
static irqreturn_t tegra_hte_isr ( int irq , void * dev_id )
{
struct tegra_hte_soc * gs = dev_id ;
( void ) irq ;
tegra_hte_read_fifo ( gs ) ;
return IRQ_HANDLED ;
}
static bool tegra_hte_match_from_linedata ( const struct hte_chip * chip ,
const struct hte_ts_desc * hdesc )
{
struct tegra_hte_soc * hte_dev = chip - > data ;
if ( ! hte_dev | | ( hte_dev - > prov_data - > type ! = HTE_TEGRA_TYPE_GPIO ) )
return false ;
return hte_dev - > c = = gpiod_to_chip ( hdesc - > attr . line_data ) ;
}
static const struct of_device_id tegra_hte_of_match [ ] = {
2023-04-14 03:44:53 +03:00
{ . compatible = " nvidia,tegra194-gte-lic " , . data = & t194_lic_hte } ,
2023-04-14 03:44:52 +03:00
{ . compatible = " nvidia,tegra194-gte-aon " , . data = & t194_aon_hte } ,
2023-04-14 03:44:53 +03:00
{ . compatible = " nvidia,tegra234-gte-lic " , . data = & t234_lic_hte } ,
2023-04-14 03:44:52 +03:00
{ . compatible = " nvidia,tegra234-gte-aon " , . data = & t234_aon_hte } ,
2022-04-22 23:52:14 +03:00
{ }
} ;
MODULE_DEVICE_TABLE ( of , tegra_hte_of_match ) ;
static const struct hte_ops g_ops = {
. request = tegra_hte_request ,
. release = tegra_hte_release ,
. enable = tegra_hte_enable ,
. disable = tegra_hte_disable ,
. get_clk_src_info = tegra_hte_clk_src_info ,
} ;
static void tegra_gte_disable ( void * data )
{
struct platform_device * pdev = data ;
struct tegra_hte_soc * gs = dev_get_drvdata ( & pdev - > dev ) ;
tegra_hte_writel ( gs , HTE_TECTRL , 0 ) ;
}
static int tegra_get_gpiochip_from_name ( struct gpio_chip * chip , void * data )
{
return ! strcmp ( chip - > label , data ) ;
}
2023-04-14 03:44:54 +03:00
static int tegra_gpiochip_match ( struct gpio_chip * chip , void * data )
{
return chip - > fwnode = = of_node_to_fwnode ( data ) ;
}
2022-04-22 23:52:14 +03:00
static int tegra_hte_probe ( struct platform_device * pdev )
{
int ret ;
u32 i , slices , val = 0 ;
u32 nlines ;
struct device * dev ;
struct tegra_hte_soc * hte_dev ;
struct hte_chip * gc ;
2023-04-14 03:44:54 +03:00
struct device_node * gpio_ctrl ;
2022-04-22 23:52:14 +03:00
dev = & pdev - > dev ;
hte_dev = devm_kzalloc ( dev , sizeof ( * hte_dev ) , GFP_KERNEL ) ;
if ( ! hte_dev )
return - ENOMEM ;
gc = devm_kzalloc ( dev , sizeof ( * gc ) , GFP_KERNEL ) ;
if ( ! gc )
return - ENOMEM ;
dev_set_drvdata ( & pdev - > dev , hte_dev ) ;
hte_dev - > prov_data = of_device_get_match_data ( & pdev - > dev ) ;
2023-04-14 03:44:53 +03:00
ret = of_property_read_u32 ( dev - > of_node , " nvidia,slices " , & slices ) ;
if ( ret ! = 0 )
slices = hte_dev - > prov_data - > slices ;
dev_dbg ( dev , " slices:%d \n " , slices ) ;
nlines = slices < < 5 ;
2022-04-22 23:52:14 +03:00
hte_dev - > regs = devm_platform_ioremap_resource ( pdev , 0 ) ;
if ( IS_ERR ( hte_dev - > regs ) )
return PTR_ERR ( hte_dev - > regs ) ;
ret = of_property_read_u32 ( dev - > of_node , " nvidia,int-threshold " ,
& hte_dev - > itr_thrshld ) ;
if ( ret ! = 0 )
hte_dev - > itr_thrshld = 1 ;
hte_dev - > sl = devm_kcalloc ( dev , slices , sizeof ( * hte_dev - > sl ) ,
GFP_KERNEL ) ;
if ( ! hte_dev - > sl )
return - ENOMEM ;
ret = platform_get_irq ( pdev , 0 ) ;
if ( ret < 0 ) {
dev_err_probe ( dev , ret , " failed to get irq \n " ) ;
return ret ;
}
hte_dev - > hte_irq = ret ;
ret = devm_request_irq ( dev , hte_dev - > hte_irq , tegra_hte_isr , 0 ,
dev_name ( dev ) , hte_dev ) ;
if ( ret < 0 ) {
dev_err ( dev , " request irq failed. \n " ) ;
return ret ;
}
gc - > nlines = nlines ;
gc - > ops = & g_ops ;
gc - > dev = dev ;
gc - > data = hte_dev ;
gc - > xlate_of = tegra_hte_line_xlate ;
gc - > xlate_plat = tegra_hte_line_xlate_plat ;
gc - > of_hte_n_cells = 1 ;
if ( hte_dev - > prov_data & &
hte_dev - > prov_data - > type = = HTE_TEGRA_TYPE_GPIO ) {
hte_dev - > line_data = devm_kcalloc ( dev , nlines ,
sizeof ( * hte_dev - > line_data ) ,
GFP_KERNEL ) ;
if ( ! hte_dev - > line_data )
return - ENOMEM ;
gc - > match_from_linedata = tegra_hte_match_from_linedata ;
2023-04-14 03:44:52 +03:00
if ( of_device_is_compatible ( dev - > of_node ,
2023-04-14 03:44:54 +03:00
" nvidia,tegra194-gte-aon " ) ) {
2023-04-14 03:44:52 +03:00
hte_dev - > c = gpiochip_find ( " tegra194-gpio-aon " ,
tegra_get_gpiochip_from_name ) ;
2023-04-14 03:44:54 +03:00
} else {
gpio_ctrl = of_parse_phandle ( dev - > of_node ,
" nvidia,gpio-controller " ,
0 ) ;
if ( ! gpio_ctrl ) {
dev_err ( dev ,
" gpio controller node not found \n " ) ;
return - ENODEV ;
}
hte_dev - > c = gpiochip_find ( gpio_ctrl ,
tegra_gpiochip_match ) ;
of_node_put ( gpio_ctrl ) ;
}
2023-04-14 03:44:52 +03:00
2022-04-22 23:52:14 +03:00
if ( ! hte_dev - > c )
return dev_err_probe ( dev , - EPROBE_DEFER ,
" wait for gpio controller \n " ) ;
}
hte_dev - > chip = gc ;
ret = devm_hte_register_chip ( hte_dev - > chip ) ;
if ( ret ) {
dev_err ( gc - > dev , " hte chip register failed " ) ;
return ret ;
}
for ( i = 0 ; i < slices ; i + + ) {
hte_dev - > sl [ i ] . flags = 0 ;
spin_lock_init ( & hte_dev - > sl [ i ] . s_lock ) ;
}
val = HTE_TECTRL_ENABLE_ENABLE |
( HTE_TECTRL_INTR_ENABLE < < HTE_TECTRL_INTR_SHIFT ) |
( hte_dev - > itr_thrshld < < HTE_TECTRL_OCCU_SHIFT ) ;
tegra_hte_writel ( hte_dev , HTE_TECTRL , val ) ;
ret = devm_add_action_or_reset ( & pdev - > dev , tegra_gte_disable , pdev ) ;
if ( ret )
return ret ;
dev_dbg ( gc - > dev , " lines: %d, slices:%d " , gc - > nlines , slices ) ;
return 0 ;
}
static int __maybe_unused tegra_hte_resume_early ( struct device * dev )
{
u32 i ;
struct tegra_hte_soc * gs = dev_get_drvdata ( dev ) ;
u32 slices = gs - > chip - > nlines / NV_LINES_IN_SLICE ;
u32 sl_bit_shift = __builtin_ctz ( HTE_SLICE_SIZE ) ;
tegra_hte_writel ( gs , HTE_TECTRL , gs - > conf_rval ) ;
for ( i = 0 ; i < slices ; i + + ) {
spin_lock ( & gs - > sl [ i ] . s_lock ) ;
tegra_hte_writel ( gs ,
( ( i < < sl_bit_shift ) + HTE_SLICE0_TETEN ) ,
gs - > sl [ i ] . r_val ) ;
clear_bit ( HTE_SUSPEND , & gs - > sl [ i ] . flags ) ;
spin_unlock ( & gs - > sl [ i ] . s_lock ) ;
}
return 0 ;
}
static int __maybe_unused tegra_hte_suspend_late ( struct device * dev )
{
u32 i ;
struct tegra_hte_soc * gs = dev_get_drvdata ( dev ) ;
u32 slices = gs - > chip - > nlines / NV_LINES_IN_SLICE ;
u32 sl_bit_shift = __builtin_ctz ( HTE_SLICE_SIZE ) ;
gs - > conf_rval = tegra_hte_readl ( gs , HTE_TECTRL ) ;
for ( i = 0 ; i < slices ; i + + ) {
spin_lock ( & gs - > sl [ i ] . s_lock ) ;
gs - > sl [ i ] . r_val = tegra_hte_readl ( gs ,
( ( i < < sl_bit_shift ) + HTE_SLICE0_TETEN ) ) ;
set_bit ( HTE_SUSPEND , & gs - > sl [ i ] . flags ) ;
spin_unlock ( & gs - > sl [ i ] . s_lock ) ;
}
return 0 ;
}
static const struct dev_pm_ops tegra_hte_pm = {
SET_LATE_SYSTEM_SLEEP_PM_OPS ( tegra_hte_suspend_late ,
tegra_hte_resume_early )
} ;
static struct platform_driver tegra_hte_driver = {
. probe = tegra_hte_probe ,
. driver = {
. name = " tegra_hte " ,
. pm = & tegra_hte_pm ,
. of_match_table = tegra_hte_of_match ,
} ,
} ;
module_platform_driver ( tegra_hte_driver ) ;
MODULE_AUTHOR ( " Dipen Patel <dipenp@nvidia.com> " ) ;
MODULE_DESCRIPTION ( " NVIDIA Tegra HTE (Hardware Timestamping Engine) driver " ) ;
MODULE_LICENSE ( " GPL " ) ;