sii9234.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994
  1. /*
  2. * Copyright (C) 2017 Samsung Electronics
  3. *
  4. * Authors:
  5. * Tomasz Stanislawski <t.stanislaws@samsung.com>
  6. * Maciej Purski <m.purski@samsung.com>
  7. *
  8. * Based on sii9234 driver created by:
  9. * Adam Hampson <ahampson@sta.samsung.com>
  10. * Erik Gilling <konkers@android.com>
  11. * Shankar Bandal <shankar.b@samsung.com>
  12. * Dharam Kumar <dharam.kr@samsung.com>
  13. *
  14. * This program is free software; you can redistribute it and/or modify
  15. * it under the terms of the GNU General Public License as published by
  16. * the Free Software Foundation; either version 2 of the License, or
  17. * (at your option) any later version.
  18. *
  19. * This program is distributed in the hope that it will be useful,
  20. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22. * GNU General Public License for more details.
  23. *
  24. * You should have received a copy of the GNU General Public License
  25. * along with this program
  26. *
  27. */
  28. #include <drm/bridge/mhl.h>
  29. #include <drm/drm_crtc.h>
  30. #include <drm/drm_edid.h>
  31. #include <linux/delay.h>
  32. #include <linux/err.h>
  33. #include <linux/gpio/consumer.h>
  34. #include <linux/i2c.h>
  35. #include <linux/interrupt.h>
  36. #include <linux/irq.h>
  37. #include <linux/kernel.h>
  38. #include <linux/module.h>
  39. #include <linux/mutex.h>
  40. #include <linux/regulator/consumer.h>
  41. #include <linux/slab.h>
  42. #define CBUS_DEVCAP_OFFSET 0x80
  43. #define SII9234_MHL_VERSION 0x11
  44. #define SII9234_SCRATCHPAD_SIZE 0x10
  45. #define SII9234_INT_STAT_SIZE 0x33
  46. #define BIT_TMDS_CCTRL_TMDS_OE BIT(4)
  47. #define MHL_HPD_OUT_OVR_EN BIT(4)
  48. #define MHL_HPD_OUT_OVR_VAL BIT(5)
  49. #define MHL_INIT_TIMEOUT 0x0C
  50. /* MHL Tx registers and bits */
  51. #define MHL_TX_SRST 0x05
  52. #define MHL_TX_SYSSTAT_REG 0x09
  53. #define MHL_TX_INTR1_REG 0x71
  54. #define MHL_TX_INTR4_REG 0x74
  55. #define MHL_TX_INTR1_ENABLE_REG 0x75
  56. #define MHL_TX_INTR4_ENABLE_REG 0x78
  57. #define MHL_TX_INT_CTRL_REG 0x79
  58. #define MHL_TX_TMDS_CCTRL 0x80
  59. #define MHL_TX_DISC_CTRL1_REG 0x90
  60. #define MHL_TX_DISC_CTRL2_REG 0x91
  61. #define MHL_TX_DISC_CTRL3_REG 0x92
  62. #define MHL_TX_DISC_CTRL4_REG 0x93
  63. #define MHL_TX_DISC_CTRL5_REG 0x94
  64. #define MHL_TX_DISC_CTRL6_REG 0x95
  65. #define MHL_TX_DISC_CTRL7_REG 0x96
  66. #define MHL_TX_DISC_CTRL8_REG 0x97
  67. #define MHL_TX_STAT2_REG 0x99
  68. #define MHL_TX_MHLTX_CTL1_REG 0xA0
  69. #define MHL_TX_MHLTX_CTL2_REG 0xA1
  70. #define MHL_TX_MHLTX_CTL4_REG 0xA3
  71. #define MHL_TX_MHLTX_CTL6_REG 0xA5
  72. #define MHL_TX_MHLTX_CTL7_REG 0xA6
  73. #define RSEN_STATUS BIT(2)
  74. #define HPD_CHANGE_INT BIT(6)
  75. #define RSEN_CHANGE_INT BIT(5)
  76. #define RGND_READY_INT BIT(6)
  77. #define VBUS_LOW_INT BIT(5)
  78. #define CBUS_LKOUT_INT BIT(4)
  79. #define MHL_DISC_FAIL_INT BIT(3)
  80. #define MHL_EST_INT BIT(2)
  81. #define HPD_CHANGE_INT_MASK BIT(6)
  82. #define RSEN_CHANGE_INT_MASK BIT(5)
  83. #define RGND_READY_MASK BIT(6)
  84. #define CBUS_LKOUT_MASK BIT(4)
  85. #define MHL_DISC_FAIL_MASK BIT(3)
  86. #define MHL_EST_MASK BIT(2)
  87. #define SKIP_GND BIT(6)
  88. #define ATT_THRESH_SHIFT 0x04
  89. #define ATT_THRESH_MASK (0x03 << ATT_THRESH_SHIFT)
  90. #define USB_D_OEN BIT(3)
  91. #define DEGLITCH_TIME_MASK 0x07
  92. #define DEGLITCH_TIME_2MS 0
  93. #define DEGLITCH_TIME_4MS 1
  94. #define DEGLITCH_TIME_8MS 2
  95. #define DEGLITCH_TIME_16MS 3
  96. #define DEGLITCH_TIME_40MS 4
  97. #define DEGLITCH_TIME_50MS 5
  98. #define DEGLITCH_TIME_60MS 6
  99. #define DEGLITCH_TIME_128MS 7
  100. #define USB_D_OVR BIT(7)
  101. #define USB_ID_OVR BIT(6)
  102. #define DVRFLT_SEL BIT(5)
  103. #define BLOCK_RGND_INT BIT(4)
  104. #define SKIP_DEG BIT(3)
  105. #define CI2CA_POL BIT(2)
  106. #define CI2CA_WKUP BIT(1)
  107. #define SINGLE_ATT BIT(0)
  108. #define USB_D_ODN BIT(5)
  109. #define VBUS_CHECK BIT(2)
  110. #define RGND_INTP_MASK 0x03
  111. #define RGND_INTP_OPEN 0
  112. #define RGND_INTP_2K 1
  113. #define RGND_INTP_1K 2
  114. #define RGND_INTP_SHORT 3
  115. /* HDMI registers */
  116. #define HDMI_RX_TMDS0_CCTRL1_REG 0x10
  117. #define HDMI_RX_TMDS_CLK_EN_REG 0x11
  118. #define HDMI_RX_TMDS_CH_EN_REG 0x12
  119. #define HDMI_RX_PLL_CALREFSEL_REG 0x17
  120. #define HDMI_RX_PLL_VCOCAL_REG 0x1A
  121. #define HDMI_RX_EQ_DATA0_REG 0x22
  122. #define HDMI_RX_EQ_DATA1_REG 0x23
  123. #define HDMI_RX_EQ_DATA2_REG 0x24
  124. #define HDMI_RX_EQ_DATA3_REG 0x25
  125. #define HDMI_RX_EQ_DATA4_REG 0x26
  126. #define HDMI_RX_TMDS_ZONE_CTRL_REG 0x4C
  127. #define HDMI_RX_TMDS_MODE_CTRL_REG 0x4D
  128. /* CBUS registers */
  129. #define CBUS_INT_STATUS_1_REG 0x08
  130. #define CBUS_INTR1_ENABLE_REG 0x09
  131. #define CBUS_MSC_REQ_ABORT_REASON_REG 0x0D
  132. #define CBUS_INT_STATUS_2_REG 0x1E
  133. #define CBUS_INTR2_ENABLE_REG 0x1F
  134. #define CBUS_LINK_CONTROL_2_REG 0x31
  135. #define CBUS_MHL_STATUS_REG_0 0xB0
  136. #define CBUS_MHL_STATUS_REG_1 0xB1
  137. #define BIT_CBUS_RESET BIT(3)
  138. #define SET_HPD_DOWNSTREAM BIT(6)
  139. /* TPI registers */
  140. #define TPI_DPD_REG 0x3D
  141. /* Timeouts in msec */
  142. #define T_SRC_VBUS_CBUS_TO_STABLE 200
  143. #define T_SRC_CBUS_FLOAT 100
  144. #define T_SRC_CBUS_DEGLITCH 2
  145. #define T_SRC_RXSENSE_DEGLITCH 110
  146. #define MHL1_MAX_CLK 75000 /* in kHz */
  147. #define I2C_TPI_ADDR 0x3D
  148. #define I2C_HDMI_ADDR 0x49
  149. #define I2C_CBUS_ADDR 0x64
  150. enum sii9234_state {
  151. ST_OFF,
  152. ST_D3,
  153. ST_RGND_INIT,
  154. ST_RGND_1K,
  155. ST_RSEN_HIGH,
  156. ST_MHL_ESTABLISHED,
  157. ST_FAILURE_DISCOVERY,
  158. ST_FAILURE,
  159. };
  160. struct sii9234 {
  161. struct i2c_client *client[4];
  162. struct drm_bridge bridge;
  163. struct device *dev;
  164. struct gpio_desc *gpio_reset;
  165. int i2c_error;
  166. struct regulator_bulk_data supplies[4];
  167. struct mutex lock; /* Protects fields below and device registers */
  168. enum sii9234_state state;
  169. };
  170. enum sii9234_client_id {
  171. I2C_MHL,
  172. I2C_TPI,
  173. I2C_HDMI,
  174. I2C_CBUS,
  175. };
  176. static const char * const sii9234_client_name[] = {
  177. [I2C_MHL] = "MHL",
  178. [I2C_TPI] = "TPI",
  179. [I2C_HDMI] = "HDMI",
  180. [I2C_CBUS] = "CBUS",
  181. };
  182. static int sii9234_writeb(struct sii9234 *ctx, int id, int offset,
  183. int value)
  184. {
  185. int ret;
  186. struct i2c_client *client = ctx->client[id];
  187. if (ctx->i2c_error)
  188. return ctx->i2c_error;
  189. ret = i2c_smbus_write_byte_data(client, offset, value);
  190. if (ret < 0)
  191. dev_err(ctx->dev, "writeb: %4s[0x%02x] <- 0x%02x\n",
  192. sii9234_client_name[id], offset, value);
  193. ctx->i2c_error = ret;
  194. return ret;
  195. }
  196. static int sii9234_writebm(struct sii9234 *ctx, int id, int offset,
  197. int value, int mask)
  198. {
  199. int ret;
  200. struct i2c_client *client = ctx->client[id];
  201. if (ctx->i2c_error)
  202. return ctx->i2c_error;
  203. ret = i2c_smbus_write_byte(client, offset);
  204. if (ret < 0) {
  205. dev_err(ctx->dev, "writebm: %4s[0x%02x] <- 0x%02x\n",
  206. sii9234_client_name[id], offset, value);
  207. ctx->i2c_error = ret;
  208. return ret;
  209. }
  210. ret = i2c_smbus_read_byte(client);
  211. if (ret < 0) {
  212. dev_err(ctx->dev, "writebm: %4s[0x%02x] <- 0x%02x\n",
  213. sii9234_client_name[id], offset, value);
  214. ctx->i2c_error = ret;
  215. return ret;
  216. }
  217. value = (value & mask) | (ret & ~mask);
  218. ret = i2c_smbus_write_byte_data(client, offset, value);
  219. if (ret < 0) {
  220. dev_err(ctx->dev, "writebm: %4s[0x%02x] <- 0x%02x\n",
  221. sii9234_client_name[id], offset, value);
  222. ctx->i2c_error = ret;
  223. }
  224. return ret;
  225. }
  226. static int sii9234_readb(struct sii9234 *ctx, int id, int offset)
  227. {
  228. int ret;
  229. struct i2c_client *client = ctx->client[id];
  230. if (ctx->i2c_error)
  231. return ctx->i2c_error;
  232. ret = i2c_smbus_write_byte(client, offset);
  233. if (ret < 0) {
  234. dev_err(ctx->dev, "readb: %4s[0x%02x]\n",
  235. sii9234_client_name[id], offset);
  236. ctx->i2c_error = ret;
  237. return ret;
  238. }
  239. ret = i2c_smbus_read_byte(client);
  240. if (ret < 0) {
  241. dev_err(ctx->dev, "readb: %4s[0x%02x]\n",
  242. sii9234_client_name[id], offset);
  243. ctx->i2c_error = ret;
  244. }
  245. return ret;
  246. }
  247. static int sii9234_clear_error(struct sii9234 *ctx)
  248. {
  249. int ret = ctx->i2c_error;
  250. ctx->i2c_error = 0;
  251. return ret;
  252. }
  253. #define mhl_tx_writeb(sii9234, offset, value) \
  254. sii9234_writeb(sii9234, I2C_MHL, offset, value)
  255. #define mhl_tx_writebm(sii9234, offset, value, mask) \
  256. sii9234_writebm(sii9234, I2C_MHL, offset, value, mask)
  257. #define mhl_tx_readb(sii9234, offset) \
  258. sii9234_readb(sii9234, I2C_MHL, offset)
  259. #define cbus_writeb(sii9234, offset, value) \
  260. sii9234_writeb(sii9234, I2C_CBUS, offset, value)
  261. #define cbus_writebm(sii9234, offset, value, mask) \
  262. sii9234_writebm(sii9234, I2C_CBUS, offset, value, mask)
  263. #define cbus_readb(sii9234, offset) \
  264. sii9234_readb(sii9234, I2C_CBUS, offset)
  265. #define hdmi_writeb(sii9234, offset, value) \
  266. sii9234_writeb(sii9234, I2C_HDMI, offset, value)
  267. #define hdmi_writebm(sii9234, offset, value, mask) \
  268. sii9234_writebm(sii9234, I2C_HDMI, offset, value, mask)
  269. #define hdmi_readb(sii9234, offset) \
  270. sii9234_readb(sii9234, I2C_HDMI, offset)
  271. #define tpi_writeb(sii9234, offset, value) \
  272. sii9234_writeb(sii9234, I2C_TPI, offset, value)
  273. #define tpi_writebm(sii9234, offset, value, mask) \
  274. sii9234_writebm(sii9234, I2C_TPI, offset, value, mask)
  275. #define tpi_readb(sii9234, offset) \
  276. sii9234_readb(sii9234, I2C_TPI, offset)
  277. static u8 sii9234_tmds_control(struct sii9234 *ctx, bool enable)
  278. {
  279. mhl_tx_writebm(ctx, MHL_TX_TMDS_CCTRL, enable ? ~0 : 0,
  280. BIT_TMDS_CCTRL_TMDS_OE);
  281. mhl_tx_writebm(ctx, MHL_TX_INT_CTRL_REG, enable ? ~0 : 0,
  282. MHL_HPD_OUT_OVR_EN | MHL_HPD_OUT_OVR_VAL);
  283. return sii9234_clear_error(ctx);
  284. }
  285. static int sii9234_cbus_reset(struct sii9234 *ctx)
  286. {
  287. int i;
  288. mhl_tx_writebm(ctx, MHL_TX_SRST, ~0, BIT_CBUS_RESET);
  289. msleep(T_SRC_CBUS_DEGLITCH);
  290. mhl_tx_writebm(ctx, MHL_TX_SRST, 0, BIT_CBUS_RESET);
  291. for (i = 0; i < 4; i++) {
  292. /*
  293. * Enable WRITE_STAT interrupt for writes to all
  294. * 4 MSC Status registers.
  295. */
  296. cbus_writeb(ctx, 0xE0 + i, 0xF2);
  297. /*
  298. * Enable SET_INT interrupt for writes to all
  299. * 4 MSC Interrupt registers.
  300. */
  301. cbus_writeb(ctx, 0xF0 + i, 0xF2);
  302. }
  303. return sii9234_clear_error(ctx);
  304. }
  305. /* Require to chek mhl imformation of samsung in cbus_init_register */
  306. static int sii9234_cbus_init(struct sii9234 *ctx)
  307. {
  308. cbus_writeb(ctx, 0x07, 0xF2);
  309. cbus_writeb(ctx, 0x40, 0x03);
  310. cbus_writeb(ctx, 0x42, 0x06);
  311. cbus_writeb(ctx, 0x36, 0x0C);
  312. cbus_writeb(ctx, 0x3D, 0xFD);
  313. cbus_writeb(ctx, 0x1C, 0x01);
  314. cbus_writeb(ctx, 0x1D, 0x0F);
  315. cbus_writeb(ctx, 0x44, 0x02);
  316. /* Setup our devcap */
  317. cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_DEV_STATE, 0x00);
  318. cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_MHL_VERSION,
  319. SII9234_MHL_VERSION);
  320. cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_CAT,
  321. MHL_DCAP_CAT_SOURCE);
  322. cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_ADOPTER_ID_H, 0x01);
  323. cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_ADOPTER_ID_L, 0x41);
  324. cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_VID_LINK_MODE,
  325. MHL_DCAP_VID_LINK_RGB444 | MHL_DCAP_VID_LINK_YCBCR444);
  326. cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_VIDEO_TYPE,
  327. MHL_DCAP_VT_GRAPHICS);
  328. cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_LOG_DEV_MAP,
  329. MHL_DCAP_LD_GUI);
  330. cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_BANDWIDTH, 0x0F);
  331. cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_FEATURE_FLAG,
  332. MHL_DCAP_FEATURE_RCP_SUPPORT | MHL_DCAP_FEATURE_RAP_SUPPORT
  333. | MHL_DCAP_FEATURE_SP_SUPPORT);
  334. cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_DEVICE_ID_H, 0x0);
  335. cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_DEVICE_ID_L, 0x0);
  336. cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_SCRATCHPAD_SIZE,
  337. SII9234_SCRATCHPAD_SIZE);
  338. cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_INT_STAT_SIZE,
  339. SII9234_INT_STAT_SIZE);
  340. cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_RESERVED, 0);
  341. cbus_writebm(ctx, 0x31, 0x0C, 0x0C);
  342. cbus_writeb(ctx, 0x30, 0x01);
  343. cbus_writebm(ctx, 0x3C, 0x30, 0x38);
  344. cbus_writebm(ctx, 0x22, 0x0D, 0x0F);
  345. cbus_writebm(ctx, 0x2E, 0x15, 0x15);
  346. cbus_writeb(ctx, CBUS_INTR1_ENABLE_REG, 0);
  347. cbus_writeb(ctx, CBUS_INTR2_ENABLE_REG, 0);
  348. return sii9234_clear_error(ctx);
  349. }
  350. static void force_usb_id_switch_open(struct sii9234 *ctx)
  351. {
  352. /* Disable CBUS discovery */
  353. mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL1_REG, 0, 0x01);
  354. /* Force USB ID switch to open */
  355. mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL6_REG, ~0, USB_ID_OVR);
  356. mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL3_REG, ~0, 0x86);
  357. /* Force upstream HPD to 0 when not in MHL mode. */
  358. mhl_tx_writebm(ctx, MHL_TX_INT_CTRL_REG, 0, 0x30);
  359. }
  360. static void release_usb_id_switch_open(struct sii9234 *ctx)
  361. {
  362. msleep(T_SRC_CBUS_FLOAT);
  363. /* Clear USB ID switch to open */
  364. mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL6_REG, 0, USB_ID_OVR);
  365. /* Enable CBUS discovery */
  366. mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL1_REG, ~0, 0x01);
  367. }
  368. static int sii9234_power_init(struct sii9234 *ctx)
  369. {
  370. /* Force the SiI9234 into the D0 state. */
  371. tpi_writeb(ctx, TPI_DPD_REG, 0x3F);
  372. /* Enable TxPLL Clock */
  373. hdmi_writeb(ctx, HDMI_RX_TMDS_CLK_EN_REG, 0x01);
  374. /* Enable Tx Clock Path & Equalizer */
  375. hdmi_writeb(ctx, HDMI_RX_TMDS_CH_EN_REG, 0x15);
  376. /* Power Up TMDS */
  377. mhl_tx_writeb(ctx, 0x08, 0x35);
  378. return sii9234_clear_error(ctx);
  379. }
  380. static int sii9234_hdmi_init(struct sii9234 *ctx)
  381. {
  382. hdmi_writeb(ctx, HDMI_RX_TMDS0_CCTRL1_REG, 0xC1);
  383. hdmi_writeb(ctx, HDMI_RX_PLL_CALREFSEL_REG, 0x03);
  384. hdmi_writeb(ctx, HDMI_RX_PLL_VCOCAL_REG, 0x20);
  385. hdmi_writeb(ctx, HDMI_RX_EQ_DATA0_REG, 0x8A);
  386. hdmi_writeb(ctx, HDMI_RX_EQ_DATA1_REG, 0x6A);
  387. hdmi_writeb(ctx, HDMI_RX_EQ_DATA2_REG, 0xAA);
  388. hdmi_writeb(ctx, HDMI_RX_EQ_DATA3_REG, 0xCA);
  389. hdmi_writeb(ctx, HDMI_RX_EQ_DATA4_REG, 0xEA);
  390. hdmi_writeb(ctx, HDMI_RX_TMDS_ZONE_CTRL_REG, 0xA0);
  391. hdmi_writeb(ctx, HDMI_RX_TMDS_MODE_CTRL_REG, 0x00);
  392. mhl_tx_writeb(ctx, MHL_TX_TMDS_CCTRL, 0x34);
  393. hdmi_writeb(ctx, 0x45, 0x44);
  394. hdmi_writeb(ctx, 0x31, 0x0A);
  395. hdmi_writeb(ctx, HDMI_RX_TMDS0_CCTRL1_REG, 0xC1);
  396. return sii9234_clear_error(ctx);
  397. }
  398. static int sii9234_mhl_tx_ctl_int(struct sii9234 *ctx)
  399. {
  400. mhl_tx_writeb(ctx, MHL_TX_MHLTX_CTL1_REG, 0xD0);
  401. mhl_tx_writeb(ctx, MHL_TX_MHLTX_CTL2_REG, 0xFC);
  402. mhl_tx_writeb(ctx, MHL_TX_MHLTX_CTL4_REG, 0xEB);
  403. mhl_tx_writeb(ctx, MHL_TX_MHLTX_CTL7_REG, 0x0C);
  404. return sii9234_clear_error(ctx);
  405. }
  406. static int sii9234_reset(struct sii9234 *ctx)
  407. {
  408. int ret;
  409. sii9234_clear_error(ctx);
  410. ret = sii9234_power_init(ctx);
  411. if (ret < 0)
  412. return ret;
  413. ret = sii9234_cbus_reset(ctx);
  414. if (ret < 0)
  415. return ret;
  416. ret = sii9234_hdmi_init(ctx);
  417. if (ret < 0)
  418. return ret;
  419. ret = sii9234_mhl_tx_ctl_int(ctx);
  420. if (ret < 0)
  421. return ret;
  422. /* Enable HDCP Compliance safety */
  423. mhl_tx_writeb(ctx, 0x2B, 0x01);
  424. /* CBUS discovery cycle time for each drive and float = 150us */
  425. mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL1_REG, 0x04, 0x06);
  426. /* Clear bit 6 (reg_skip_rgnd) */
  427. mhl_tx_writeb(ctx, MHL_TX_DISC_CTRL2_REG, (1 << 7) /* Reserved */
  428. | 2 << ATT_THRESH_SHIFT | DEGLITCH_TIME_50MS);
  429. /*
  430. * Changed from 66 to 65 for 94[1:0] = 01 = 5k reg_cbusmhl_pup_sel
  431. * 1.8V CBUS VTH & GND threshold
  432. * to meet CTS 3.3.7.2 spec
  433. */
  434. mhl_tx_writeb(ctx, MHL_TX_DISC_CTRL5_REG, 0x77);
  435. cbus_writebm(ctx, CBUS_LINK_CONTROL_2_REG, ~0, MHL_INIT_TIMEOUT);
  436. mhl_tx_writeb(ctx, MHL_TX_MHLTX_CTL6_REG, 0xA0);
  437. /* RGND & single discovery attempt (RGND blocking) */
  438. mhl_tx_writeb(ctx, MHL_TX_DISC_CTRL6_REG, BLOCK_RGND_INT |
  439. DVRFLT_SEL | SINGLE_ATT);
  440. /* Use VBUS path of discovery state machine */
  441. mhl_tx_writeb(ctx, MHL_TX_DISC_CTRL8_REG, 0);
  442. /* 0x92[3] sets the CBUS / ID switch */
  443. mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL6_REG, ~0, USB_ID_OVR);
  444. /*
  445. * To allow RGND engine to operate correctly.
  446. * When moving the chip from D2 to D0 (power up, init regs)
  447. * the values should be
  448. * 94[1:0] = 01 reg_cbusmhl_pup_sel[1:0] should be set for 5k
  449. * 93[7:6] = 10 reg_cbusdisc_pup_sel[1:0] should be
  450. * set for 10k (default)
  451. * 93[5:4] = 00 reg_cbusidle_pup_sel[1:0] = open (default)
  452. */
  453. mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL3_REG, ~0, 0x86);
  454. /*
  455. * Change from CC to 8C to match 5K
  456. * to meet CTS 3.3.72 spec
  457. */
  458. mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL4_REG, ~0, 0x8C);
  459. /* Configure the interrupt as active high */
  460. mhl_tx_writebm(ctx, MHL_TX_INT_CTRL_REG, 0, 0x06);
  461. msleep(25);
  462. /* Release usb_id switch */
  463. mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL6_REG, 0, USB_ID_OVR);
  464. mhl_tx_writeb(ctx, MHL_TX_DISC_CTRL1_REG, 0x27);
  465. ret = sii9234_clear_error(ctx);
  466. if (ret < 0)
  467. return ret;
  468. ret = sii9234_cbus_init(ctx);
  469. if (ret < 0)
  470. return ret;
  471. /* Enable Auto soft reset on SCDT = 0 */
  472. mhl_tx_writeb(ctx, 0x05, 0x04);
  473. /* HDMI Transcode mode enable */
  474. mhl_tx_writeb(ctx, 0x0D, 0x1C);
  475. mhl_tx_writeb(ctx, MHL_TX_INTR4_ENABLE_REG,
  476. RGND_READY_MASK | CBUS_LKOUT_MASK
  477. | MHL_DISC_FAIL_MASK | MHL_EST_MASK);
  478. mhl_tx_writeb(ctx, MHL_TX_INTR1_ENABLE_REG, 0x60);
  479. /* This point is very important before measure RGND impedance */
  480. force_usb_id_switch_open(ctx);
  481. mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL4_REG, 0, 0xF0);
  482. mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL5_REG, 0, 0x03);
  483. release_usb_id_switch_open(ctx);
  484. /* Force upstream HPD to 0 when not in MHL mode */
  485. mhl_tx_writebm(ctx, MHL_TX_INT_CTRL_REG, 0, 1 << 5);
  486. mhl_tx_writebm(ctx, MHL_TX_INT_CTRL_REG, ~0, 1 << 4);
  487. return sii9234_clear_error(ctx);
  488. }
  489. static int sii9234_goto_d3(struct sii9234 *ctx)
  490. {
  491. int ret;
  492. dev_dbg(ctx->dev, "sii9234: detection started d3\n");
  493. ret = sii9234_reset(ctx);
  494. if (ret < 0)
  495. goto exit;
  496. hdmi_writeb(ctx, 0x01, 0x03);
  497. tpi_writebm(ctx, TPI_DPD_REG, 0, 1);
  498. /* I2C above is expected to fail because power goes down */
  499. sii9234_clear_error(ctx);
  500. ctx->state = ST_D3;
  501. return 0;
  502. exit:
  503. dev_err(ctx->dev, "%s failed\n", __func__);
  504. return -1;
  505. }
  506. static int sii9234_hw_on(struct sii9234 *ctx)
  507. {
  508. return regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
  509. }
  510. static void sii9234_hw_off(struct sii9234 *ctx)
  511. {
  512. gpiod_set_value(ctx->gpio_reset, 1);
  513. msleep(20);
  514. regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
  515. }
  516. static void sii9234_hw_reset(struct sii9234 *ctx)
  517. {
  518. gpiod_set_value(ctx->gpio_reset, 1);
  519. msleep(20);
  520. gpiod_set_value(ctx->gpio_reset, 0);
  521. }
  522. static void sii9234_cable_in(struct sii9234 *ctx)
  523. {
  524. int ret;
  525. mutex_lock(&ctx->lock);
  526. if (ctx->state != ST_OFF)
  527. goto unlock;
  528. ret = sii9234_hw_on(ctx);
  529. if (ret < 0)
  530. goto unlock;
  531. sii9234_hw_reset(ctx);
  532. sii9234_goto_d3(ctx);
  533. /* To avoid irq storm, when hw is in meta state */
  534. enable_irq(to_i2c_client(ctx->dev)->irq);
  535. unlock:
  536. mutex_unlock(&ctx->lock);
  537. }
  538. static void sii9234_cable_out(struct sii9234 *ctx)
  539. {
  540. mutex_lock(&ctx->lock);
  541. if (ctx->state == ST_OFF)
  542. goto unlock;
  543. disable_irq(to_i2c_client(ctx->dev)->irq);
  544. tpi_writeb(ctx, TPI_DPD_REG, 0);
  545. /* Turn on&off hpd festure for only QCT HDMI */
  546. sii9234_hw_off(ctx);
  547. ctx->state = ST_OFF;
  548. unlock:
  549. mutex_unlock(&ctx->lock);
  550. }
  551. static enum sii9234_state sii9234_rgnd_ready_irq(struct sii9234 *ctx)
  552. {
  553. int value;
  554. if (ctx->state == ST_D3) {
  555. int ret;
  556. dev_dbg(ctx->dev, "RGND_READY_INT\n");
  557. sii9234_hw_reset(ctx);
  558. ret = sii9234_reset(ctx);
  559. if (ret < 0) {
  560. dev_err(ctx->dev, "sii9234_reset() failed\n");
  561. return ST_FAILURE;
  562. }
  563. return ST_RGND_INIT;
  564. }
  565. /* Got interrupt in inappropriate state */
  566. if (ctx->state != ST_RGND_INIT)
  567. return ST_FAILURE;
  568. value = mhl_tx_readb(ctx, MHL_TX_STAT2_REG);
  569. if (sii9234_clear_error(ctx))
  570. return ST_FAILURE;
  571. if ((value & RGND_INTP_MASK) != RGND_INTP_1K) {
  572. dev_warn(ctx->dev, "RGND is not 1k\n");
  573. return ST_RGND_INIT;
  574. }
  575. dev_dbg(ctx->dev, "RGND 1K!!\n");
  576. mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL4_REG, ~0, 0x8C);
  577. mhl_tx_writeb(ctx, MHL_TX_DISC_CTRL5_REG, 0x77);
  578. mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL6_REG, ~0, 0x05);
  579. if (sii9234_clear_error(ctx))
  580. return ST_FAILURE;
  581. msleep(T_SRC_VBUS_CBUS_TO_STABLE);
  582. return ST_RGND_1K;
  583. }
  584. static enum sii9234_state sii9234_mhl_established(struct sii9234 *ctx)
  585. {
  586. dev_dbg(ctx->dev, "mhl est interrupt\n");
  587. /* Discovery override */
  588. mhl_tx_writeb(ctx, MHL_TX_MHLTX_CTL1_REG, 0x10);
  589. /* Increase DDC translation layer timer (byte mode) */
  590. cbus_writeb(ctx, 0x07, 0x32);
  591. cbus_writebm(ctx, 0x44, ~0, 1 << 1);
  592. /* Keep the discovery enabled. Need RGND interrupt */
  593. mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL1_REG, ~0, 1);
  594. mhl_tx_writeb(ctx, MHL_TX_INTR1_ENABLE_REG,
  595. RSEN_CHANGE_INT_MASK | HPD_CHANGE_INT_MASK);
  596. if (sii9234_clear_error(ctx))
  597. return ST_FAILURE;
  598. return ST_MHL_ESTABLISHED;
  599. }
  600. static enum sii9234_state sii9234_hpd_change(struct sii9234 *ctx)
  601. {
  602. int value;
  603. value = cbus_readb(ctx, CBUS_MSC_REQ_ABORT_REASON_REG);
  604. if (sii9234_clear_error(ctx))
  605. return ST_FAILURE;
  606. if (value & SET_HPD_DOWNSTREAM) {
  607. /* Downstream HPD High, Enable TMDS */
  608. sii9234_tmds_control(ctx, true);
  609. } else {
  610. /* Downstream HPD Low, Disable TMDS */
  611. sii9234_tmds_control(ctx, false);
  612. }
  613. return ctx->state;
  614. }
  615. static enum sii9234_state sii9234_rsen_change(struct sii9234 *ctx)
  616. {
  617. int value;
  618. /* Work_around code to handle wrong interrupt */
  619. if (ctx->state != ST_RGND_1K) {
  620. dev_err(ctx->dev, "RSEN_HIGH without RGND_1K\n");
  621. return ST_FAILURE;
  622. }
  623. value = mhl_tx_readb(ctx, MHL_TX_SYSSTAT_REG);
  624. if (value < 0)
  625. return ST_FAILURE;
  626. if (value & RSEN_STATUS) {
  627. dev_dbg(ctx->dev, "MHL cable connected.. RSEN High\n");
  628. return ST_RSEN_HIGH;
  629. }
  630. dev_dbg(ctx->dev, "RSEN lost\n");
  631. /*
  632. * Once RSEN loss is confirmed,we need to check
  633. * based on cable status and chip power status,whether
  634. * it is SINK Loss(HDMI cable not connected, TV Off)
  635. * or MHL cable disconnection
  636. * TODO: Define the below mhl_disconnection()
  637. */
  638. msleep(T_SRC_RXSENSE_DEGLITCH);
  639. value = mhl_tx_readb(ctx, MHL_TX_SYSSTAT_REG);
  640. if (value < 0)
  641. return ST_FAILURE;
  642. dev_dbg(ctx->dev, "sys_stat: %x\n", value);
  643. if (value & RSEN_STATUS) {
  644. dev_dbg(ctx->dev, "RSEN recovery\n");
  645. return ST_RSEN_HIGH;
  646. }
  647. dev_dbg(ctx->dev, "RSEN Really LOW\n");
  648. /* To meet CTS 3.3.22.2 spec */
  649. sii9234_tmds_control(ctx, false);
  650. force_usb_id_switch_open(ctx);
  651. release_usb_id_switch_open(ctx);
  652. return ST_FAILURE;
  653. }
  654. static irqreturn_t sii9234_irq_thread(int irq, void *data)
  655. {
  656. struct sii9234 *ctx = data;
  657. int intr1, intr4;
  658. int intr1_en, intr4_en;
  659. int cbus_intr1, cbus_intr2;
  660. dev_dbg(ctx->dev, "%s\n", __func__);
  661. mutex_lock(&ctx->lock);
  662. intr1 = mhl_tx_readb(ctx, MHL_TX_INTR1_REG);
  663. intr4 = mhl_tx_readb(ctx, MHL_TX_INTR4_REG);
  664. intr1_en = mhl_tx_readb(ctx, MHL_TX_INTR1_ENABLE_REG);
  665. intr4_en = mhl_tx_readb(ctx, MHL_TX_INTR4_ENABLE_REG);
  666. cbus_intr1 = cbus_readb(ctx, CBUS_INT_STATUS_1_REG);
  667. cbus_intr2 = cbus_readb(ctx, CBUS_INT_STATUS_2_REG);
  668. if (sii9234_clear_error(ctx))
  669. goto done;
  670. dev_dbg(ctx->dev, "irq %02x/%02x %02x/%02x %02x/%02x\n",
  671. intr1, intr1_en, intr4, intr4_en, cbus_intr1, cbus_intr2);
  672. if (intr4 & RGND_READY_INT)
  673. ctx->state = sii9234_rgnd_ready_irq(ctx);
  674. if (intr1 & RSEN_CHANGE_INT)
  675. ctx->state = sii9234_rsen_change(ctx);
  676. if (intr4 & MHL_EST_INT)
  677. ctx->state = sii9234_mhl_established(ctx);
  678. if (intr1 & HPD_CHANGE_INT)
  679. ctx->state = sii9234_hpd_change(ctx);
  680. if (intr4 & CBUS_LKOUT_INT)
  681. ctx->state = ST_FAILURE;
  682. if (intr4 & MHL_DISC_FAIL_INT)
  683. ctx->state = ST_FAILURE_DISCOVERY;
  684. done:
  685. /* Clean interrupt status and pending flags */
  686. mhl_tx_writeb(ctx, MHL_TX_INTR1_REG, intr1);
  687. mhl_tx_writeb(ctx, MHL_TX_INTR4_REG, intr4);
  688. cbus_writeb(ctx, CBUS_MHL_STATUS_REG_0, 0xFF);
  689. cbus_writeb(ctx, CBUS_MHL_STATUS_REG_1, 0xFF);
  690. cbus_writeb(ctx, CBUS_INT_STATUS_1_REG, cbus_intr1);
  691. cbus_writeb(ctx, CBUS_INT_STATUS_2_REG, cbus_intr2);
  692. sii9234_clear_error(ctx);
  693. if (ctx->state == ST_FAILURE) {
  694. dev_dbg(ctx->dev, "try to reset after failure\n");
  695. sii9234_hw_reset(ctx);
  696. sii9234_goto_d3(ctx);
  697. }
  698. if (ctx->state == ST_FAILURE_DISCOVERY) {
  699. dev_err(ctx->dev, "discovery failed, no power for MHL?\n");
  700. tpi_writebm(ctx, TPI_DPD_REG, 0, 1);
  701. ctx->state = ST_D3;
  702. }
  703. mutex_unlock(&ctx->lock);
  704. return IRQ_HANDLED;
  705. }
  706. static int sii9234_init_resources(struct sii9234 *ctx,
  707. struct i2c_client *client)
  708. {
  709. struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
  710. int ret;
  711. if (!ctx->dev->of_node) {
  712. dev_err(ctx->dev, "not DT device\n");
  713. return -ENODEV;
  714. }
  715. ctx->gpio_reset = devm_gpiod_get(ctx->dev, "reset", GPIOD_OUT_LOW);
  716. if (IS_ERR(ctx->gpio_reset)) {
  717. dev_err(ctx->dev, "failed to get reset gpio from DT\n");
  718. return PTR_ERR(ctx->gpio_reset);
  719. }
  720. ctx->supplies[0].supply = "avcc12";
  721. ctx->supplies[1].supply = "avcc33";
  722. ctx->supplies[2].supply = "iovcc18";
  723. ctx->supplies[3].supply = "cvcc12";
  724. ret = devm_regulator_bulk_get(ctx->dev, 4, ctx->supplies);
  725. if (ret) {
  726. dev_err(ctx->dev, "regulator_bulk failed\n");
  727. return ret;
  728. }
  729. ctx->client[I2C_MHL] = client;
  730. ctx->client[I2C_TPI] = i2c_new_dummy(adapter, I2C_TPI_ADDR);
  731. if (!ctx->client[I2C_TPI]) {
  732. dev_err(ctx->dev, "failed to create TPI client\n");
  733. return -ENODEV;
  734. }
  735. ctx->client[I2C_HDMI] = i2c_new_dummy(adapter, I2C_HDMI_ADDR);
  736. if (!ctx->client[I2C_HDMI]) {
  737. dev_err(ctx->dev, "failed to create HDMI RX client\n");
  738. goto fail_tpi;
  739. }
  740. ctx->client[I2C_CBUS] = i2c_new_dummy(adapter, I2C_CBUS_ADDR);
  741. if (!ctx->client[I2C_CBUS]) {
  742. dev_err(ctx->dev, "failed to create CBUS client\n");
  743. goto fail_hdmi;
  744. }
  745. return 0;
  746. fail_hdmi:
  747. i2c_unregister_device(ctx->client[I2C_HDMI]);
  748. fail_tpi:
  749. i2c_unregister_device(ctx->client[I2C_TPI]);
  750. return -ENODEV;
  751. }
  752. static void sii9234_deinit_resources(struct sii9234 *ctx)
  753. {
  754. i2c_unregister_device(ctx->client[I2C_CBUS]);
  755. i2c_unregister_device(ctx->client[I2C_HDMI]);
  756. i2c_unregister_device(ctx->client[I2C_TPI]);
  757. }
  758. static inline struct sii9234 *bridge_to_sii9234(struct drm_bridge *bridge)
  759. {
  760. return container_of(bridge, struct sii9234, bridge);
  761. }
  762. static enum drm_mode_status sii9234_mode_valid(struct drm_bridge *bridge,
  763. const struct drm_display_mode *mode)
  764. {
  765. if (mode->clock > MHL1_MAX_CLK)
  766. return MODE_CLOCK_HIGH;
  767. return MODE_OK;
  768. }
  769. static const struct drm_bridge_funcs sii9234_bridge_funcs = {
  770. .mode_valid = sii9234_mode_valid,
  771. };
  772. static int sii9234_probe(struct i2c_client *client,
  773. const struct i2c_device_id *id)
  774. {
  775. struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
  776. struct sii9234 *ctx;
  777. struct device *dev = &client->dev;
  778. int ret;
  779. ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
  780. if (!ctx)
  781. return -ENOMEM;
  782. ctx->dev = dev;
  783. mutex_init(&ctx->lock);
  784. if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
  785. dev_err(dev, "I2C adapter lacks SMBUS feature\n");
  786. return -EIO;
  787. }
  788. if (!client->irq) {
  789. dev_err(dev, "no irq provided\n");
  790. return -EINVAL;
  791. }
  792. irq_set_status_flags(client->irq, IRQ_NOAUTOEN);
  793. ret = devm_request_threaded_irq(dev, client->irq, NULL,
  794. sii9234_irq_thread,
  795. IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
  796. "sii9234", ctx);
  797. if (ret < 0) {
  798. dev_err(dev, "failed to install IRQ handler\n");
  799. return ret;
  800. }
  801. ret = sii9234_init_resources(ctx, client);
  802. if (ret < 0)
  803. return ret;
  804. i2c_set_clientdata(client, ctx);
  805. ctx->bridge.funcs = &sii9234_bridge_funcs;
  806. ctx->bridge.of_node = dev->of_node;
  807. drm_bridge_add(&ctx->bridge);
  808. sii9234_cable_in(ctx);
  809. return 0;
  810. }
  811. static int sii9234_remove(struct i2c_client *client)
  812. {
  813. struct sii9234 *ctx = i2c_get_clientdata(client);
  814. sii9234_cable_out(ctx);
  815. drm_bridge_remove(&ctx->bridge);
  816. sii9234_deinit_resources(ctx);
  817. return 0;
  818. }
  819. static const struct of_device_id sii9234_dt_match[] = {
  820. { .compatible = "sil,sii9234" },
  821. { },
  822. };
  823. MODULE_DEVICE_TABLE(of, sii9234_dt_match);
  824. static const struct i2c_device_id sii9234_id[] = {
  825. { "SII9234", 0 },
  826. { },
  827. };
  828. MODULE_DEVICE_TABLE(i2c, sii9234_id);
  829. static struct i2c_driver sii9234_driver = {
  830. .driver = {
  831. .name = "sii9234",
  832. .of_match_table = sii9234_dt_match,
  833. },
  834. .probe = sii9234_probe,
  835. .remove = sii9234_remove,
  836. .id_table = sii9234_id,
  837. };
  838. module_i2c_driver(sii9234_driver);
  839. MODULE_LICENSE("GPL");