Compare commits

...

5 Commits

Author SHA1 Message Date
Mohan Kumar
4212fbd97f ASoC: tegra: avoid enabling aud_mclk during init
Enabling the aud_mclk clock during initialization of drivers
was done for T30 chip due to some external dependencies, now
it is not required for latest version of chips and also due
to this aud_mclk is kept always ON. Add check to avoid enabling
aud_mclk clock other than T30

Bug 4373898

Change-Id: If341b1b73051c5572c5551bf6d4659fab7a116d2
Signed-off-by: Mohan Kumar <mkumard@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3015891
(cherry picked from commit 7ffd0c9cfa)
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3019203
Reviewed-by: Amulya Yarlagadda <ayarlagadda@nvidia.com>
GVS: Gerrit_Virtual_Submit <buildbot_gerritrpt@nvidia.com>
2023-11-22 13:02:29 -08:00
Praveen AC
4e63d195c6 drivers:media: Fix imx390 & imx185 probe issue.
Due to "mingain - 1" & "minexp - 1" during probe time observing
out of range whenever gain or exp is set "0" as min in DT.
Instead doing "maxgain + 1" & "maxexp + 1" to fix the probe.

Bug 4142996
Bug 4189361
Bug 4386912

Change-Id: I103e87b293079dadcd16b91f8e329ec9f938208c
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3020349
Tested-by: Praveen AC <pac@nvidia.com>
Reviewed-by: Praveen AC <pac@nvidia.com>
Reviewed-by: Narendra Kondapalli <nkondapalli@nvidia.com>
Reviewed-by: Ankur Pawar <ankurp@nvidia.com>
Reviewed-by: Anubhav Rai <arai@nvidia.com>
Reviewed-by: Amulya Yarlagadda <ayarlagadda@nvidia.com>
GVS: Gerrit_Virtual_Submit <buildbot_gerritrpt@nvidia.com>
2023-11-22 10:18:55 -08:00
Yi-Wei Wang
4ad0e0c6c8 thermal: add thermal trip event cooling device
This change adds a cooling device driver to notify the user space of the
thermal trip event. To avoid having user space process poll the
cooling state, a sysfs node is exposed that supports blocking reads.
The driver also supports a timeout (in milliseconds) for blocking reads
which can be done by writing the value to thermal_trip_event_block node
before reading. The blocked user space process will be woken up when the
cooling device becomes active or times out.

Bug 4261645
Bug 1688327

Signed-off-by: Yi-Wei Wang <yiweiw@nvidia.com>
Change-Id: Ic89406ba2713e5bc8f3806d6cfeb462601c73a7d
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3015652
(cherry picked from commit 856471d64f)
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3019213
Reviewed-by: Laxman Dewangan <ldewangan@nvidia.com>
GVS: Gerrit_Virtual_Submit <buildbot_gerritrpt@nvidia.com>
2023-11-21 12:24:53 -08:00
Anubhav Rai
969619a872 camera: lt6911uxc update with Shadow EDID
Update the Lontium driver to flash shadow EDID
to lt6911uxc chip. This will ensure that the requested
resolution through the application is flashed to the
chip and the source is forced to select the
requested resolution only.

bug 4266018
bug 4301203
bug 4168489
Signed-off-by: Anubhav Rai <arai@nvidia.com>

Change-Id: I945a9658b52c82956535f3710312d317c0098be7
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3007702
(cherry picked from commit c3ddb23392)
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3016371
Tested-by: Anubhav Rai <arai@nvidia.com>
Reviewed-by: Anubhav Rai <arai@nvidia.com>
Reviewed-by: Amulya Yarlagadda <ayarlagadda@nvidia.com>
2023-11-16 21:15:37 -08:00
Gautham Srinivasan
ad7508c52a drivers: aon: Add AON Echo driver
Add AON echo driver. This driver creates data_channel file in sysfs
which is used to communicate between CCPLEX and AON.

Bug 4296173

Change-Id: Id790fc4076205e16509611f7fa07ffc073491227
Signed-off-by: Gautham Srinivasan <gauthams@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/2954202
(cherry picked from commit 66c26d1ac3)
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3015993
Reviewed-by: Amulya Yarlagadda <ayarlagadda@nvidia.com>
Tested-by: Amulya Yarlagadda <ayarlagadda@nvidia.com>
2023-11-14 20:48:17 -08:00
7 changed files with 648 additions and 38 deletions

View File

@@ -19,6 +19,134 @@
#include "../platform/tegra/camera/camera_gpio.h"
#define lt6911uxc_reg struct reg_8
#define LT6911_TABLE_WAIT_MS 0
#define LT6911_TABLE_END 1
static lt6911uxc_reg lt_enable_i2c[] = {
{0xff, 0x80},
{0xee, 0x01},
{0x10, 0x00},
{LT6911_TABLE_END, 0x00}
};
static lt6911uxc_reg lt_configure_param[] = {
{0x5e, 0xdf},
{0x58, 0x00},
{0x59, 0x50},
{0x5a, 0x10},
{LT6911_TABLE_WAIT_MS, 1},
{0x5a, 0x00},
{0x58, 0x21},
{LT6911_TABLE_END, 0x00}
};
static lt6911uxc_reg lt_block_erase[] = {
{0x5a, 0x04},
{LT6911_TABLE_WAIT_MS, 1},
{0x5a, 0x00},
{0x5b, 0x01},
{0x5c, 0x80},
{0x5d, 0x00},
{0x5a, 0x01},
{LT6911_TABLE_WAIT_MS, 1},
{0x5a, 0x00},
{LT6911_TABLE_END, 0x00}
};
static lt6911uxc_reg lt_fifo_rst[] = {
{0xff, 0x81},
{0x08, 0xbf},
{LT6911_TABLE_WAIT_MS, 1},
{0x08, 0xff},
{LT6911_TABLE_END, 0x00}
};
static lt6911uxc_reg lt_write_enable[] = {
{0xff, 0x80},
{0x5a, 0x04},
{LT6911_TABLE_WAIT_MS, 1},
{0x5a, 0x00},
{LT6911_TABLE_END, 0x00}
};
static lt6911uxc_reg lt_data_to_fifo[] = {
{0x5e, 0xdf},
{0x5a, 0x20},
{LT6911_TABLE_WAIT_MS, 1},
{0x5a, 0x00},
{LT6911_TABLE_END, 0x00}
};
static lt6911uxc_reg lt_write_disable[] = {
{0xff, 0x80},
{0x5a, 0x08},
{LT6911_TABLE_WAIT_MS, 1},
{0x5a, 0x00},
{0x58, 0x00},
{LT6911_TABLE_END, 0x00}
};
static u8 LT6911_EDIDs[][256] = {
// EDID with default 1920x1080 60fps
{
0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x3A,0xC4,0x04,0xED,0x01,0x01,0x01,0x01,
0x1E,0x21,0x01,0x03,0x80,0x6F,0x3E,0x78,0x0A,0xEE,0x91,0xA3,0x54,0x4C,0x99,0x26,
0x0F,0x50,0x54,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
0x01,0x01,0x01,0x01,0x01,0x01,0x02,0x3A,0x80,0x18,0x71,0x38,0x2D,0x40,0x58,0x2C,
0x45,0x00,0xBA,0x88,0x21,0x00,0x00,0x1E,0x02,0x3A,0x80,0x18,0x71,0x38,0x2D,0x40,
0x58,0x2C,0x45,0x00,0xBA,0x88,0x21,0x00,0x00,0x1E,0x00,0x00,0x00,0xFD,0x00,0x18,
0x4B,0x0F,0x87,0x22,0x00,0x0A,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x00,0x00,0xFC,
0x00,0x44,0x75,0x61,0x6C,0x20,0x50,0x6F,0x72,0x74,0x20,0x52,0x47,0x42,0x01,0x50,
0x02,0x03,0x18,0x71,0x43,0x04,0x01,0x03,0x23,0x09,0x07,0x01,0x83,0x01,0x00,0x00,
0x67,0x03,0x0C,0x00,0x10,0x00,0x00,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xAD
},
// EDID with default 3840x2160 60fps
{
0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x3A,0xC4,0x01,0xED,0x01,0x01,0x01,0x01,
0x1E,0x21,0x01,0x03,0x80,0x6F,0x3E,0x78,0x0A,0xEE,0x91,0xA3,0x54,0x4C,0x99,0x26,
0x0F,0x50,0x54,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
0x01,0x01,0x01,0x01,0x01,0x01,0x08,0xE8,0x00,0x30,0xF2,0x70,0x5A,0x80,0xB0,0x58,
0x8A,0x00,0x50,0x1D,0x74,0x00,0x00,0x1E,0x08,0xE8,0x00,0x30,0xF2,0x70,0x5A,0x80,
0xB0,0x58,0x8A,0x00,0x50,0x1D,0x74,0x00,0x00,0x1E,0x00,0x00,0x00,0xFD,0x00,0x18,
0x4B,0x0F,0x87,0x3C,0x00,0x0A,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x00,0x00,0xFC,
0x00,0x44,0x75,0x61,0x6C,0x20,0x50,0x6F,0x72,0x74,0x20,0x52,0x47,0x42,0x01,0xC7,
0x02,0x03,0x20,0x71,0x43,0x61,0x01,0x03,0x23,0x09,0x07,0x01,0x83,0x01,0x00,0x00,
0x67,0x03,0x0C,0x00,0x10,0x00,0x00,0x3C,0x67,0xD8,0x5D,0xC4,0x01,0x78,0x80,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xEF
},
// EDID with default 1280x720 60fps
{
0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x3A,0xC4,0x05,0xED,0x01,0x01,0x01,0x01,
0x1E,0x21,0x01,0x03,0x80,0x6F,0x3E,0x78,0x0A,0xEE,0x91,0xA3,0x54,0x4C,0x99,0x26,
0x0F,0x50,0x54,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x1D,0x00,0x72,0x51,0xD0,0x1E,0x20,0x6E,0x28,
0x55,0x00,0xC4,0x8E,0x21,0x00,0x00,0x1E,0x01,0x1D,0x00,0x72,0x51,0xD0,0x1E,0x20,
0x6E,0x28,0x55,0x00,0xC4,0x8E,0x21,0x00,0x00,0x1E,0x00,0x00,0x00,0xFD,0x00,0x18,
0x4B,0x0F,0x87,0x22,0x00,0x0A,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x00,0x00,0xFC,
0x00,0x44,0x75,0x61,0x6C,0x20,0x50,0x6F,0x72,0x74,0x20,0x52,0x47,0x42,0x01,0xE1,
0x02,0x03,0x18,0x71,0x43,0x04,0x01,0x03,0x23,0x09,0x07,0x01,0x83,0x01,0x00,0x00,
0x67,0x03,0x0C,0x00,0x10,0x00,0x00,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xAD
}
};
static const struct of_device_id lt6911uxc_of_match[] = {
{ .compatible = "nvidia,lt6911uxc", },
{ },
@@ -37,13 +165,18 @@ static const int lt6911uxc_30fps[] = {
30,
};
static const u8 lt6911uxc_HDMI_Signal = 0xa3;
static const u8 lt6911uxc_FW_version[] = { 0xa7, 0xa8, 0xa9, 0xaa };
struct lt6911uxc {
struct i2c_client *i2c_client;
struct v4l2_subdev *subdev;
u16 fine_integ_time;
u32 frame_length;
u16 fine_integ_time;
u32 frame_length;
struct camera_common_data *s_data;
struct tegracam_device *tc_dev;
struct regmap *regmap;
};
static const struct camera_common_frmfmt lt6911uxc_frmfmt[] = {
@@ -53,11 +186,50 @@ static const struct camera_common_frmfmt lt6911uxc_frmfmt[] = {
};
static const struct regmap_config sensor_regmap_config = {
.reg_bits = 16,
.reg_bits = 8,
.val_bits = 8,
.cache_type = REGCACHE_RBTREE,
};
static inline int lt6911uxc_read_reg(struct camera_common_data *s_data,
u16 addr, u8 *val)
{
int err = 0;
u32 reg_val = 0;
err = regmap_read(s_data->regmap, addr, &reg_val);
if (err) {
dev_err(s_data->dev, "%s: i2c read , 0x%x = %x",
__func__, addr, reg_val);
return err;
}
*val = reg_val & 0xff;
return err;
}
static inline int lt6911uxc_write_reg(struct camera_common_data *s_data,
u16 addr, u8 val)
{
int err = 0;
err = regmap_write(s_data->regmap, addr, val);
if (err)
dev_err(s_data->dev, "%s: i2c write failed, 0x%x = %x",
__func__, addr, val);
return err;
}
static int lt6911uxc_write_table(struct lt6911uxc *priv,
const lt6911uxc_reg table[])
{
return regmap_util_write_table_8(priv->s_data->regmap,
table,
NULL, 0,
LT6911_TABLE_WAIT_MS,
LT6911_TABLE_END);
}
static int lt6911uxc_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -84,6 +256,8 @@ static int lt6911uxc_start_streaming(struct tegracam_device *tc_dev)
else
gpio_set_value(pw->reset_gpio, 1);
}
msleep(300);
return 0;
}
@@ -101,29 +275,7 @@ static int lt6911uxc_stop_streaming(struct tegracam_device *tc_dev)
return 0;
}
static int lt6911uxc_set_mode(struct tegracam_device *tc_dev)
{
/* Width and Height taken care of by the firmware */
return 0;
}
static inline int lt6911uxc_read_reg(struct camera_common_data *s_data,
u16 addr, u8 *val)
{
int err = 0;
u32 reg_val = 0;
err = regmap_read(s_data->regmap, addr, &reg_val);
*val = reg_val & 0xff;
return err;
}
static inline int lt6911uxc_write_reg(struct camera_common_data *s_data,
u16 addr, u8 val)
{
return 0;
}
static int lt6911uxc_power_get(struct tegracam_device *tc_dev)
{
@@ -309,9 +461,9 @@ static int lt6911uxc_power_on(struct camera_common_data *s_data)
if (pw->reset_gpio) {
if (gpiod_cansleep(gpio_to_desc(pw->reset_gpio)))
gpio_set_value_cansleep(pw->reset_gpio, 0);
gpio_set_value_cansleep(pw->reset_gpio, 1);
else
gpio_set_value(pw->reset_gpio, 0);
gpio_set_value(pw->reset_gpio, 1);
}
usleep_range(10, 20);
@@ -335,7 +487,7 @@ static int lt6911uxc_power_on(struct camera_common_data *s_data)
goto lt6911uxc_dvdd_fail;
}
usleep_range(10, 20);
msleep(300);
pw->state = SWITCH_ON;
@@ -389,11 +541,64 @@ static int lt6911uxc_power_off(struct camera_common_data *s_data)
return 0;
}
static int lt6911uxc_set_mode(struct tegracam_device *tc_dev)
{
int err = 0;
int i, j;
struct camera_common_data *s_data = tc_dev->s_data;
struct lt6911uxc *priv = (struct lt6911uxc *)s_data->priv;
struct camera_common_power_rail *pw = s_data->power;
// Write the corresponding Shadow EDID
err |= lt6911uxc_write_table(priv, lt_enable_i2c);
err |= lt6911uxc_write_table(priv, lt_configure_param);
err |= lt6911uxc_write_table(priv, lt_block_erase);
msleep(600);
for (i = 0; i < 8; i++)
{
err |= lt6911uxc_write_table(priv, lt_fifo_rst);
err |= lt6911uxc_write_table(priv, lt_write_enable);
err |= lt6911uxc_write_table(priv, lt_data_to_fifo);
for(j = 0; j < 32; j++)
{
lt6911uxc_write_reg(priv->s_data, 0x59,
LT6911_EDIDs[s_data->mode][(i * 32) + j]);
}
err |= lt6911uxc_write_reg(priv->s_data, 0x5b, 0x01);
err |= lt6911uxc_write_reg(priv->s_data, 0x5c, 0x80);
err |= lt6911uxc_write_reg(priv->s_data, 0x5d, (i) * 32);
err |= lt6911uxc_write_reg(priv->s_data, 0x5a, 0x10);
msleep(1);
err |= lt6911uxc_write_reg(priv->s_data, 0x5a, 0x00);
msleep(1);
}
err |= lt6911uxc_write_table(priv, lt_write_disable);
if (err)
dev_err(tc_dev->dev, "%s Error in writing shadow EDID \n", __func__);
// Toggle the reset pin to low, stream on will again set it to high
if (pw->reset_gpio) {
if (gpiod_cansleep(gpio_to_desc(pw->reset_gpio)))
gpio_set_value_cansleep(pw->reset_gpio, 0);
else
gpio_set_value(pw->reset_gpio, 0);
}
// Keep reset pin low for the changes to take effect
msleep(800);
return err;
}
static int lt6911uxc_board_setup(struct lt6911uxc *priv)
{
struct camera_common_data *s_data = priv->s_data;
struct camera_common_pdata *pdata = s_data->pdata;
struct device *dev = s_data->dev;
u8 version;
int i = 0, fw_ver;
int err = 0;
if (pdata->mclk_name) {
@@ -409,11 +614,31 @@ static int lt6911uxc_board_setup(struct lt6911uxc *priv)
dev_err(dev, "error during power on sensor (%d)\n", err);
goto err_power_on;
}
msleep(300);
err |= lt6911uxc_write_table(priv, lt_enable_i2c);
err |= lt6911uxc_write_reg(s_data, 0xff, 0x86);
for (i = 0; i < sizeof(lt6911uxc_FW_version); i++) {
fw_ver = 0;
err = lt6911uxc_read_reg(s_data, lt6911uxc_FW_version[i], &version);
if (err)
dev_err(s_data->dev, "%s: Error in reading FW version \n",
__func__);
fw_ver = (fw_ver << 1) | version;
}
dev_info(s_data->dev, "Lontium FW version %d \n",fw_ver);
err_power_on:
if (pdata->mclk_name)
camera_common_mclk_disable(s_data);
err = lt6911uxc_power_off(s_data);
if (err) {
dev_err(dev, "error during power off sensor (%d)\n", err);
goto err_power_on;
}
done:
return err;
}

View File

@@ -326,7 +326,7 @@ static int tegracam_set_ctrls(struct tegracam_ctrl_handler *handler,
/* For controls that require sensor to be on */
switch (ctrl->id) {
case TEGRA_CAMERA_CID_GAIN:
if (*ctrl->p_new.p_s64 == ctrlprops->min_gain_val - 1)
if (*ctrl->p_new.p_s64 == ctrlprops->max_gain_val + 1)
return 0;
err = ops->set_gain(tc_dev, *ctrl->p_new.p_s64);
break;
@@ -334,7 +334,7 @@ static int tegracam_set_ctrls(struct tegracam_ctrl_handler *handler,
err = ops->set_frame_rate(tc_dev, *ctrl->p_new.p_s64);
break;
case TEGRA_CAMERA_CID_EXPOSURE:
if (*ctrl->p_new.p_s64 == ctrlprops->min_exp_time.val - 1)
if (*ctrl->p_new.p_s64 == ctrlprops->max_exp_time.val + 1)
return 0;
err = ops->set_exposure(tc_dev, *ctrl->p_new.p_s64);
break;
@@ -607,8 +607,8 @@ int tegracam_init_ctrl_ranges_by_mode(
switch (ctrl->id) {
case TEGRA_CAMERA_CID_GAIN:
err = v4l2_ctrl_modify_range(ctrl,
ctrlprops->min_gain_val - 1,
ctrlprops->max_gain_val,
ctrlprops->min_gain_val,
ctrlprops->max_gain_val + 1,
ctrlprops->step_gain_val,
ctrlprops->default_gain);
break;
@@ -621,8 +621,8 @@ int tegracam_init_ctrl_ranges_by_mode(
break;
case TEGRA_CAMERA_CID_EXPOSURE:
err = v4l2_ctrl_modify_range(ctrl,
ctrlprops->min_exp_time.val - 1,
ctrlprops->max_exp_time.val,
ctrlprops->min_exp_time.val,
ctrlprops->max_exp_time.val + 1,
ctrlprops->step_exp_time.val,
ctrlprops->default_exp_time.val);
break;

View File

@@ -10,6 +10,7 @@ LINUXINCLUDE += -I$(srctree.nvidia-oot)/drivers/platform/tegra/aon/include
ccflags-y += -Werror
obj-m += tegra234-aon.o
obj-m += tegra-aon-ivc-echo.o
tegra234-aon-objs += \
tegra-aon-hsp.o \

View File

@@ -0,0 +1,124 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2017-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#include <linux/device.h>
#include <linux/mailbox_client.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/tegra-aon.h>
#define TX_BLOCK_PERIOD 100
#define IVC_FRAME_SIZE 64
struct tegra_aon_ivc_echo_data {
struct mbox_client cl;
struct mbox_chan *mbox;
char rx_data[IVC_FRAME_SIZE];
};
static ssize_t tegra_aon_ivc_echo_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct tegra_aon_ivc_echo_data *drvdata = dev_get_drvdata(dev);
memcpy(buf, drvdata->rx_data, IVC_FRAME_SIZE);
return IVC_FRAME_SIZE;
}
static ssize_t tegra_aon_ivc_echo_tx(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct tegra_aon_ivc_echo_data *drvdata = dev_get_drvdata(dev);
struct tegra_aon_mbox_msg msg;
int ret;
if (count > IVC_FRAME_SIZE) {
dev_err(dev, "Message is greater than the frame size %d\n",
IVC_FRAME_SIZE);
return -EINVAL;
}
msg.length = count;
msg.data = (void *)buf;
ret = mbox_send_message(drvdata->mbox, (void *)&msg);
if (ret < 0)
dev_err(dev, "mbox_send_message failed %d\n", ret);
return count;
}
static const DEVICE_ATTR(data_channel, S_IRUGO | S_IWUSR,
tegra_aon_ivc_echo_show, tegra_aon_ivc_echo_tx);
static void tegra_aon_ivc_echo_rx(struct mbox_client *cl, void *data)
{
struct tegra_aon_mbox_msg *msg = data;
struct tegra_aon_ivc_echo_data *drvdata = container_of(cl,
struct tegra_aon_ivc_echo_data,
cl);
memcpy(drvdata->rx_data, msg->data, IVC_FRAME_SIZE);
}
static int tegra_aon_ivc_echo_probe(struct platform_device *pdev)
{
int ret;
struct device *dev = &pdev->dev;
struct tegra_aon_ivc_echo_data *drvdata;
drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
if (!drvdata)
return -ENOMEM;
dev_set_drvdata(dev, drvdata);
drvdata->cl.dev = dev;
drvdata->cl.tx_block = true;
drvdata->cl.tx_tout = TX_BLOCK_PERIOD;
drvdata->cl.knows_txdone = false;
drvdata->cl.rx_callback = tegra_aon_ivc_echo_rx;
drvdata->mbox = mbox_request_channel(&drvdata->cl, 0);
if (IS_ERR(drvdata->mbox)) {
ret = PTR_ERR(drvdata->mbox);
if (ret != -EPROBE_DEFER)
dev_err(dev, "mbox_request_channel failed. Error %d\n",
ret);
return ret;
}
ret = device_create_file(dev, &dev_attr_data_channel);
if (ret) {
dev_err(dev, "Failed to create device file. Error %d\n", ret);
mbox_free_channel(drvdata->mbox);
return ret;
}
return 0;
}
static int tegra_aon_ivc_echo_remove(struct platform_device *pdev)
{
struct tegra_aon_ivc_echo_data *drvdata = dev_get_drvdata(&pdev->dev);
device_remove_file(&pdev->dev, &dev_attr_data_channel);
mbox_free_channel(drvdata->mbox);
return 0;
}
static const struct of_device_id tegra_aon_ivc_echo_match[] = {
{ .compatible = "nvidia,tegra186-aon-ivc-echo", },
{ },
};
MODULE_DEVICE_TABLE(of, tegra_aon_ivc_echo_match);
static struct platform_driver tegra_aon_ivc_echo_driver = {
.probe = tegra_aon_ivc_echo_probe,
.remove = tegra_aon_ivc_echo_remove,
.driver = {
.name = "tegra-aon-ivc-echo",
.of_match_table = tegra_aon_ivc_echo_match,
},
};
module_platform_driver(tegra_aon_ivc_echo_driver);
MODULE_LICENSE("GPL v2");

View File

@@ -4,5 +4,6 @@
ifeq ($(findstring ack_src,$(NV_BUILD_KERNEL_OPTIONS)),)
obj-m += pex9749-thermal.o
obj-m += tegra234-oc-event.o
obj-m += thermal-trip-event.o
endif
obj-m += max77851_thermal.o

View File

@@ -0,0 +1,257 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/thermal.h>
#include <linux/wait.h>
enum cdev_states {
CDEV_INACTIVE,
CDEV_ACTIVE,
CDEV_DESTROY,
};
struct therm_trip_event {
unsigned int cur_state;
unsigned int max_state;
unsigned int event_timeout_ms;
struct mutex cur_state_lock;
struct mutex event_timeout_lock;
struct thermal_cooling_device *cdev;
wait_queue_head_t waitq_head;
};
static int tte_cdev_get_max_state(struct thermal_cooling_device *tcd,
unsigned long *state)
{
struct therm_trip_event *tte = tcd->devdata;
*state = tte->max_state;
return 0;
}
static int tte_cdev_get_cur_state(struct thermal_cooling_device *tcd,
unsigned long *state)
{
struct therm_trip_event *tte = tcd->devdata;
*state = tte->cur_state;
return 0;
}
static int tte_cdev_set_cur_state(struct thermal_cooling_device *tcd,
unsigned long state)
{
struct therm_trip_event *tte = tcd->devdata;
struct device *dev = &tcd->device;
if (state > tte->max_state)
return -EINVAL;
if (state == tte->cur_state)
return 0;
dev_notice(dev, "%s cooling state: %u -> %lu\n", tcd->type,
tte->cur_state, state);
/*
* Although tcd->lock is already held in the thermal framework, a lock
* is added here to avoid a race condition between set_cur_state() and
* driver removal.
*/
mutex_lock(&tte->cur_state_lock);
tte->cur_state = state;
mutex_unlock(&tte->cur_state_lock);
if (tte->cur_state != CDEV_INACTIVE) {
if (wq_has_sleeper(&tte->waitq_head)) {
wake_up_interruptible_all(&tte->waitq_head);
dev_dbg(dev, "THERMAL_EVENT_TRIPPED!\n");
}
}
return 0;
}
static ssize_t thermal_trip_event_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct therm_trip_event *tte = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", tte->cur_state);
}
static ssize_t thermal_trip_event_block_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct therm_trip_event *tte = dev_get_drvdata(dev);
unsigned int event_timeout_ms = tte->event_timeout_ms;
int ret;
if (event_timeout_ms > 0)
ret = wait_event_interruptible_timeout(
tte->waitq_head, tte->cur_state != CDEV_INACTIVE,
msecs_to_jiffies(event_timeout_ms));
else
ret = wait_event_interruptible(tte->waitq_head,
tte->cur_state != CDEV_INACTIVE);
/*
* -ERESTARTSYS is returned to avoid false alarm and to resume the call.
*/
if (ret < 0)
return ret;
return sprintf(buf, "%d\n", tte->cur_state);
}
static ssize_t thermal_trip_event_block_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
unsigned int val;
struct therm_trip_event *tte = dev_get_drvdata(dev);
if (kstrtouint(buf, 0, &val))
return -EINVAL;
mutex_lock(&tte->event_timeout_lock);
tte->event_timeout_ms = val;
mutex_unlock(&tte->event_timeout_lock);
return count;
}
static struct thermal_cooling_device_ops tte_cdev_ops = {
.get_max_state = tte_cdev_get_max_state,
.get_cur_state = tte_cdev_get_cur_state,
.set_cur_state = tte_cdev_set_cur_state,
};
static DEVICE_ATTR_RO(thermal_trip_event);
static DEVICE_ATTR_RW(thermal_trip_event_block);
static const struct attribute *tte_cdev_attr[] = {
&dev_attr_thermal_trip_event.attr,
&dev_attr_thermal_trip_event_block.attr,
NULL,
};
static int thermal_trip_event_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct therm_trip_event *tte;
const char *cdev_type;
int ret;
tte = devm_kzalloc(dev, sizeof(struct therm_trip_event), GFP_KERNEL);
if (!tte)
return -ENOMEM;
if (of_property_read_string(np, "cdev-type", &cdev_type) != 0) {
dev_err(dev, "invalid cdev-type property of %pOFn\n", np);
return -EINVAL;
}
tte->cur_state = CDEV_INACTIVE;
tte->max_state = CDEV_DESTROY;
mutex_init(&tte->cur_state_lock);
mutex_init(&tte->event_timeout_lock);
init_waitqueue_head(&tte->waitq_head);
dev_set_drvdata(dev, tte);
tte->cdev = thermal_of_cooling_device_register(np, cdev_type, tte,
&tte_cdev_ops);
if (IS_ERR(tte->cdev)) {
ret = PTR_ERR(tte->cdev);
goto destroy_lock;
}
ret = sysfs_create_files(&dev->kobj, tte_cdev_attr);
if (ret) {
dev_err(dev, "failed to create sysfs files\n");
goto free_cdev;
}
ret = sysfs_create_link(&tte->cdev->device.kobj, &dev->kobj,
"thermal_trip_event");
if (ret) {
dev_err(dev, "failed to create sysfs symlink\n");
goto free_sysfs_files;
}
dev_info(dev, "cooling device registered.\n");
return 0;
free_sysfs_files:
sysfs_remove_files(&dev->kobj, tte_cdev_attr);
free_cdev:
thermal_cooling_device_unregister(tte->cdev);
destroy_lock:
mutex_destroy(&tte->event_timeout_lock);
mutex_destroy(&tte->cur_state_lock);
return ret;
}
static int thermal_trip_event_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct therm_trip_event *tte = dev_get_drvdata(dev);
struct thermal_cooling_device *cdev = tte->cdev;
/*
* There could be processes waiting for the event to happen while the
* driver is being removed. To have smooth removal, wake them up by
* updating the cur_state. The cooling state change here is not
* perceived by the thermal framework, but it's not a big deal as the
* cooling device is going to be destroyed soon.
*/
mutex_lock(&tte->cur_state_lock);
tte->cur_state = CDEV_DESTROY;
mutex_unlock(&tte->cur_state_lock);
if (wq_has_sleeper(&tte->waitq_head)) {
wake_up_interruptible_all(&tte->waitq_head);
dev_dbg(dev, "THERMAL_EVENT_DESTROYED!\n");
}
sysfs_remove_link(&cdev->device.kobj, "thermal_trip_event");
sysfs_remove_files(&dev->kobj, tte_cdev_attr);
thermal_cooling_device_unregister(cdev);
mutex_destroy(&tte->event_timeout_lock);
mutex_destroy(&tte->cur_state_lock);
return 0;
}
static const struct of_device_id thermal_trip_event_of_match[] = {
{
.compatible = "thermal-trip-event",
},
{},
};
MODULE_DEVICE_TABLE(of, thermal_trip_event_of_match);
static struct platform_driver thermal_trip_event_driver = {
.driver = {
.name = "thermal-trip-event",
.owner = THIS_MODULE,
.of_match_table = thermal_trip_event_of_match,
},
.probe = thermal_trip_event_probe,
.remove = thermal_trip_event_remove,
};
module_platform_driver(thermal_trip_event_driver);
MODULE_AUTHOR("Sreenivasulu Velpula <svelpula@nvidia.com>");
MODULE_AUTHOR("Yi-Wei Wang <yiweiw@nvidia.com>");
MODULE_DESCRIPTION("Thermal Trip Event Driver");
MODULE_LICENSE("GPL v2");

View File

@@ -434,10 +434,12 @@ int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data,
* and suspend-resume functionality on Tegra30, although audio mclk is
* only needed for audio.
*/
ret = clk_prepare_enable(data->clk_cdev1);
if (ret) {
dev_err(data->dev, "Can't enable cdev1: %d\n", ret);
return ret;
if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA30) {
ret = clk_prepare_enable(data->clk_cdev1);
if (ret) {
dev_err(data->dev, "Can't enable cdev1: %d\n", ret);
return ret;
}
}
return 0;