mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-22 17:25:35 +03:00
drivers: tegra: Add Tegra USS io-proxy driver
This commit adds the Tegra USS io-proxy driver which allows userspace to control clock and GPIO signals to the Ultrasonic sensor subsystem found on Tegra platform. Bug 3360749 Change-Id: I0b765e8b9e14b7de87f0f9205237d4dbfdd9f8f5 Signed-off-by: JC Kuo <jckuo@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/2886017 Reviewed-by: Laxman Dewangan <ldewangan@nvidia.com> GVS: Gerrit_Virtual_Submit <buildbot_gerritrpt@nvidia.com>
This commit is contained in:
committed by
mobile promotions
parent
c9858e1282
commit
d7d941e745
@@ -32,3 +32,4 @@ obj-m += dce/
|
|||||||
obj-m += psc/
|
obj-m += psc/
|
||||||
obj-m += rtcpu/
|
obj-m += rtcpu/
|
||||||
obj-m += aon/
|
obj-m += aon/
|
||||||
|
obj-m += tegra-uss-io-proxy.o
|
||||||
|
|||||||
513
drivers/platform/tegra/tegra-uss-io-proxy.c
Normal file
513
drivers/platform/tegra/tegra-uss-io-proxy.c
Normal file
@@ -0,0 +1,513 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* Tegra Ultrasonics Sensor Subsystem IO-Proxy driver
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/compiler.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/of_platform.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/clk.h>
|
||||||
|
#include <linux/reset.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/wait.h>
|
||||||
|
#include <linux/gpio.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/of_gpio.h>
|
||||||
|
|
||||||
|
#define SAFETY_I2S_CTRL_0 (0x114)
|
||||||
|
#define MASTER (1 << 5)
|
||||||
|
|
||||||
|
struct tegra_uss_io_proxy {
|
||||||
|
void __iomem *i2s8_base;
|
||||||
|
struct reset_control *i2s8_reset;
|
||||||
|
struct clk *uss_clk;
|
||||||
|
|
||||||
|
unsigned int hss_version;
|
||||||
|
int uss_reset_gpio;
|
||||||
|
int vsup_dia_gpio;
|
||||||
|
unsigned int vsup_fault_gpio;
|
||||||
|
unsigned int vsup_latch_gpio;
|
||||||
|
struct gpio_descs *g1_gpiods;
|
||||||
|
struct gpio_descs *g2_gpiods;
|
||||||
|
unsigned long g1_bitmap;
|
||||||
|
unsigned long g2_bitmap;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct of_device_id tegra_uss_io_proxy_of_match[] = {
|
||||||
|
{ .compatible = "nvidia,uss-io-proxy", },
|
||||||
|
{ },
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, tegra_uss_io_proxy_of_match);
|
||||||
|
|
||||||
|
static bool uss_clk_enabled;
|
||||||
|
static ssize_t uss_clk_store(struct device *dev, struct device_attribute *attr,
|
||||||
|
const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
struct tegra_uss_io_proxy *proxy = dev_get_drvdata(dev);
|
||||||
|
int val, rc;
|
||||||
|
u32 reg;
|
||||||
|
|
||||||
|
if (kstrtoint(buf, 10, &val))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (val == 0) {
|
||||||
|
rc = reset_control_assert(proxy->i2s8_reset);
|
||||||
|
if (rc) {
|
||||||
|
dev_err(dev, "i2s8 reset assert failed: %d\n", rc);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
clk_disable_unprepare(proxy->uss_clk);
|
||||||
|
uss_clk_enabled = false;
|
||||||
|
} else {
|
||||||
|
rc = clk_prepare_enable(proxy->uss_clk);
|
||||||
|
if (rc) {
|
||||||
|
dev_err(dev, "i2s8 clock enable failed: %d\n", rc);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = reset_control_deassert(proxy->i2s8_reset);
|
||||||
|
if (rc) {
|
||||||
|
dev_err(dev, "i2s8 reset deassert failed: %d\n", rc);
|
||||||
|
clk_disable_unprepare(proxy->uss_clk);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
reg = ioread32(proxy->i2s8_base + SAFETY_I2S_CTRL_0);
|
||||||
|
reg |= MASTER;
|
||||||
|
iowrite32(reg, proxy->i2s8_base + SAFETY_I2S_CTRL_0);
|
||||||
|
|
||||||
|
uss_clk_enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t uss_clk_show(struct device *dev, struct device_attribute *attr,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
if (uss_clk_enabled)
|
||||||
|
return sprintf(buf, "1\n");
|
||||||
|
else
|
||||||
|
return sprintf(buf, "0\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static DEVICE_ATTR_RW(uss_clk);
|
||||||
|
|
||||||
|
static ssize_t uss_reset_store(struct device *dev,
|
||||||
|
struct device_attribute *attr,
|
||||||
|
const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
struct tegra_uss_io_proxy *proxy = dev_get_drvdata(dev);
|
||||||
|
int val;
|
||||||
|
|
||||||
|
if (kstrtoint(buf, 10, &val))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (val == 0)
|
||||||
|
gpio_set_value(proxy->uss_reset_gpio, 1);
|
||||||
|
else
|
||||||
|
gpio_set_value(proxy->uss_reset_gpio, 0);
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t uss_reset_show(struct device *dev, struct device_attribute *attr,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
struct tegra_uss_io_proxy *proxy = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
return sprintf(buf, "%d\n", !gpio_get_value(proxy->uss_reset_gpio));
|
||||||
|
}
|
||||||
|
|
||||||
|
static DEVICE_ATTR_RW(uss_reset);
|
||||||
|
|
||||||
|
static ssize_t vsup_dia_store(struct device *dev, struct device_attribute *attr,
|
||||||
|
const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
struct tegra_uss_io_proxy *proxy = dev_get_drvdata(dev);
|
||||||
|
int val;
|
||||||
|
|
||||||
|
if (kstrtoint(buf, 10, &val))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (val == 0)
|
||||||
|
gpio_set_value(proxy->vsup_dia_gpio, 0);
|
||||||
|
else
|
||||||
|
gpio_set_value(proxy->vsup_dia_gpio, 1);
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t vsup_dia_show(struct device *dev, struct device_attribute *attr,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
struct tegra_uss_io_proxy *proxy = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
return sprintf(buf, "%d\n", gpio_get_value(proxy->vsup_dia_gpio));
|
||||||
|
}
|
||||||
|
|
||||||
|
static DEVICE_ATTR_RW(vsup_dia);
|
||||||
|
|
||||||
|
static ssize_t vsup_latch_store(struct device *dev,
|
||||||
|
struct device_attribute *attr,
|
||||||
|
const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
struct tegra_uss_io_proxy *proxy = dev_get_drvdata(dev);
|
||||||
|
int val;
|
||||||
|
|
||||||
|
if (kstrtoint(buf, 10, &val))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (val == 0)
|
||||||
|
gpio_set_value(proxy->vsup_latch_gpio, 0);
|
||||||
|
else
|
||||||
|
gpio_set_value(proxy->vsup_latch_gpio, 1);
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t vsup_latch_show(struct device *dev,
|
||||||
|
struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
struct tegra_uss_io_proxy *proxy = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
return sprintf(buf, "%d\n", gpio_get_value(proxy->vsup_latch_gpio));
|
||||||
|
}
|
||||||
|
|
||||||
|
static DEVICE_ATTR_RW(vsup_latch);
|
||||||
|
|
||||||
|
static ssize_t vsup_fault_show(struct device *dev,
|
||||||
|
struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
struct tegra_uss_io_proxy *proxy = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
return sprintf(buf, "%d\n", gpio_get_value(proxy->vsup_fault_gpio));
|
||||||
|
}
|
||||||
|
|
||||||
|
static DEVICE_ATTR_ADMIN_RO(vsup_fault);
|
||||||
|
|
||||||
|
static ssize_t sensor_gpios_store(struct device *dev,
|
||||||
|
struct device_attribute *attr,
|
||||||
|
const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
struct tegra_uss_io_proxy *proxy = dev_get_drvdata(dev);
|
||||||
|
unsigned long bitmap;
|
||||||
|
int rc;
|
||||||
|
u32 val;
|
||||||
|
u8 *b = (u8 *)&val;
|
||||||
|
|
||||||
|
if (kstrtou32(buf, 16, &val))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (b[2] != 0) {
|
||||||
|
bitmap = proxy->g1_bitmap & (~b[2]);
|
||||||
|
bitmap |= (b[0] & b[2]);
|
||||||
|
rc = gpiod_set_array_value_cansleep(proxy->g1_gpiods->ndescs,
|
||||||
|
proxy->g1_gpiods->desc,
|
||||||
|
proxy->g1_gpiods->info,
|
||||||
|
&bitmap);
|
||||||
|
if (rc) {
|
||||||
|
dev_err(dev, "set group-1 GPIOs failed %d\n", rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
proxy->g1_bitmap = bitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (b[3] != 0) {
|
||||||
|
bitmap = proxy->g2_bitmap & (~b[3]);
|
||||||
|
bitmap |= (b[1] & b[3]);
|
||||||
|
rc = gpiod_set_array_value_cansleep(proxy->g2_gpiods->ndescs,
|
||||||
|
proxy->g2_gpiods->desc,
|
||||||
|
proxy->g2_gpiods->info,
|
||||||
|
&bitmap);
|
||||||
|
if (rc) {
|
||||||
|
dev_err(dev, "set group-2 GPIOs failed %d\n", rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
proxy->g2_bitmap = bitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t sensor_gpios_show(struct device *dev,
|
||||||
|
struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
struct tegra_uss_io_proxy *proxy = dev_get_drvdata(dev);
|
||||||
|
size_t n = PAGE_SIZE;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
n -= snprintf(&buf[PAGE_SIZE - n], n, "Sensor Group 1\n");
|
||||||
|
for (i = 0; i < 6; i++) {
|
||||||
|
n -= snprintf(&buf[PAGE_SIZE - n], n, "\tSensor %d: %d\n",
|
||||||
|
i + 1, !!(proxy->g1_bitmap & (1 << i)));
|
||||||
|
}
|
||||||
|
n -= snprintf(&buf[PAGE_SIZE - n], n, "\tVSUP_EN1: %d\n",
|
||||||
|
!!(proxy->g1_bitmap & (1 << 6)));
|
||||||
|
n -= snprintf(&buf[PAGE_SIZE - n], n, "\tVSUP_SEL1: %d\n",
|
||||||
|
!!(proxy->g1_bitmap & (1 << 7)));
|
||||||
|
|
||||||
|
n -= snprintf(&buf[PAGE_SIZE - n], n, "Sensor Group 2\n");
|
||||||
|
for (i = 0; i < 6; i++) {
|
||||||
|
n -= snprintf(&buf[PAGE_SIZE - n], n, "\tSensor %d: %d\n",
|
||||||
|
i + 1, !!(proxy->g2_bitmap & (1 << i)));
|
||||||
|
}
|
||||||
|
n -= snprintf(&buf[PAGE_SIZE - n], n, "\tVSUP_EN2: %d\n",
|
||||||
|
!!(proxy->g2_bitmap & (1 << 6)));
|
||||||
|
if (proxy->hss_version == 1) {
|
||||||
|
n -= snprintf(&buf[PAGE_SIZE - n], n, "\tVSUP_SEL2: %d\n",
|
||||||
|
!!(proxy->g2_bitmap & (1 << 7)));
|
||||||
|
}
|
||||||
|
if (proxy->hss_version == 2) {
|
||||||
|
n -= snprintf(&buf[PAGE_SIZE - n], n, "\tVSUP_LATCH: %d\n",
|
||||||
|
!!(proxy->g2_bitmap & (1 << 7)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return PAGE_SIZE - n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static DEVICE_ATTR_RW(sensor_gpios);
|
||||||
|
|
||||||
|
static int tegra_uss_create_dev_attrs(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct tegra_uss_io_proxy *proxy = platform_get_drvdata(pdev);
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = device_create_file(&pdev->dev, &dev_attr_uss_clk);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
err = device_create_file(&pdev->dev, &dev_attr_uss_reset);
|
||||||
|
if (err)
|
||||||
|
goto err_reset;
|
||||||
|
|
||||||
|
err = device_create_file(&pdev->dev, &dev_attr_vsup_dia);
|
||||||
|
if (err)
|
||||||
|
goto err_vsup_dia;
|
||||||
|
|
||||||
|
if (proxy->hss_version == 1)
|
||||||
|
err = device_create_file(&pdev->dev, &dev_attr_vsup_latch);
|
||||||
|
|
||||||
|
if (proxy->hss_version == 2)
|
||||||
|
err = device_create_file(&pdev->dev, &dev_attr_vsup_fault);
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
goto err_vsup_latch_fault;
|
||||||
|
|
||||||
|
err = device_create_file(&pdev->dev, &dev_attr_sensor_gpios);
|
||||||
|
if (err)
|
||||||
|
goto err_sensor_gpios;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
|
||||||
|
err_sensor_gpios:
|
||||||
|
if (proxy->hss_version == 1)
|
||||||
|
device_remove_file(&pdev->dev, &dev_attr_vsup_latch);
|
||||||
|
if (proxy->hss_version == 2)
|
||||||
|
device_remove_file(&pdev->dev, &dev_attr_vsup_fault);
|
||||||
|
err_vsup_latch_fault:
|
||||||
|
device_remove_file(&pdev->dev, &dev_attr_vsup_dia);
|
||||||
|
err_vsup_dia:
|
||||||
|
device_remove_file(&pdev->dev, &dev_attr_uss_reset);
|
||||||
|
err_reset:
|
||||||
|
device_remove_file(&pdev->dev, &dev_attr_uss_clk);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tegra_uss_remove_dev_attrs(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct tegra_uss_io_proxy *proxy = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
|
device_remove_file(&pdev->dev, &dev_attr_uss_clk);
|
||||||
|
device_remove_file(&pdev->dev, &dev_attr_uss_reset);
|
||||||
|
device_remove_file(&pdev->dev, &dev_attr_vsup_dia);
|
||||||
|
if (proxy->hss_version == 1)
|
||||||
|
device_remove_file(&pdev->dev, &dev_attr_vsup_latch);
|
||||||
|
if (proxy->hss_version == 2)
|
||||||
|
device_remove_file(&pdev->dev, &dev_attr_vsup_fault);
|
||||||
|
device_remove_file(&pdev->dev, &dev_attr_sensor_gpios);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tegra_uss_request_gpio(struct platform_device *pdev, const char *name)
|
||||||
|
{
|
||||||
|
struct device_node *np = pdev->dev.of_node;
|
||||||
|
int gpio, rc;
|
||||||
|
|
||||||
|
gpio = of_get_named_gpio(np, name, 0);
|
||||||
|
if (gpio == -EPROBE_DEFER)
|
||||||
|
return gpio;
|
||||||
|
|
||||||
|
if (!gpio_is_valid(gpio)) {
|
||||||
|
dev_err(&pdev->dev, "%s is invalid\n", name);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = devm_gpio_request(&pdev->dev, gpio, name);
|
||||||
|
if (rc) {
|
||||||
|
dev_err(&pdev->dev, "could not request %s %d\n", name, rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = gpio_direction_output(gpio, 0);
|
||||||
|
if (rc) {
|
||||||
|
dev_err(&pdev->dev, "could not set %s output %d\n", name, rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return gpio;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tegra_uss_io_proxy_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct device_node *node = pdev->dev.of_node;
|
||||||
|
struct tegra_uss_io_proxy *proxy;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
proxy = devm_kzalloc(&pdev->dev, sizeof(*proxy), GFP_KERNEL);
|
||||||
|
if (unlikely(proxy == NULL))
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
proxy->i2s8_base = devm_platform_ioremap_resource(pdev, 0);
|
||||||
|
if (IS_ERR(proxy->i2s8_base)) {
|
||||||
|
return dev_err_probe(&pdev->dev, PTR_ERR(proxy->i2s8_base),
|
||||||
|
"failed to get I2S8 mmio\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
proxy->uss_clk = devm_clk_get(&pdev->dev, "i2s8");
|
||||||
|
if (IS_ERR(proxy->uss_clk)) {
|
||||||
|
return dev_err_probe(&pdev->dev, PTR_ERR(proxy->uss_clk),
|
||||||
|
"failed to get I2S8 clock\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
proxy->i2s8_reset = devm_reset_control_get(&pdev->dev, "i2s8");
|
||||||
|
if (IS_ERR(proxy->i2s8_reset)) {
|
||||||
|
return dev_err_probe(&pdev->dev, PTR_ERR(proxy->i2s8_reset),
|
||||||
|
"failed to get I2S8 reset\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = of_property_read_u32(node, "uss-hss-version", &proxy->hss_version);
|
||||||
|
if (rc != 0) {
|
||||||
|
/* backward compatibility */
|
||||||
|
dev_info(&pdev->dev, "uss-hss-version property doesn't exist, version=1\n");
|
||||||
|
proxy->hss_version = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proxy->hss_version > 2) {
|
||||||
|
return dev_err_probe(&pdev->dev, -EINVAL,
|
||||||
|
"uss_hss_version is not valid.");
|
||||||
|
}
|
||||||
|
|
||||||
|
proxy->uss_reset_gpio = tegra_uss_request_gpio(pdev, "uss-nres");
|
||||||
|
if (proxy->uss_reset_gpio < 0) {
|
||||||
|
return dev_err_probe(&pdev->dev, proxy->uss_reset_gpio,
|
||||||
|
"failed to get uss-nres GPIO\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
proxy->vsup_dia_gpio = tegra_uss_request_gpio(pdev, "uss-vsup-dia");
|
||||||
|
if (proxy->vsup_dia_gpio < 0) {
|
||||||
|
return dev_err_probe(&pdev->dev, proxy->vsup_dia_gpio,
|
||||||
|
"failed to get vsup-dia GPIO\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proxy->hss_version == 1) {
|
||||||
|
rc = tegra_uss_request_gpio(pdev, "uss-vsup-latch");
|
||||||
|
if (rc < 0)
|
||||||
|
return dev_err_probe(&pdev->dev, rc, "failed to get vsup-latch GPIO\n");
|
||||||
|
|
||||||
|
proxy->vsup_fault_gpio = rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proxy->hss_version == 2) {
|
||||||
|
rc = tegra_uss_request_gpio(pdev, "uss-vsup-fault");
|
||||||
|
if (rc < 0)
|
||||||
|
return dev_err_probe(&pdev->dev, rc, "failed to get vsup-fault GPIO\n");
|
||||||
|
|
||||||
|
proxy->vsup_fault_gpio = rc;
|
||||||
|
gpio_direction_input(proxy->vsup_fault_gpio);
|
||||||
|
}
|
||||||
|
|
||||||
|
proxy->g1_gpiods = devm_gpiod_get_array(&pdev->dev, "sensor-group-1",
|
||||||
|
GPIOD_OUT_LOW);
|
||||||
|
if (IS_ERR(proxy->g1_gpiods)) {
|
||||||
|
return dev_err_probe(&pdev->dev, PTR_ERR(proxy->g1_gpiods),
|
||||||
|
"failed to get sensor-group-1 GPIOs\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
proxy->g2_gpiods = devm_gpiod_get_array(&pdev->dev, "sensor-group-2",
|
||||||
|
GPIOD_OUT_LOW);
|
||||||
|
if (IS_ERR(proxy->g2_gpiods)) {
|
||||||
|
return dev_err_probe(&pdev->dev, PTR_ERR(proxy->g2_gpiods),
|
||||||
|
"failed to get sensor-group-2 GPIOs\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
platform_set_drvdata(pdev, proxy);
|
||||||
|
tegra_uss_create_dev_attrs(pdev);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tegra_uss_reset(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct tegra_uss_io_proxy *proxy = platform_get_drvdata(pdev);
|
||||||
|
unsigned long bitmap = 0;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
gpio_set_value(proxy->uss_reset_gpio, 0);
|
||||||
|
|
||||||
|
rc = reset_control_assert(proxy->i2s8_reset);
|
||||||
|
if (rc)
|
||||||
|
dev_err(&pdev->dev, "i2s8 reset assert failed: %d\n", rc);
|
||||||
|
|
||||||
|
clk_disable_unprepare(proxy->uss_clk);
|
||||||
|
|
||||||
|
rc = gpiod_set_array_value_cansleep(proxy->g1_gpiods->ndescs,
|
||||||
|
proxy->g1_gpiods->desc,
|
||||||
|
proxy->g1_gpiods->info,
|
||||||
|
&bitmap);
|
||||||
|
if (rc)
|
||||||
|
dev_err(&pdev->dev, "set group-1 GPIOs failed %d\n", rc);
|
||||||
|
|
||||||
|
proxy->g1_bitmap = 0;
|
||||||
|
|
||||||
|
rc = gpiod_set_array_value_cansleep(proxy->g2_gpiods->ndescs,
|
||||||
|
proxy->g2_gpiods->desc,
|
||||||
|
proxy->g2_gpiods->info,
|
||||||
|
&bitmap);
|
||||||
|
if (rc)
|
||||||
|
dev_err(&pdev->dev, "set group-2 GPIOs failed %d\n", rc);
|
||||||
|
|
||||||
|
proxy->g1_bitmap = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tegra_uss_io_proxy_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
tegra_uss_remove_dev_attrs(pdev);
|
||||||
|
tegra_uss_reset(pdev);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct platform_driver tegra_uss_io_proxy_driver = {
|
||||||
|
.probe = tegra_uss_io_proxy_probe,
|
||||||
|
.remove = tegra_uss_io_proxy_remove,
|
||||||
|
.driver = {
|
||||||
|
.name = "tegra-uss-io-proxy",
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.of_match_table = of_match_ptr(tegra_uss_io_proxy_of_match),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
module_platform_driver(tegra_uss_io_proxy_driver);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("JC Kuo <jckuo@nvidia.com>");
|
||||||
|
MODULE_DESCRIPTION("NVIDIA Tegra USS IO-PROXY driver");
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
Reference in New Issue
Block a user