Files
linux-nv-oot/drivers/media/platform/tegra/camera/camera_gpio.c
Frank Chen 92ac7bc35a media: camera: Build tegra-camera as OOT module
Port camera drivers below from /kenrel/nvidia to
/kernel/nvidia-oot as OOT modules:
- Fusa-capture driver
- Tegra V4L2 framework driver
- vi/csi driver
- tegra camera platform driver

Change-Id: I390af27096425bb11e0934201dd1a90f001bb3fa
Signed-off-by: Frank Chen <frankc@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/2780698
Reviewed-by: FNU Raunak <fraunak@nvidia.com>
Reviewed-by: Ankur Pawar <ankurp@nvidia.com>
Reviewed-by: Shiva Dubey <sdubey@nvidia.com>
GVS: Gerrit_Virtual_Submit <buildbot_gerritrpt@nvidia.com>
2022-12-13 06:15:42 -08:00

150 lines
3.1 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* virtual.c - Camera GPIO driver
*
* Copyright (c) 2014-2022, NVIDIA CORPORATION. All rights reserved.
*/
#include <linux/list.h>
#include <linux/debugfs.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/gpio.h>
#include "camera_gpio.h"
struct camera_gpio {
struct list_head list;
unsigned gpio_num;
struct mutex mutex;
atomic_t state_cnt;
atomic_t use_cnt;
};
static DEFINE_MUTEX(g_mutex);
static LIST_HEAD(cam_gpio_list);
int cam_gpio_register(struct device *dev,
unsigned pin_num) {
struct camera_gpio *new_gpio;
struct camera_gpio *next_gpio;
mutex_lock(&g_mutex);
list_for_each_entry(next_gpio, &cam_gpio_list, list) {
if (next_gpio->gpio_num == pin_num) {
dev_dbg(dev,
"%s: gpio pin %u already registered.\n",
__func__, pin_num);
atomic_inc(&next_gpio->use_cnt);
mutex_unlock(&g_mutex);
return 0;
}
}
/* gpio is not present in the cam_gpio_list, add it */
new_gpio = kzalloc(sizeof(*new_gpio), GFP_KERNEL);
if (!new_gpio) {
dev_err(dev, "%s: memory low!\n", __func__);
mutex_unlock(&g_mutex);
return -EFAULT;
}
dev_dbg(dev, "%s: adding cam gpio %u\n",
__func__, pin_num);
new_gpio->gpio_num = pin_num;
mutex_init(&new_gpio->mutex);
atomic_inc(&new_gpio->use_cnt);
list_add(&new_gpio->list, &cam_gpio_list);
mutex_unlock(&g_mutex);
return 0;
}
EXPORT_SYMBOL(cam_gpio_register);
void cam_gpio_deregister(struct device *dev,
unsigned pin_num) {
struct camera_gpio *next_gpio;
mutex_lock(&g_mutex);
list_for_each_entry(next_gpio, &cam_gpio_list, list) {
if (next_gpio->gpio_num == pin_num) {
atomic_dec(&next_gpio->use_cnt);
if (atomic_read(&next_gpio->use_cnt) == 0) {
list_del(&next_gpio->list);
kfree(next_gpio);
dev_dbg(dev,
"%s: removing cam gpio %u\n",
__func__, pin_num);
}
break;
}
}
mutex_unlock(&g_mutex);
return;
}
EXPORT_SYMBOL(cam_gpio_deregister);
int cam_gpio_ctrl(struct device *dev,
unsigned pin_num, int val,
bool active_high) /* val: 0=deassert, 1=assert */
{
struct camera_gpio *next_gpio;
int err = -EINVAL;
int pin_val;
bool found = false;
list_for_each_entry(next_gpio, &cam_gpio_list, list) {
mutex_lock(&next_gpio->mutex);
if (next_gpio->gpio_num == pin_num) {
found = true;
if (!atomic_read(&next_gpio->state_cnt) &&
!val) {
dev_err(dev,
"%s: state cnt can't be < 0\n",
__func__);
mutex_unlock(&next_gpio->mutex);
return err;
}
if (val)
atomic_inc(&next_gpio->state_cnt);
else
atomic_dec(&next_gpio->state_cnt);
pin_val = active_high ? val : !val;
pin_val &= 1;
err = pin_val;
/* subtract val allows a 0 check to be
* used to indicate that gpio can be written to*/
if (atomic_read(&next_gpio->state_cnt) - val == 0) {
gpio_set_value_cansleep(pin_num, pin_val);
dev_dbg(dev, "%s %u %d\n",
__func__, pin_num, pin_val);
}
}
mutex_unlock(&next_gpio->mutex);
}
if (!found)
dev_dbg(dev,
"WARNING %s: gpio %u not in list\n",
__func__, pin_num);
return err; /* return value written or error */
}
EXPORT_SYMBOL(cam_gpio_ctrl);