NVIDIA: SAUCE: platform: tegra: Add tegra prod as built-in driver

BugLink: https://bugs.launchpad.net/bugs/2080908

This is an integration squash change of below commits.

 - [INTG: NV INTERNAL] platform: tegra: Add tegra prod as built-in
 - [INTG: NV INTERNAL] platform: tegra: Add tegra prod framework
 - [INTG: NV INTERNAL] platform: tegra: Add support for mask with 1s
 - [INTG: NV INTERNAL] platform: tegra_prod: Use kmemleak_not_leak for allocated memory
 - [INTG: NV INTERNAL] platform: tegra_prod: Fix prod setting parsing for package/board
 - [INTG: NV INTERNAL] platform: tegra_prod: Use proper variable name
 - [INTG: NV INTERNAL] platform: tegra_prod: Use for_each_available_child_of_node()
 - [INTG: NV INTERNAL] platform: tegra: move struct tegra_prod_list to private
 - [INTG: NV INTERNAL] platform: tegra_prod: Add APIs to managed allocation of prod_list
 - [INTG: NV INTERNAL] platform: tegra_prod: Remove unused APIs from public header
 - [INTG: NV INTERNAL] platform: tegra_prod: Get rid of tegra_prod_release()
 - [INTG: NV INTERNAL] platform: tegra_prod: Add support for nested prod nodes
 - [INTG: NV INTERNAL] platform: tegra_prod: Add devm_tegra_prod_get_from_node()
 - [INTG: NV INTERNAL] platform: tegra_prod: use devm_ for allocation
 - [INTG: NV INTERNAL] platform: tegra_prod: Do not use kmemleak_not_leak()
 - [INTG: NV INTERNAL] platform: tegra: Add support to find prod setting
 - [INTG: NV INTERNAL] platform: tegra: APIs to set prod based on name/index/offset/mask
 - [INTG: NV INTERNAL] prod: Add support for masked write in partially prod config
 - [INTG: NV INTERNAL] platform: tegra_prod: Use strcasecmp() for prod name
 - [INTG: NV INTERNAL] prod: set prod-settings mask to 1-style default
 - [INTG: NV INTERNAL] platform: tegra_prod: add support to avoid multiple configruation
 - soc: tegra: Add prod configuration parser
 - prod: remove package and board specific prod node
 - platform: tegra: Add config for next generation tegra prod
 - tegra-prod: Add legacy and next gen prod based on config
 - tegra-prod: Fix missing last entry
 - tegra-prod: Fix null pointer error
 - tegra-prod: Fix null pointer error
 - tegra: prod: remove new prod settings support

http://nvbugs/4165866
http://nvbugs/200416207
http://nvbugs/1758682
http://nvbugs/1745386
http://nvbugs/1768583
http://nvbugs/200217343
http://nvbugs/200215286
http://nvbugs/1807581
http://nvbugs/1865456
http://nvbugs/4097475
http://nvbugs/3389584
http://nvbugs/4638219
http://nvbugs/4283554
http://nvbugs/4765671
http://nvbugs/4754882

Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
Signed-off-by: Petlozu Pravareshwar <petlozup@nvidia.com>
Acked-by: Noah Wager <noah.wager@canonical.com>
Acked-by: Jacob Martin <jacob.martin@canonical.com>
Signed-off-by: Noah Wager <noah.wager@canonical.com>
This commit is contained in:
Laxman Dewangan
2023-06-22 12:34:49 +00:00
committed by Thomas Makin
parent 9b8622f15f
commit 9cf1f30f0a
5 changed files with 774 additions and 0 deletions

View File

@@ -12,4 +12,5 @@ obj-$(CONFIG_GOLDFISH) += goldfish/
obj-$(CONFIG_CHROME_PLATFORMS) += chrome/
obj-$(CONFIG_CZNIC_PLATFORMS) += cznic/
obj-$(CONFIG_SURFACE_PLATFORMS) += surface/
obj-$(CONFIG_ARCH_TEGRA) += tegra/
obj-$(CONFIG_ARM64_PLATFORM_DEVICES) += arm64/

View File

@@ -0,0 +1,24 @@
# SPDX-License-Identifier: GPL-2.0-only
#
# Tegra Platform Specific Drivers
#
menuconfig TEGRA_PLATFORM_DEVICES
bool "Tegra Platform Specific Device Drivers"
default y
help
Say Y here to get to see options for device drivers of various
Tegra platforms. This option itself does not add any kernel code.
If you say N, all options in this submenu will be skipped and
disabled.
if TEGRA_PLATFORM_DEVICES
config TEGRA_PROD_LEGACY
def_bool y
help
This config helps client driver to identify whether prod
framework is implemented as legacy method or not.
endif # TEGRA_PLATFORM_DEVICES

View File

@@ -0,0 +1,3 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_TEGRA_PROD_LEGACY) += tegra_prod.o

View File

@@ -0,0 +1,620 @@
/*
* Copyright (c) 2014-2017, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/io.h>
#include <linux/tegra_prod.h>
#define PROD_TUPLE_NUM (sizeof(struct prod_tuple)/sizeof(u32))
/* tegra_prod: Tegra Prod list for the given submodule
* @n_prod_cells: Number of prod setting cells.
*/
struct tegra_prod {
struct tegra_prod_config *prod_config;
int num; /* number of tegra_prod*/
int n_prod_cells;
};
struct prod_tuple {
u32 index; /* Address base index */
u32 addr; /* offset address*/
u32 mask; /* mask */
u32 val; /* value */
};
struct tegra_prod_config {
const char *name;
struct prod_tuple *prod_tuple;
int count; /* number of prod_tuple*/
bool boot_init;
};
static int tegra_prod_get_child_tupple_count(struct device *dev,
struct device_node *np,
int n_tupple)
{
struct device_node *child;
int count;
int total_tupple = 0;
count = of_property_count_u32_elems(np, "prod");
if (count > 0) {
if ((count < n_tupple) || (count % n_tupple != 0)) {
dev_err(dev, "Node %s has invalid entries\n", np->name);
return -EINVAL;
}
total_tupple = count / n_tupple;
}
for_each_available_child_of_node(np, child) {
count = tegra_prod_get_child_tupple_count(dev, child, n_tupple);
if (count < 0)
return count;
total_tupple += count;
}
return total_tupple;
}
static int tegra_prod_read_prod_data(struct device *dev,
struct device_node *np,
struct prod_tuple *p_tuple,
int n_tupple)
{
u32 pval;
int count;
int t_count;
int cnt;
int index;
int ret;
count = of_property_count_u32_elems(np, "prod");
if (count <= 0) {
dev_dbg(dev, "Node %s: prod prop not found\n", np->name);
return 0;
}
t_count = count / n_tupple;
for (cnt = 0; cnt < t_count; cnt++, p_tuple++) {
index = cnt * n_tupple;
if (n_tupple == 4) {
ret = of_property_read_u32_index(np, "prod", index,
&pval);
if (ret) {
dev_err(dev, "Failed to parse prod of node %s\n",
np->name);
return -EINVAL;
}
p_tuple->index = pval;
index++;
} else {
p_tuple->index = 0;
}
ret = of_property_read_u32_index(np, "prod", index, &pval);
if (ret) {
dev_err(dev, "Failed to parse address of node %s\n",
np->name);
return -EINVAL;
}
p_tuple->addr = pval;
index++;
ret = of_property_read_u32_index(np, "prod", index, &pval);
if (ret) {
dev_err(dev, "Failed to parse mask of node %s\n",
np->name);
return -EINVAL;
}
p_tuple->mask = pval;
index++;
ret = of_property_read_u32_index(np, "prod", index, &pval);
if (ret) {
dev_err(dev, "Failed to parse value of node %s\n",
np->name);
return -EINVAL;
}
p_tuple->val = pval;
}
return t_count;
}
static int tegra_prod_read_node_tupple(struct device *dev,
struct device_node *np,
struct prod_tuple *p_tuple,
int n_tupple)
{
int ret = 0;
int sindex;
struct device_node *child;
ret = tegra_prod_read_prod_data(dev, np, p_tuple, n_tupple);
if (ret < 0)
return -EINVAL;
sindex = ret;
p_tuple += ret;
for_each_available_child_of_node(np, child) {
ret = tegra_prod_read_node_tupple(dev, child,
p_tuple, n_tupple);
if (ret < 0)
return -EINVAL;
sindex += ret;
p_tuple += ret;
}
return sindex;
}
/* Process the tupples and optimise for the register configuration for
* Same location.
*/
static void tegra_prod_optimise_tupple(struct prod_tuple *p_tuple,
int n_tupple)
{
struct prod_tuple *ti, *tj;
u32 mask;
int i, j;
for (i = 0; i < n_tupple; ++i) {
ti = p_tuple + i;
for (j = i + 1; j < n_tupple; ++j) {
tj = p_tuple + j;
if (ti->index != tj->index)
continue;
if (ti->addr != tj->addr)
continue;
mask = ti->mask & tj->mask;
if (!mask)
continue;
ti->val &= ~mask;
ti->mask &= ~mask;
}
}
}
/**
* tegra_prod_parse_dt - Read the prod setting form Device tree.
* @np: device node from which the property value is to be read.
* @np_prod: Prod setting node.
* @tegra_prod: The list of tegra prods.
*
* Read the prod setting form DT according the prod name in tegra prod list.
* prod tuple will be allocated dynamically according to the tuple number of
* each prod in DT.
*
* Returns 0 on success.
*/
static int tegra_prod_parse_dt(struct device *dev,
const struct device_node *np,
const struct device_node *np_prod,
struct tegra_prod *tegra_prod)
{
struct device_node *child;
struct tegra_prod_config *t_prod;
struct prod_tuple *p_tuple;
int n_child;
int n_tupple = 3;
int ret;
int count;
u32 pval;
bool mask_opt;
if (!tegra_prod || !tegra_prod->prod_config) {
dev_err(dev, "Node %s: Invalid tegra prods list.\n", np->name);
return -EINVAL;
};
mask_opt = of_property_read_bool(np_prod, "enable-mask-optimisation");
ret = of_property_read_u32(np_prod, "#prod-cells", &pval);
if (!ret)
n_tupple = pval;
if ((n_tupple != 3) && (n_tupple != 4)) {
dev_err(dev, "Node %s: Prod cells not supported\n", np->name);
return -EINVAL;
}
tegra_prod->n_prod_cells = n_tupple;
n_child = 0;
for_each_available_child_of_node(np_prod, child) {
t_prod = &tegra_prod->prod_config[n_child];
t_prod->name = child->name;
count = tegra_prod_get_child_tupple_count(dev, child, n_tupple);
if (count < 0) {
dev_err(dev, "Node %s: Child has not proper setting\n",
child->name);
return -EINVAL;
}
if (!count) {
dev_err(dev, "Node %s: prod prop not found\n",
child->name);
return -EINVAL;
}
t_prod->count = count;
t_prod->prod_tuple = devm_kcalloc(dev, t_prod->count,
sizeof(*p_tuple), GFP_KERNEL);
if (!t_prod->prod_tuple)
return -ENOMEM;
t_prod->boot_init = of_property_read_bool(child,
"nvidia,prod-boot-init");
ret = tegra_prod_read_node_tupple(dev, child,
t_prod->prod_tuple, n_tupple);
if (ret < 0) {
dev_err(dev, "Node %s: Reading prod setting failed: %d\n",
child->name, ret);
return ret;
}
if (t_prod->count != ret) {
dev_err(dev, "Node %s: prod read failed: exp %d read %d\n",
child->name, t_prod->count, ret);
return -EINVAL;
}
/* Optimise the prod configuration */
if (mask_opt)
tegra_prod_optimise_tupple(t_prod->prod_tuple,
t_prod->count);
n_child++;
}
tegra_prod->num = n_child;
return 0;
}
/**
* tegra_prod_set_tuple - Only set a tuple.
* @base: base address of the register.
* @prod_tuple: the tuple to set.
* @new_mask: Mask override value, 0 means use from tupple.
*
* Returns 0 on success.
*/
static int tegra_prod_set_tuple(void __iomem **base,
struct prod_tuple *prod_tuple,
u32 new_mask)
{
u32 reg;
u32 mask = (new_mask) ? new_mask : prod_tuple->mask;
if (!prod_tuple)
return -EINVAL;
reg = readl(base[prod_tuple->index] + prod_tuple->addr);
reg = ((reg & ~mask) | (prod_tuple->val & mask));
writel(reg, base[prod_tuple->index] + prod_tuple->addr);
return 0;
}
/**
* tegra_prod_set - Set one prod setting.
* @base: base address of the register.
* @tegra_prod: the prod setting to set.
*
* Set all the tuples in one tegra_prod.
* Returns 0 on success.
*/
static int tegra_prod_set(void __iomem **base,
struct tegra_prod_config *tegra_prod)
{
int i;
int ret;
if (!tegra_prod)
return -EINVAL;
for (i = 0; i < tegra_prod->count; i++) {
ret = tegra_prod_set_tuple(base, &tegra_prod->prod_tuple[i], 0);
if (ret)
return ret;
}
return 0;
}
/**
* tegra_prod_set_list - Set all the prod settings of the list in sequence.
* @base: base address of the register.
* @tegra_prod: the list of tegra prods.
*
* Returns 0 on success.
*/
int tegra_prod_set_list(void __iomem **base,
struct tegra_prod *tegra_prod)
{
int i;
int ret;
if (!tegra_prod)
return -EINVAL;
for (i = 0; i < tegra_prod->num; i++) {
ret = tegra_prod_set(base, &tegra_prod->prod_config[i]);
if (ret)
return ret;
}
return 0;
}
EXPORT_SYMBOL(tegra_prod_set_list);
/**
* tegra_prod_set_boot_init - Set all the prod settings of the list in sequence
* Which are needed for boot initialisation.
* @base: base address of the register.
* @tegra_prod: the list of tegra prods.
*
* Returns 0 on success.
*/
int tegra_prod_set_boot_init(void __iomem **base,
struct tegra_prod *tegra_prod)
{
int i;
int ret;
if (!tegra_prod)
return -EINVAL;
for (i = 0; i < tegra_prod->num; i++) {
if (!tegra_prod->prod_config[i].boot_init)
continue;
ret = tegra_prod_set(base, &tegra_prod->prod_config[i]);
if (ret)
return ret;
}
return 0;
}
EXPORT_SYMBOL(tegra_prod_set_boot_init);
/**
* tegra_prod_set_by_name - Set the prod setting according the name.
* @base: base address of the register.
* @name: the name of tegra prod need to set.
* @tegra_prod: the list of tegra prods.
*
* Find the tegra prod in the list according to the name. Then set
* that tegra prod.
*
* Returns 0 on success.
*/
int tegra_prod_set_by_name(void __iomem **base, const char *name,
struct tegra_prod *tegra_prod)
{
int i;
struct tegra_prod_config *t_prod;
if (!tegra_prod)
return -EINVAL;
for (i = 0; i < tegra_prod->num; i++) {
t_prod = &tegra_prod->prod_config[i];
if (!strcasecmp(t_prod->name, name))
return tegra_prod_set(base, t_prod);
}
return -ENODEV;
}
EXPORT_SYMBOL(tegra_prod_set_by_name);
/**
* tegra_prod_set_by_name_partially - Set the prod setting from list partially
* under given prod name. The matching is done
* qith index, offset and mask.
* @base: base address of the register.
* @name: the name of tegra prod need to set.
* @tegra_prod: the list of tegra prods.
* @index: Index of base address.
* @offset: Offset of the register.
* @mask: Mask field on given register.
*
* Find the tegra prod in the list according to the name. Then set
* that tegra prod which has matching of index, offset and mask.
*
* Returns 0 on success.
*/
int tegra_prod_set_by_name_partially(void __iomem **base, const char *name,
struct tegra_prod *tegra_prod, u32 index,
u32 offset, u32 mask)
{
struct tegra_prod_config *t_prod;
int ret;
int i;
bool found = false;
if (!tegra_prod)
return -EINVAL;
for (i = 0; i < tegra_prod->num; i++) {
t_prod = &tegra_prod->prod_config[i];
if (!strcasecmp(t_prod->name, name)) {
found = true;
break;
}
}
if (!found)
return -ENODEV;
for (i = 0; i < t_prod->count; i++) {
struct prod_tuple *ptuple = &t_prod->prod_tuple[i];;
if ((ptuple->index != index) || (ptuple->addr != offset) ||
((ptuple->mask & mask) != mask))
continue;
ret = tegra_prod_set_tuple(base, ptuple, mask);
if (ret < 0)
return ret;
}
return 0;
}
EXPORT_SYMBOL(tegra_prod_set_by_name_partially);
bool tegra_prod_by_name_supported(struct tegra_prod *tegra_prod,
const char *name)
{
int i;
struct tegra_prod_config *t_prod;
if (!tegra_prod)
return false;
for (i = 0; i < tegra_prod->num; i++) {
t_prod = &tegra_prod->prod_config[i];
if (!t_prod)
break;
if (!strcasecmp(t_prod->name, name))
return true;
}
return false;
}
EXPORT_SYMBOL(tegra_prod_by_name_supported);
/**
* tegra_prod_init - Init tegra prod list.
# @dev: Device handle.
* @np: device node from which the property value is to be read.
*
* Query all the prod settings under DT node & Init the tegra prod list
* automatically.
*
* Returns 0 on success, -EINVAL for wrong prod number, -ENOMEM if failed
* to allocate memory for tegra prod list.
*/
static struct tegra_prod *tegra_prod_init(struct device *dev,
const struct device_node *np)
{
struct tegra_prod *tegra_prod;
struct device_node *np_prod;
int prod_num = 0;
int ret;
np_prod = of_get_child_by_name(np, "prod-settings");
if (!np_prod)
return ERR_PTR(-ENODEV);
/* Check whether child is enabled or not */
if (!of_device_is_available(np_prod)) {
dev_err(dev, "Node %s: Node is not enabled\n", np_prod->name);
return ERR_PTR(-ENODEV);
}
prod_num = of_get_child_count(np_prod);
if (prod_num <= 0) {
dev_err(dev, "Node %s: No child node for prod settings\n",
np_prod->name);
return ERR_PTR(-ENODEV);
}
tegra_prod = devm_kzalloc(dev, sizeof(*tegra_prod), GFP_KERNEL);
if (!tegra_prod)
return ERR_PTR(-ENOMEM);
tegra_prod->prod_config = devm_kcalloc(dev, prod_num,
sizeof(*tegra_prod->prod_config),
GFP_KERNEL);
if (!tegra_prod->prod_config)
return ERR_PTR(-ENOMEM);
tegra_prod->num = prod_num;
ret = tegra_prod_parse_dt(dev, np, np_prod, tegra_prod);
if (ret) {
dev_err(dev, "Node %s: Failed to read the Prod Setting.\n",
np->name);
return ERR_PTR(ret);
}
return tegra_prod;
}
static void devm_tegra_prod_release(struct device *dev, void *res)
{
}
struct tegra_prod *devm_tegra_prod_get(struct device *dev)
{
struct tegra_prod **ptr, *prod_list;
ptr = devres_alloc(devm_tegra_prod_release, sizeof(*ptr), GFP_KERNEL);
if (!ptr)
return ERR_PTR(-ENOMEM);
prod_list = tegra_prod_init(dev, dev->of_node);
if (IS_ERR(prod_list)) {
devres_free(ptr);
return prod_list;
}
*ptr = prod_list;
devres_add(dev, ptr);
return prod_list;
}
EXPORT_SYMBOL(devm_tegra_prod_get);
struct tegra_prod *devm_tegra_prod_get_from_node(struct device *dev,
struct device_node *np)
{
struct tegra_prod **ptr, *prod_list;
ptr = devres_alloc(devm_tegra_prod_release, sizeof(*ptr), GFP_KERNEL);
if (!ptr)
return ERR_PTR(-ENOMEM);
prod_list = tegra_prod_init(dev, np);
if (IS_ERR(prod_list)) {
devres_free(ptr);
return prod_list;
}
*ptr = prod_list;
devres_add(dev, ptr);
return prod_list;
}
EXPORT_SYMBOL(devm_tegra_prod_get_from_node);

126
include/linux/tegra_prod.h Normal file
View File

@@ -0,0 +1,126 @@
/*
* Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _TEGRA_PRODS_H
#define _TEGRA_PRODS_H
struct tegra_prod;
/**
* tegra_prod_set_list(): Set all prods configurations
* @base: List of IO mapped registers.
* @tegra_prod: tegra_prod handle which is allocated by devm_tegra_prod_get()
* or tegra_prod_get_from_node();
*
* Configure all the prod configuration listed on prod-setting nodes.
*
* Returns 0 on success otherwise negive error number for failed case.
*/
int tegra_prod_set_list(void __iomem **base, struct tegra_prod *tegra_prod);
/**
* tegra_prod_set_boot_init(): Set all prods configurations which has boot init
* flag on the prod setting nodes.
* @base: List of IO mapped registers.
* @tegra_prod: tegra_prod handle which is allocated by devm_tegra_prod_get()
* or tegra_prod_get_from_node();
*
* Configure all the prod configuration listed on prod-setting nodes.
*
* Returns 0 on success otherwise negive error number for failed case.
*/
int tegra_prod_set_boot_init(void __iomem **base,
struct tegra_prod *tegra_prod);
/**
* tegra_prod_set_by_name(): Set prod configuration with specific prod name.
* This is used for conditional prod configurations.
* @base: List of IO mapped registers.
* @name: Name of conditional prod which need to be configure.
* @tegra_prod: tegra_prod handle which is allocated by devm_tegra_prod_get()
* or tegra_prod_get_from_node();
*
* Configure prod configuration with specific prod name for conditional
* prod configurations.
*
* Returns 0 on success otherwise negive error number for failed case.
*/
int tegra_prod_set_by_name(void __iomem **base, const char *name,
struct tegra_prod *tegra_prod);
/**
* tegra_prod_set_by_name_partially - Set the prod setting from list partially
* under given prod name. The matching is done
* qith index, offset and mask.
* @base: base address of the register.
* @name: the name of tegra prod need to set.
* @tegra_prod: the list of tegra prods.
* @index: Index of base address.
* @offset: Offset of the register.
* @mask: Mask field on given register.
*
* Find the tegra prod in the list according to the name. Then set
* that tegra prod which has matching of index, offset and mask.
*
* Returns 0 on success.
*/
int tegra_prod_set_by_name_partially(void __iomem **base, const char *name,
struct tegra_prod *tegra_prod, u32 index,
u32 offset, u32 mask);
/**
* tegra_prod_by_name_supported - Tell whether tegra prod will be supported by
* given name or not.
* @tegra_prod: the list of tegra prods.
* @name: the name of tegra prod need to set.
*
* Find the tegra prod in the list according to the name. If it exist then
* return true else false.
*/
bool tegra_prod_by_name_supported(struct tegra_prod *tegra_prod,
const char *name);
/**
* devm_tegra_prod_get(): Get the prod handle from the device.
* @dev: Device handle on which prod setting nodes are available.
*
* Parse the prod-setting node of the dev->of_node and keep all prod
* setting data in prod handle.
* This handle is used for setting prod configurations.
*
* Returns valid prod_list handle on success or pointer to the error
* when it failed.
*/
struct tegra_prod *devm_tegra_prod_get(struct device *dev);
/**
* devm_tegra_prod_get_from_node(): Get the prod handle from the node.
* @dev: Device handle.
* @np: Node pointer on which prod setting nodes are available.
*
* Parse the prod-setting node of the node pointer "np" and keep all prod
* setting data in prod handle.
* This handle is used for setting prod configurations.
*
* Returns valid prod_list handle on success or pointer to the error
* when it failed.
* The allocated resource is released by driver core framework when device
* is unbinded and so no need to call any release APIs for the tegra_prod
* handle.
*/
struct tegra_prod *devm_tegra_prod_get_from_node(struct device *dev,
struct device_node *np);
#endif