^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (C) 2013 NVIDIA Corporation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/of_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/pinctrl/pinconf-generic.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/pinctrl/pinctrl.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/pinctrl/pinmux.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/pm_runtime.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/regulator/consumer.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/reset.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/workqueue.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <drm/drm_dp_helper.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <drm/drm_panel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include "dp.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include "dpaux.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include "drm.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include "trace.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) static DEFINE_MUTEX(dpaux_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) static LIST_HEAD(dpaux_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) struct tegra_dpaux_soc {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) unsigned int cmh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) unsigned int drvz;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) unsigned int drvi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) struct tegra_dpaux {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) struct drm_dp_aux aux;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) struct device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) const struct tegra_dpaux_soc *soc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) void __iomem *regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) int irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) struct tegra_output *output;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) struct reset_control *rst;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) struct clk *clk_parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) struct clk *clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) struct regulator *vdd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) struct completion complete;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) struct work_struct work;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) struct list_head list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) #ifdef CONFIG_GENERIC_PINCONF
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) struct pinctrl_dev *pinctrl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) struct pinctrl_desc desc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) static inline struct tegra_dpaux *to_dpaux(struct drm_dp_aux *aux)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) return container_of(aux, struct tegra_dpaux, aux);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) static inline struct tegra_dpaux *work_to_dpaux(struct work_struct *work)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) return container_of(work, struct tegra_dpaux, work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) static inline u32 tegra_dpaux_readl(struct tegra_dpaux *dpaux,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) unsigned int offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) u32 value = readl(dpaux->regs + (offset << 2));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) trace_dpaux_readl(dpaux->dev, offset, value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) return value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) static inline void tegra_dpaux_writel(struct tegra_dpaux *dpaux,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) u32 value, unsigned int offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) trace_dpaux_writel(dpaux->dev, offset, value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) writel(value, dpaux->regs + (offset << 2));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) static void tegra_dpaux_write_fifo(struct tegra_dpaux *dpaux, const u8 *buffer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) size_t size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) size_t i, j;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) for (i = 0; i < DIV_ROUND_UP(size, 4); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) size_t num = min_t(size_t, size - i * 4, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) u32 value = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) for (j = 0; j < num; j++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) value |= buffer[i * 4 + j] << (j * 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) tegra_dpaux_writel(dpaux, value, DPAUX_DP_AUXDATA_WRITE(i));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) static void tegra_dpaux_read_fifo(struct tegra_dpaux *dpaux, u8 *buffer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) size_t size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) size_t i, j;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) for (i = 0; i < DIV_ROUND_UP(size, 4); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) size_t num = min_t(size_t, size - i * 4, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) u32 value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) value = tegra_dpaux_readl(dpaux, DPAUX_DP_AUXDATA_READ(i));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) for (j = 0; j < num; j++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) buffer[i * 4 + j] = value >> (j * 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) static ssize_t tegra_dpaux_transfer(struct drm_dp_aux *aux,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) struct drm_dp_aux_msg *msg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) unsigned long timeout = msecs_to_jiffies(250);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) struct tegra_dpaux *dpaux = to_dpaux(aux);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) unsigned long status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) ssize_t ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) u8 reply = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) u32 value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) /* Tegra has 4x4 byte DP AUX transmit and receive FIFOs. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) if (msg->size > 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) * Allow zero-sized messages only for I2C, in which case they specify
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) * address-only transactions.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) if (msg->size < 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) switch (msg->request & ~DP_AUX_I2C_MOT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) case DP_AUX_I2C_WRITE_STATUS_UPDATE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) case DP_AUX_I2C_WRITE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) case DP_AUX_I2C_READ:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) value = DPAUX_DP_AUXCTL_CMD_ADDRESS_ONLY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) /* For non-zero-sized messages, set the CMDLEN field. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) value = DPAUX_DP_AUXCTL_CMDLEN(msg->size - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) switch (msg->request & ~DP_AUX_I2C_MOT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) case DP_AUX_I2C_WRITE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) if (msg->request & DP_AUX_I2C_MOT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) value |= DPAUX_DP_AUXCTL_CMD_MOT_WR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) value |= DPAUX_DP_AUXCTL_CMD_I2C_WR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) case DP_AUX_I2C_READ:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) if (msg->request & DP_AUX_I2C_MOT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) value |= DPAUX_DP_AUXCTL_CMD_MOT_RD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) value |= DPAUX_DP_AUXCTL_CMD_I2C_RD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) case DP_AUX_I2C_WRITE_STATUS_UPDATE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) if (msg->request & DP_AUX_I2C_MOT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) value |= DPAUX_DP_AUXCTL_CMD_MOT_RQ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) value |= DPAUX_DP_AUXCTL_CMD_I2C_RQ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) case DP_AUX_NATIVE_WRITE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) value |= DPAUX_DP_AUXCTL_CMD_AUX_WR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) case DP_AUX_NATIVE_READ:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) value |= DPAUX_DP_AUXCTL_CMD_AUX_RD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) tegra_dpaux_writel(dpaux, msg->address, DPAUX_DP_AUXADDR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) tegra_dpaux_writel(dpaux, value, DPAUX_DP_AUXCTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) if ((msg->request & DP_AUX_I2C_READ) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) tegra_dpaux_write_fifo(dpaux, msg->buffer, msg->size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) ret = msg->size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) /* start transaction */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) value = tegra_dpaux_readl(dpaux, DPAUX_DP_AUXCTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) value |= DPAUX_DP_AUXCTL_TRANSACTREQ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) tegra_dpaux_writel(dpaux, value, DPAUX_DP_AUXCTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) status = wait_for_completion_timeout(&dpaux->complete, timeout);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) if (!status)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) return -ETIMEDOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) /* read status and clear errors */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) value = tegra_dpaux_readl(dpaux, DPAUX_DP_AUXSTAT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) tegra_dpaux_writel(dpaux, 0xf00, DPAUX_DP_AUXSTAT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) if (value & DPAUX_DP_AUXSTAT_TIMEOUT_ERROR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) return -ETIMEDOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) if ((value & DPAUX_DP_AUXSTAT_RX_ERROR) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) (value & DPAUX_DP_AUXSTAT_SINKSTAT_ERROR) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) (value & DPAUX_DP_AUXSTAT_NO_STOP_ERROR))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) switch ((value & DPAUX_DP_AUXSTAT_REPLY_TYPE_MASK) >> 16) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) case 0x00:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) reply = DP_AUX_NATIVE_REPLY_ACK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) case 0x01:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) reply = DP_AUX_NATIVE_REPLY_NACK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) case 0x02:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) reply = DP_AUX_NATIVE_REPLY_DEFER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) case 0x04:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) reply = DP_AUX_I2C_REPLY_NACK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) case 0x08:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) reply = DP_AUX_I2C_REPLY_DEFER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) if ((msg->size > 0) && (msg->reply == DP_AUX_NATIVE_REPLY_ACK)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) if (msg->request & DP_AUX_I2C_READ) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) size_t count = value & DPAUX_DP_AUXSTAT_REPLY_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) * There might be a smarter way to do this, but since
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) * the DP helpers will already retry transactions for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) * an -EBUSY return value, simply reuse that instead.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) if (count != msg->size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) ret = -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) tegra_dpaux_read_fifo(dpaux, msg->buffer, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) ret = count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) msg->reply = reply;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) static void tegra_dpaux_hotplug(struct work_struct *work)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) struct tegra_dpaux *dpaux = work_to_dpaux(work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) if (dpaux->output)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) drm_helper_hpd_irq_event(dpaux->output->connector.dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) static irqreturn_t tegra_dpaux_irq(int irq, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) struct tegra_dpaux *dpaux = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) irqreturn_t ret = IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) u32 value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) /* clear interrupts */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) value = tegra_dpaux_readl(dpaux, DPAUX_INTR_AUX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) tegra_dpaux_writel(dpaux, value, DPAUX_INTR_AUX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) if (value & (DPAUX_INTR_PLUG_EVENT | DPAUX_INTR_UNPLUG_EVENT))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) schedule_work(&dpaux->work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) if (value & DPAUX_INTR_IRQ_EVENT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) /* TODO: handle this */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) if (value & DPAUX_INTR_AUX_DONE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) complete(&dpaux->complete);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) enum tegra_dpaux_functions {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) DPAUX_PADCTL_FUNC_AUX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) DPAUX_PADCTL_FUNC_I2C,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) DPAUX_PADCTL_FUNC_OFF,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) static void tegra_dpaux_pad_power_down(struct tegra_dpaux *dpaux)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) u32 value = tegra_dpaux_readl(dpaux, DPAUX_HYBRID_SPARE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) value |= DPAUX_HYBRID_SPARE_PAD_POWER_DOWN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) tegra_dpaux_writel(dpaux, value, DPAUX_HYBRID_SPARE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) static void tegra_dpaux_pad_power_up(struct tegra_dpaux *dpaux)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) u32 value = tegra_dpaux_readl(dpaux, DPAUX_HYBRID_SPARE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) value &= ~DPAUX_HYBRID_SPARE_PAD_POWER_DOWN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) tegra_dpaux_writel(dpaux, value, DPAUX_HYBRID_SPARE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) static int tegra_dpaux_pad_config(struct tegra_dpaux *dpaux, unsigned function)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) u32 value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) switch (function) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) case DPAUX_PADCTL_FUNC_AUX:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) value = DPAUX_HYBRID_PADCTL_AUX_CMH(dpaux->soc->cmh) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) DPAUX_HYBRID_PADCTL_AUX_DRVZ(dpaux->soc->drvz) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) DPAUX_HYBRID_PADCTL_AUX_DRVI(dpaux->soc->drvi) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) DPAUX_HYBRID_PADCTL_AUX_INPUT_RCV |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) DPAUX_HYBRID_PADCTL_MODE_AUX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) case DPAUX_PADCTL_FUNC_I2C:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) value = DPAUX_HYBRID_PADCTL_I2C_SDA_INPUT_RCV |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) DPAUX_HYBRID_PADCTL_I2C_SCL_INPUT_RCV |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) DPAUX_HYBRID_PADCTL_AUX_CMH(dpaux->soc->cmh) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) DPAUX_HYBRID_PADCTL_AUX_DRVZ(dpaux->soc->drvz) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) DPAUX_HYBRID_PADCTL_AUX_DRVI(dpaux->soc->drvi) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) DPAUX_HYBRID_PADCTL_MODE_I2C;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) case DPAUX_PADCTL_FUNC_OFF:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) tegra_dpaux_pad_power_down(dpaux);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) return -ENOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) tegra_dpaux_writel(dpaux, value, DPAUX_HYBRID_PADCTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) tegra_dpaux_pad_power_up(dpaux);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) #ifdef CONFIG_GENERIC_PINCONF
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) static const struct pinctrl_pin_desc tegra_dpaux_pins[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) PINCTRL_PIN(0, "DP_AUX_CHx_P"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) PINCTRL_PIN(1, "DP_AUX_CHx_N"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) static const unsigned tegra_dpaux_pin_numbers[] = { 0, 1 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) static const char * const tegra_dpaux_groups[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) "dpaux-io",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) static const char * const tegra_dpaux_functions[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) "aux",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) "i2c",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) "off",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) static int tegra_dpaux_get_groups_count(struct pinctrl_dev *pinctrl)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) return ARRAY_SIZE(tegra_dpaux_groups);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) static const char *tegra_dpaux_get_group_name(struct pinctrl_dev *pinctrl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) unsigned int group)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) return tegra_dpaux_groups[group];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) static int tegra_dpaux_get_group_pins(struct pinctrl_dev *pinctrl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) unsigned group, const unsigned **pins,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) unsigned *num_pins)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) *pins = tegra_dpaux_pin_numbers;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) *num_pins = ARRAY_SIZE(tegra_dpaux_pin_numbers);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) static const struct pinctrl_ops tegra_dpaux_pinctrl_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) .get_groups_count = tegra_dpaux_get_groups_count,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) .get_group_name = tegra_dpaux_get_group_name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) .get_group_pins = tegra_dpaux_get_group_pins,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) .dt_node_to_map = pinconf_generic_dt_node_to_map_group,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) .dt_free_map = pinconf_generic_dt_free_map,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) static int tegra_dpaux_get_functions_count(struct pinctrl_dev *pinctrl)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) return ARRAY_SIZE(tegra_dpaux_functions);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) static const char *tegra_dpaux_get_function_name(struct pinctrl_dev *pinctrl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) unsigned int function)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) return tegra_dpaux_functions[function];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) static int tegra_dpaux_get_function_groups(struct pinctrl_dev *pinctrl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) unsigned int function,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) const char * const **groups,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) unsigned * const num_groups)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) *num_groups = ARRAY_SIZE(tegra_dpaux_groups);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) *groups = tegra_dpaux_groups;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) static int tegra_dpaux_set_mux(struct pinctrl_dev *pinctrl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) unsigned int function, unsigned int group)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) struct tegra_dpaux *dpaux = pinctrl_dev_get_drvdata(pinctrl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) return tegra_dpaux_pad_config(dpaux, function);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) static const struct pinmux_ops tegra_dpaux_pinmux_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) .get_functions_count = tegra_dpaux_get_functions_count,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) .get_function_name = tegra_dpaux_get_function_name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) .get_function_groups = tegra_dpaux_get_function_groups,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) .set_mux = tegra_dpaux_set_mux,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) static int tegra_dpaux_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) struct tegra_dpaux *dpaux;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) struct resource *regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) u32 value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) dpaux = devm_kzalloc(&pdev->dev, sizeof(*dpaux), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) if (!dpaux)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) dpaux->soc = of_device_get_match_data(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) INIT_WORK(&dpaux->work, tegra_dpaux_hotplug);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) init_completion(&dpaux->complete);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) INIT_LIST_HEAD(&dpaux->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) dpaux->dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) dpaux->regs = devm_ioremap_resource(&pdev->dev, regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) if (IS_ERR(dpaux->regs))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) return PTR_ERR(dpaux->regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) dpaux->irq = platform_get_irq(pdev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) if (dpaux->irq < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) dev_err(&pdev->dev, "failed to get IRQ\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) if (!pdev->dev.pm_domain) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) dpaux->rst = devm_reset_control_get(&pdev->dev, "dpaux");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) if (IS_ERR(dpaux->rst)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) dev_err(&pdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) "failed to get reset control: %ld\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) PTR_ERR(dpaux->rst));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) return PTR_ERR(dpaux->rst);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) dpaux->clk = devm_clk_get(&pdev->dev, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) if (IS_ERR(dpaux->clk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) dev_err(&pdev->dev, "failed to get module clock: %ld\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) PTR_ERR(dpaux->clk));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) return PTR_ERR(dpaux->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) dpaux->clk_parent = devm_clk_get(&pdev->dev, "parent");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) if (IS_ERR(dpaux->clk_parent)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) dev_err(&pdev->dev, "failed to get parent clock: %ld\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) PTR_ERR(dpaux->clk_parent));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) return PTR_ERR(dpaux->clk_parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) err = clk_set_rate(dpaux->clk_parent, 270000000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) if (err < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) dev_err(&pdev->dev, "failed to set clock to 270 MHz: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) dpaux->vdd = devm_regulator_get_optional(&pdev->dev, "vdd");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) if (IS_ERR(dpaux->vdd)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) if (PTR_ERR(dpaux->vdd) != -ENODEV) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) if (PTR_ERR(dpaux->vdd) != -EPROBE_DEFER)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) dev_err(&pdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) "failed to get VDD supply: %ld\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) PTR_ERR(dpaux->vdd));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) return PTR_ERR(dpaux->vdd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) dpaux->vdd = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) platform_set_drvdata(pdev, dpaux);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) pm_runtime_enable(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) pm_runtime_get_sync(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) err = devm_request_irq(dpaux->dev, dpaux->irq, tegra_dpaux_irq, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) dev_name(dpaux->dev), dpaux);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) if (err < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) dev_err(dpaux->dev, "failed to request IRQ#%u: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) dpaux->irq, err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) disable_irq(dpaux->irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) dpaux->aux.transfer = tegra_dpaux_transfer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) dpaux->aux.dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) err = drm_dp_aux_register(&dpaux->aux);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) * Assume that by default the DPAUX/I2C pads will be used for HDMI,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) * so power them up and configure them in I2C mode.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) * The DPAUX code paths reconfigure the pads in AUX mode, but there
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) * is no possibility to perform the I2C mode configuration in the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) * HDMI path.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) err = tegra_dpaux_pad_config(dpaux, DPAUX_PADCTL_FUNC_I2C);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) #ifdef CONFIG_GENERIC_PINCONF
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) dpaux->desc.name = dev_name(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) dpaux->desc.pins = tegra_dpaux_pins;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) dpaux->desc.npins = ARRAY_SIZE(tegra_dpaux_pins);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) dpaux->desc.pctlops = &tegra_dpaux_pinctrl_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) dpaux->desc.pmxops = &tegra_dpaux_pinmux_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) dpaux->desc.owner = THIS_MODULE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) dpaux->pinctrl = devm_pinctrl_register(&pdev->dev, &dpaux->desc, dpaux);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) if (IS_ERR(dpaux->pinctrl)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) dev_err(&pdev->dev, "failed to register pincontrol\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) return PTR_ERR(dpaux->pinctrl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) /* enable and clear all interrupts */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) value = DPAUX_INTR_AUX_DONE | DPAUX_INTR_IRQ_EVENT |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) DPAUX_INTR_UNPLUG_EVENT | DPAUX_INTR_PLUG_EVENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) tegra_dpaux_writel(dpaux, value, DPAUX_INTR_EN_AUX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) tegra_dpaux_writel(dpaux, value, DPAUX_INTR_AUX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) mutex_lock(&dpaux_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) list_add_tail(&dpaux->list, &dpaux_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) mutex_unlock(&dpaux_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) static int tegra_dpaux_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) struct tegra_dpaux *dpaux = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) cancel_work_sync(&dpaux->work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) /* make sure pads are powered down when not in use */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) tegra_dpaux_pad_power_down(dpaux);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) pm_runtime_put_sync(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) pm_runtime_disable(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) drm_dp_aux_unregister(&dpaux->aux);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) mutex_lock(&dpaux_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) list_del(&dpaux->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) mutex_unlock(&dpaux_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) #ifdef CONFIG_PM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) static int tegra_dpaux_suspend(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) struct tegra_dpaux *dpaux = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) int err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) if (dpaux->rst) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) err = reset_control_assert(dpaux->rst);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) if (err < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) dev_err(dev, "failed to assert reset: %d\n", err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) usleep_range(1000, 2000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) clk_disable_unprepare(dpaux->clk_parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) clk_disable_unprepare(dpaux->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) static int tegra_dpaux_resume(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) struct tegra_dpaux *dpaux = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) err = clk_prepare_enable(dpaux->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) if (err < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) dev_err(dev, "failed to enable clock: %d\n", err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) err = clk_prepare_enable(dpaux->clk_parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) if (err < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) dev_err(dev, "failed to enable parent clock: %d\n", err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) goto disable_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) usleep_range(1000, 2000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) if (dpaux->rst) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) err = reset_control_deassert(dpaux->rst);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) if (err < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) dev_err(dev, "failed to deassert reset: %d\n", err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) goto disable_parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) usleep_range(1000, 2000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) disable_parent:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) clk_disable_unprepare(dpaux->clk_parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) disable_clk:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) clk_disable_unprepare(dpaux->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) static const struct dev_pm_ops tegra_dpaux_pm_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) SET_RUNTIME_PM_OPS(tegra_dpaux_suspend, tegra_dpaux_resume, NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) static const struct tegra_dpaux_soc tegra124_dpaux_soc = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) .cmh = 0x02,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) .drvz = 0x04,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) .drvi = 0x18,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) static const struct tegra_dpaux_soc tegra210_dpaux_soc = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) .cmh = 0x02,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) .drvz = 0x04,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) .drvi = 0x30,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) static const struct tegra_dpaux_soc tegra194_dpaux_soc = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) .cmh = 0x02,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) .drvz = 0x04,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) .drvi = 0x2c,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) static const struct of_device_id tegra_dpaux_of_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) { .compatible = "nvidia,tegra194-dpaux", .data = &tegra194_dpaux_soc },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) { .compatible = "nvidia,tegra186-dpaux", .data = &tegra210_dpaux_soc },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) { .compatible = "nvidia,tegra210-dpaux", .data = &tegra210_dpaux_soc },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) { .compatible = "nvidia,tegra124-dpaux", .data = &tegra124_dpaux_soc },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) { },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) MODULE_DEVICE_TABLE(of, tegra_dpaux_of_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) struct platform_driver tegra_dpaux_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) .name = "tegra-dpaux",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) .of_match_table = tegra_dpaux_of_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) .pm = &tegra_dpaux_pm_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) .probe = tegra_dpaux_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) .remove = tegra_dpaux_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) struct drm_dp_aux *drm_dp_aux_find_by_of_node(struct device_node *np)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) struct tegra_dpaux *dpaux;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) mutex_lock(&dpaux_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) list_for_each_entry(dpaux, &dpaux_list, list)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) if (np == dpaux->dev->of_node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) mutex_unlock(&dpaux_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) return &dpaux->aux;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) mutex_unlock(&dpaux_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) int drm_dp_aux_attach(struct drm_dp_aux *aux, struct tegra_output *output)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) struct tegra_dpaux *dpaux = to_dpaux(aux);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) unsigned long timeout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) output->connector.polled = DRM_CONNECTOR_POLL_HPD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) dpaux->output = output;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) if (output->panel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) enum drm_connector_status status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) if (dpaux->vdd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) err = regulator_enable(dpaux->vdd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) timeout = jiffies + msecs_to_jiffies(250);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) while (time_before(jiffies, timeout)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) status = drm_dp_aux_detect(aux);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) if (status == connector_status_connected)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) usleep_range(1000, 2000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) if (status != connector_status_connected)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) return -ETIMEDOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) enable_irq(dpaux->irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) int drm_dp_aux_detach(struct drm_dp_aux *aux)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) struct tegra_dpaux *dpaux = to_dpaux(aux);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) unsigned long timeout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) disable_irq(dpaux->irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) if (dpaux->output->panel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) enum drm_connector_status status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) if (dpaux->vdd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) err = regulator_disable(dpaux->vdd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) timeout = jiffies + msecs_to_jiffies(250);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) while (time_before(jiffies, timeout)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) status = drm_dp_aux_detect(aux);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) if (status == connector_status_disconnected)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) usleep_range(1000, 2000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) if (status != connector_status_disconnected)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) return -ETIMEDOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) dpaux->output = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) enum drm_connector_status drm_dp_aux_detect(struct drm_dp_aux *aux)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) struct tegra_dpaux *dpaux = to_dpaux(aux);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) u32 value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) value = tegra_dpaux_readl(dpaux, DPAUX_DP_AUXSTAT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) if (value & DPAUX_DP_AUXSTAT_HPD_STATUS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) return connector_status_connected;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) return connector_status_disconnected;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) int drm_dp_aux_enable(struct drm_dp_aux *aux)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) struct tegra_dpaux *dpaux = to_dpaux(aux);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) return tegra_dpaux_pad_config(dpaux, DPAUX_PADCTL_FUNC_AUX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) int drm_dp_aux_disable(struct drm_dp_aux *aux)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) struct tegra_dpaux *dpaux = to_dpaux(aux);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) tegra_dpaux_pad_power_down(dpaux);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) }