1bc1aee7fSJitao Shi // SPDX-License-Identifier: GPL-2.0-only 2bc1aee7fSJitao Shi /* 3bc1aee7fSJitao Shi * Copyright (c) 2016 MediaTek Inc. 4bc1aee7fSJitao Shi */ 5bc1aee7fSJitao Shi 6bc1aee7fSJitao Shi #include <linux/delay.h> 7bc1aee7fSJitao Shi #include <linux/err.h> 8bc1aee7fSJitao Shi #include <linux/gpio/consumer.h> 9bc1aee7fSJitao Shi #include <linux/i2c.h> 10bc1aee7fSJitao Shi #include <linux/module.h> 11bc1aee7fSJitao Shi #include <linux/of_graph.h> 12bc1aee7fSJitao Shi #include <linux/regulator/consumer.h> 13bc1aee7fSJitao Shi 14bc1aee7fSJitao Shi #include <drm/drm_bridge.h> 15bc1aee7fSJitao Shi #include <drm/drm_mipi_dsi.h> 16bc1aee7fSJitao Shi #include <drm/drm_of.h> 17bc1aee7fSJitao Shi #include <drm/drm_panel.h> 18bc1aee7fSJitao Shi #include <drm/drm_print.h> 19bc1aee7fSJitao Shi 20bc1aee7fSJitao Shi #define PAGE2_GPIO_H 0xa7 21bc1aee7fSJitao Shi #define PS_GPIO9 BIT(1) 22bc1aee7fSJitao Shi #define PAGE2_I2C_BYPASS 0xea 23bc1aee7fSJitao Shi #define I2C_BYPASS_EN 0xd0 24bc1aee7fSJitao Shi #define PAGE2_MCS_EN 0xf3 25bc1aee7fSJitao Shi #define MCS_EN BIT(0) 26bc1aee7fSJitao Shi #define PAGE3_SET_ADD 0xfe 27bc1aee7fSJitao Shi #define VDO_CTL_ADD 0x13 28bc1aee7fSJitao Shi #define VDO_DIS 0x18 29bc1aee7fSJitao Shi #define VDO_EN 0x1c 30bc1aee7fSJitao Shi #define DP_NUM_LANES 4 31bc1aee7fSJitao Shi 32bc1aee7fSJitao Shi /* 33bc1aee7fSJitao Shi * PS8640 uses multiple addresses: 34bc1aee7fSJitao Shi * page[0]: for DP control 35bc1aee7fSJitao Shi * page[1]: for VIDEO Bridge 36bc1aee7fSJitao Shi * page[2]: for control top 37bc1aee7fSJitao Shi * page[3]: for DSI Link Control1 38bc1aee7fSJitao Shi * page[4]: for MIPI Phy 39bc1aee7fSJitao Shi * page[5]: for VPLL 40bc1aee7fSJitao Shi * page[6]: for DSI Link Control2 41bc1aee7fSJitao Shi * page[7]: for SPI ROM mapping 42bc1aee7fSJitao Shi */ 43bc1aee7fSJitao Shi enum page_addr_offset { 44bc1aee7fSJitao Shi PAGE0_DP_CNTL = 0, 45bc1aee7fSJitao Shi PAGE1_VDO_BDG, 46bc1aee7fSJitao Shi PAGE2_TOP_CNTL, 47bc1aee7fSJitao Shi PAGE3_DSI_CNTL1, 48bc1aee7fSJitao Shi PAGE4_MIPI_PHY, 49bc1aee7fSJitao Shi PAGE5_VPLL, 50bc1aee7fSJitao Shi PAGE6_DSI_CNTL2, 51bc1aee7fSJitao Shi PAGE7_SPI_CNTL, 52bc1aee7fSJitao Shi MAX_DEVS 53bc1aee7fSJitao Shi }; 54bc1aee7fSJitao Shi 55bc1aee7fSJitao Shi enum ps8640_vdo_control { 56bc1aee7fSJitao Shi DISABLE = VDO_DIS, 57bc1aee7fSJitao Shi ENABLE = VDO_EN, 58bc1aee7fSJitao Shi }; 59bc1aee7fSJitao Shi 60bc1aee7fSJitao Shi struct ps8640 { 61bc1aee7fSJitao Shi struct drm_bridge bridge; 62bc1aee7fSJitao Shi struct drm_bridge *panel_bridge; 63bc1aee7fSJitao Shi struct mipi_dsi_device *dsi; 64bc1aee7fSJitao Shi struct i2c_client *page[MAX_DEVS]; 65bc1aee7fSJitao Shi struct regulator_bulk_data supplies[2]; 66bc1aee7fSJitao Shi struct gpio_desc *gpio_reset; 67bc1aee7fSJitao Shi struct gpio_desc *gpio_powerdown; 68*46f20630SEnric Balletbo i Serra bool powered; 69bc1aee7fSJitao Shi }; 70bc1aee7fSJitao Shi 71bc1aee7fSJitao Shi static inline struct ps8640 *bridge_to_ps8640(struct drm_bridge *e) 72bc1aee7fSJitao Shi { 73bc1aee7fSJitao Shi return container_of(e, struct ps8640, bridge); 74bc1aee7fSJitao Shi } 75bc1aee7fSJitao Shi 76bc1aee7fSJitao Shi static int ps8640_bridge_vdo_control(struct ps8640 *ps_bridge, 77bc1aee7fSJitao Shi const enum ps8640_vdo_control ctrl) 78bc1aee7fSJitao Shi { 79bc1aee7fSJitao Shi struct i2c_client *client = ps_bridge->page[PAGE3_DSI_CNTL1]; 80bc1aee7fSJitao Shi u8 vdo_ctrl_buf[] = { VDO_CTL_ADD, ctrl }; 81bc1aee7fSJitao Shi int ret; 82bc1aee7fSJitao Shi 83bc1aee7fSJitao Shi ret = i2c_smbus_write_i2c_block_data(client, PAGE3_SET_ADD, 84bc1aee7fSJitao Shi sizeof(vdo_ctrl_buf), 85bc1aee7fSJitao Shi vdo_ctrl_buf); 8694d4c132SEnric Balletbo i Serra if (ret < 0) { 8794d4c132SEnric Balletbo i Serra DRM_ERROR("failed to %sable VDO: %d\n", 8894d4c132SEnric Balletbo i Serra ctrl == ENABLE ? "en" : "dis", ret); 89bc1aee7fSJitao Shi return ret; 9094d4c132SEnric Balletbo i Serra } 91bc1aee7fSJitao Shi 92bc1aee7fSJitao Shi return 0; 93bc1aee7fSJitao Shi } 94bc1aee7fSJitao Shi 95*46f20630SEnric Balletbo i Serra static void ps8640_bridge_poweron(struct ps8640 *ps_bridge) 96bc1aee7fSJitao Shi { 97bc1aee7fSJitao Shi struct i2c_client *client = ps_bridge->page[PAGE2_TOP_CNTL]; 98bc1aee7fSJitao Shi unsigned long timeout; 99bc1aee7fSJitao Shi int ret, status; 100bc1aee7fSJitao Shi 101*46f20630SEnric Balletbo i Serra if (ps_bridge->powered) 102*46f20630SEnric Balletbo i Serra return; 103*46f20630SEnric Balletbo i Serra 104bc1aee7fSJitao Shi ret = regulator_bulk_enable(ARRAY_SIZE(ps_bridge->supplies), 105bc1aee7fSJitao Shi ps_bridge->supplies); 106bc1aee7fSJitao Shi if (ret < 0) { 107bc1aee7fSJitao Shi DRM_ERROR("cannot enable regulators %d\n", ret); 108bc1aee7fSJitao Shi return; 109bc1aee7fSJitao Shi } 110bc1aee7fSJitao Shi 111bc1aee7fSJitao Shi gpiod_set_value(ps_bridge->gpio_powerdown, 0); 112bc1aee7fSJitao Shi gpiod_set_value(ps_bridge->gpio_reset, 1); 113bc1aee7fSJitao Shi usleep_range(2000, 2500); 114bc1aee7fSJitao Shi gpiod_set_value(ps_bridge->gpio_reset, 0); 115bc1aee7fSJitao Shi 116bc1aee7fSJitao Shi /* 117bc1aee7fSJitao Shi * Wait for the ps8640 embedded MCU to be ready 118bc1aee7fSJitao Shi * First wait 200ms and then check the MCU ready flag every 20ms 119bc1aee7fSJitao Shi */ 120bc1aee7fSJitao Shi msleep(200); 121bc1aee7fSJitao Shi 122bc1aee7fSJitao Shi timeout = jiffies + msecs_to_jiffies(200) + 1; 123bc1aee7fSJitao Shi 124bc1aee7fSJitao Shi while (time_is_after_jiffies(timeout)) { 125bc1aee7fSJitao Shi status = i2c_smbus_read_byte_data(client, PAGE2_GPIO_H); 126bc1aee7fSJitao Shi if (status < 0) { 127bc1aee7fSJitao Shi DRM_ERROR("failed read PAGE2_GPIO_H: %d\n", status); 128bc1aee7fSJitao Shi goto err_regulators_disable; 129bc1aee7fSJitao Shi } 130bc1aee7fSJitao Shi if ((status & PS_GPIO9) == PS_GPIO9) 131bc1aee7fSJitao Shi break; 132bc1aee7fSJitao Shi 133bc1aee7fSJitao Shi msleep(20); 134bc1aee7fSJitao Shi } 135bc1aee7fSJitao Shi 136bc1aee7fSJitao Shi msleep(50); 137bc1aee7fSJitao Shi 138bc1aee7fSJitao Shi /* 139bc1aee7fSJitao Shi * The Manufacturer Command Set (MCS) is a device dependent interface 140bc1aee7fSJitao Shi * intended for factory programming of the display module default 141bc1aee7fSJitao Shi * parameters. Once the display module is configured, the MCS shall be 142bc1aee7fSJitao Shi * disabled by the manufacturer. Once disabled, all MCS commands are 143bc1aee7fSJitao Shi * ignored by the display interface. 144bc1aee7fSJitao Shi */ 145bc1aee7fSJitao Shi status = i2c_smbus_read_byte_data(client, PAGE2_MCS_EN); 146bc1aee7fSJitao Shi if (status < 0) { 147bc1aee7fSJitao Shi DRM_ERROR("failed read PAGE2_MCS_EN: %d\n", status); 148bc1aee7fSJitao Shi goto err_regulators_disable; 149bc1aee7fSJitao Shi } 150bc1aee7fSJitao Shi 151bc1aee7fSJitao Shi ret = i2c_smbus_write_byte_data(client, PAGE2_MCS_EN, 152bc1aee7fSJitao Shi status & ~MCS_EN); 153bc1aee7fSJitao Shi if (ret < 0) { 154bc1aee7fSJitao Shi DRM_ERROR("failed write PAGE2_MCS_EN: %d\n", ret); 155bc1aee7fSJitao Shi goto err_regulators_disable; 156bc1aee7fSJitao Shi } 157bc1aee7fSJitao Shi 158bc1aee7fSJitao Shi /* Switch access edp panel's edid through i2c */ 159bc1aee7fSJitao Shi ret = i2c_smbus_write_byte_data(client, PAGE2_I2C_BYPASS, 160bc1aee7fSJitao Shi I2C_BYPASS_EN); 161bc1aee7fSJitao Shi if (ret < 0) { 162bc1aee7fSJitao Shi DRM_ERROR("failed write PAGE2_I2C_BYPASS: %d\n", ret); 163bc1aee7fSJitao Shi goto err_regulators_disable; 164bc1aee7fSJitao Shi } 165bc1aee7fSJitao Shi 166*46f20630SEnric Balletbo i Serra ps_bridge->powered = true; 167*46f20630SEnric Balletbo i Serra 168bc1aee7fSJitao Shi return; 169bc1aee7fSJitao Shi 170bc1aee7fSJitao Shi err_regulators_disable: 171bc1aee7fSJitao Shi regulator_bulk_disable(ARRAY_SIZE(ps_bridge->supplies), 172bc1aee7fSJitao Shi ps_bridge->supplies); 173bc1aee7fSJitao Shi } 174bc1aee7fSJitao Shi 175*46f20630SEnric Balletbo i Serra static void ps8640_bridge_poweroff(struct ps8640 *ps_bridge) 176bc1aee7fSJitao Shi { 177bc1aee7fSJitao Shi int ret; 178bc1aee7fSJitao Shi 179*46f20630SEnric Balletbo i Serra if (!ps_bridge->powered) 180*46f20630SEnric Balletbo i Serra return; 181bc1aee7fSJitao Shi 182bc1aee7fSJitao Shi gpiod_set_value(ps_bridge->gpio_reset, 1); 183bc1aee7fSJitao Shi gpiod_set_value(ps_bridge->gpio_powerdown, 1); 184bc1aee7fSJitao Shi ret = regulator_bulk_disable(ARRAY_SIZE(ps_bridge->supplies), 185bc1aee7fSJitao Shi ps_bridge->supplies); 186bc1aee7fSJitao Shi if (ret < 0) 187bc1aee7fSJitao Shi DRM_ERROR("cannot disable regulators %d\n", ret); 188*46f20630SEnric Balletbo i Serra 189*46f20630SEnric Balletbo i Serra ps_bridge->powered = false; 190*46f20630SEnric Balletbo i Serra } 191*46f20630SEnric Balletbo i Serra 192*46f20630SEnric Balletbo i Serra static void ps8640_pre_enable(struct drm_bridge *bridge) 193*46f20630SEnric Balletbo i Serra { 194*46f20630SEnric Balletbo i Serra struct ps8640 *ps_bridge = bridge_to_ps8640(bridge); 195*46f20630SEnric Balletbo i Serra int ret; 196*46f20630SEnric Balletbo i Serra 197*46f20630SEnric Balletbo i Serra ps8640_bridge_poweron(ps_bridge); 198*46f20630SEnric Balletbo i Serra 199*46f20630SEnric Balletbo i Serra ret = ps8640_bridge_vdo_control(ps_bridge, ENABLE); 200*46f20630SEnric Balletbo i Serra if (ret < 0) 201*46f20630SEnric Balletbo i Serra ps8640_bridge_poweroff(ps_bridge); 202*46f20630SEnric Balletbo i Serra } 203*46f20630SEnric Balletbo i Serra 204*46f20630SEnric Balletbo i Serra static void ps8640_post_disable(struct drm_bridge *bridge) 205*46f20630SEnric Balletbo i Serra { 206*46f20630SEnric Balletbo i Serra struct ps8640 *ps_bridge = bridge_to_ps8640(bridge); 207*46f20630SEnric Balletbo i Serra 208*46f20630SEnric Balletbo i Serra ps8640_bridge_vdo_control(ps_bridge, DISABLE); 209*46f20630SEnric Balletbo i Serra ps8640_bridge_poweroff(ps_bridge); 210bc1aee7fSJitao Shi } 211bc1aee7fSJitao Shi 212a25b988fSLaurent Pinchart static int ps8640_bridge_attach(struct drm_bridge *bridge, 213a25b988fSLaurent Pinchart enum drm_bridge_attach_flags flags) 214bc1aee7fSJitao Shi { 215bc1aee7fSJitao Shi struct ps8640 *ps_bridge = bridge_to_ps8640(bridge); 216bc1aee7fSJitao Shi struct device *dev = &ps_bridge->page[0]->dev; 217bc1aee7fSJitao Shi struct device_node *in_ep, *dsi_node; 218bc1aee7fSJitao Shi struct mipi_dsi_device *dsi; 219bc1aee7fSJitao Shi struct mipi_dsi_host *host; 220bc1aee7fSJitao Shi int ret; 221bc1aee7fSJitao Shi const struct mipi_dsi_device_info info = { .type = "ps8640", 222bc1aee7fSJitao Shi .channel = 0, 223bc1aee7fSJitao Shi .node = NULL, 224bc1aee7fSJitao Shi }; 225812a65baSEnric Balletbo i Serra 226812a65baSEnric Balletbo i Serra if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) 227812a65baSEnric Balletbo i Serra return -EINVAL; 228812a65baSEnric Balletbo i Serra 229bc1aee7fSJitao Shi /* port@0 is ps8640 dsi input port */ 230bc1aee7fSJitao Shi in_ep = of_graph_get_endpoint_by_regs(dev->of_node, 0, -1); 231bc1aee7fSJitao Shi if (!in_ep) 232bc1aee7fSJitao Shi return -ENODEV; 233bc1aee7fSJitao Shi 234bc1aee7fSJitao Shi dsi_node = of_graph_get_remote_port_parent(in_ep); 235bc1aee7fSJitao Shi of_node_put(in_ep); 236bc1aee7fSJitao Shi if (!dsi_node) 237bc1aee7fSJitao Shi return -ENODEV; 238bc1aee7fSJitao Shi 239bc1aee7fSJitao Shi host = of_find_mipi_dsi_host_by_node(dsi_node); 240bc1aee7fSJitao Shi of_node_put(dsi_node); 241bc1aee7fSJitao Shi if (!host) 242bc1aee7fSJitao Shi return -ENODEV; 243bc1aee7fSJitao Shi 244bc1aee7fSJitao Shi dsi = mipi_dsi_device_register_full(host, &info); 245bc1aee7fSJitao Shi if (IS_ERR(dsi)) { 246bc1aee7fSJitao Shi dev_err(dev, "failed to create dsi device\n"); 247bc1aee7fSJitao Shi ret = PTR_ERR(dsi); 248bc1aee7fSJitao Shi return ret; 249bc1aee7fSJitao Shi } 250bc1aee7fSJitao Shi 251bc1aee7fSJitao Shi ps_bridge->dsi = dsi; 252bc1aee7fSJitao Shi 253bc1aee7fSJitao Shi dsi->host = host; 254bc1aee7fSJitao Shi dsi->mode_flags = MIPI_DSI_MODE_VIDEO | 255bc1aee7fSJitao Shi MIPI_DSI_MODE_VIDEO_SYNC_PULSE; 256bc1aee7fSJitao Shi dsi->format = MIPI_DSI_FMT_RGB888; 257bc1aee7fSJitao Shi dsi->lanes = DP_NUM_LANES; 258bc1aee7fSJitao Shi ret = mipi_dsi_attach(dsi); 259bc1aee7fSJitao Shi if (ret) 260bc1aee7fSJitao Shi goto err_dsi_attach; 261bc1aee7fSJitao Shi 262bc1aee7fSJitao Shi /* Attach the panel-bridge to the dsi bridge */ 263bc1aee7fSJitao Shi return drm_bridge_attach(bridge->encoder, ps_bridge->panel_bridge, 264a25b988fSLaurent Pinchart &ps_bridge->bridge, flags); 265bc1aee7fSJitao Shi 266bc1aee7fSJitao Shi err_dsi_attach: 267bc1aee7fSJitao Shi mipi_dsi_device_unregister(dsi); 268bc1aee7fSJitao Shi return ret; 269bc1aee7fSJitao Shi } 270bc1aee7fSJitao Shi 271d82c12abSEnric Balletbo i Serra static struct edid *ps8640_bridge_get_edid(struct drm_bridge *bridge, 272d82c12abSEnric Balletbo i Serra struct drm_connector *connector) 273d82c12abSEnric Balletbo i Serra { 274d82c12abSEnric Balletbo i Serra struct ps8640 *ps_bridge = bridge_to_ps8640(bridge); 275*46f20630SEnric Balletbo i Serra bool poweroff = !ps_bridge->powered; 276*46f20630SEnric Balletbo i Serra struct edid *edid; 277d82c12abSEnric Balletbo i Serra 278*46f20630SEnric Balletbo i Serra /* 279*46f20630SEnric Balletbo i Serra * When we end calling get_edid() triggered by an ioctl, i.e 280*46f20630SEnric Balletbo i Serra * 281*46f20630SEnric Balletbo i Serra * drm_mode_getconnector (ioctl) 282*46f20630SEnric Balletbo i Serra * -> drm_helper_probe_single_connector_modes 283*46f20630SEnric Balletbo i Serra * -> drm_bridge_connector_get_modes 284*46f20630SEnric Balletbo i Serra * -> ps8640_bridge_get_edid 285*46f20630SEnric Balletbo i Serra * 286*46f20630SEnric Balletbo i Serra * We need to make sure that what we need is enabled before reading 287*46f20630SEnric Balletbo i Serra * EDID, for this chip, we need to do a full poweron, otherwise it will 288*46f20630SEnric Balletbo i Serra * fail. 289*46f20630SEnric Balletbo i Serra */ 290*46f20630SEnric Balletbo i Serra drm_bridge_chain_pre_enable(bridge); 291*46f20630SEnric Balletbo i Serra 292*46f20630SEnric Balletbo i Serra edid = drm_get_edid(connector, 293d82c12abSEnric Balletbo i Serra ps_bridge->page[PAGE0_DP_CNTL]->adapter); 294*46f20630SEnric Balletbo i Serra 295*46f20630SEnric Balletbo i Serra /* 296*46f20630SEnric Balletbo i Serra * If we call the get_edid() function without having enabled the chip 297*46f20630SEnric Balletbo i Serra * before, return the chip to its original power state. 298*46f20630SEnric Balletbo i Serra */ 299*46f20630SEnric Balletbo i Serra if (poweroff) 300*46f20630SEnric Balletbo i Serra drm_bridge_chain_post_disable(bridge); 301*46f20630SEnric Balletbo i Serra 302*46f20630SEnric Balletbo i Serra return edid; 303d82c12abSEnric Balletbo i Serra } 304d82c12abSEnric Balletbo i Serra 305bc1aee7fSJitao Shi static const struct drm_bridge_funcs ps8640_bridge_funcs = { 306bc1aee7fSJitao Shi .attach = ps8640_bridge_attach, 307d82c12abSEnric Balletbo i Serra .get_edid = ps8640_bridge_get_edid, 308bc1aee7fSJitao Shi .post_disable = ps8640_post_disable, 309bc1aee7fSJitao Shi .pre_enable = ps8640_pre_enable, 310bc1aee7fSJitao Shi }; 311bc1aee7fSJitao Shi 312bc1aee7fSJitao Shi static int ps8640_probe(struct i2c_client *client) 313bc1aee7fSJitao Shi { 314bc1aee7fSJitao Shi struct device *dev = &client->dev; 315bc1aee7fSJitao Shi struct device_node *np = dev->of_node; 316bc1aee7fSJitao Shi struct ps8640 *ps_bridge; 317bc1aee7fSJitao Shi struct drm_panel *panel; 318bc1aee7fSJitao Shi int ret; 319bc1aee7fSJitao Shi u32 i; 320bc1aee7fSJitao Shi 321bc1aee7fSJitao Shi ps_bridge = devm_kzalloc(dev, sizeof(*ps_bridge), GFP_KERNEL); 322bc1aee7fSJitao Shi if (!ps_bridge) 323bc1aee7fSJitao Shi return -ENOMEM; 324bc1aee7fSJitao Shi 325bc1aee7fSJitao Shi /* port@1 is ps8640 output port */ 326bc1aee7fSJitao Shi ret = drm_of_find_panel_or_bridge(np, 1, 0, &panel, NULL); 327bc1aee7fSJitao Shi if (ret < 0) 328bc1aee7fSJitao Shi return ret; 329bc1aee7fSJitao Shi if (!panel) 330bc1aee7fSJitao Shi return -ENODEV; 331bc1aee7fSJitao Shi 332bc1aee7fSJitao Shi ps_bridge->panel_bridge = devm_drm_panel_bridge_add(dev, panel); 333bc1aee7fSJitao Shi if (IS_ERR(ps_bridge->panel_bridge)) 334bc1aee7fSJitao Shi return PTR_ERR(ps_bridge->panel_bridge); 335bc1aee7fSJitao Shi 336bc1aee7fSJitao Shi ps_bridge->supplies[0].supply = "vdd33"; 337bc1aee7fSJitao Shi ps_bridge->supplies[1].supply = "vdd12"; 338bc1aee7fSJitao Shi ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ps_bridge->supplies), 339bc1aee7fSJitao Shi ps_bridge->supplies); 340bc1aee7fSJitao Shi if (ret) 341bc1aee7fSJitao Shi return ret; 342bc1aee7fSJitao Shi 343bc1aee7fSJitao Shi ps_bridge->gpio_powerdown = devm_gpiod_get(&client->dev, "powerdown", 344bc1aee7fSJitao Shi GPIOD_OUT_HIGH); 345bc1aee7fSJitao Shi if (IS_ERR(ps_bridge->gpio_powerdown)) 346bc1aee7fSJitao Shi return PTR_ERR(ps_bridge->gpio_powerdown); 347bc1aee7fSJitao Shi 348bc1aee7fSJitao Shi /* 349bc1aee7fSJitao Shi * Assert the reset to avoid the bridge being initialized prematurely 350bc1aee7fSJitao Shi */ 351bc1aee7fSJitao Shi ps_bridge->gpio_reset = devm_gpiod_get(&client->dev, "reset", 352bc1aee7fSJitao Shi GPIOD_OUT_HIGH); 353bc1aee7fSJitao Shi if (IS_ERR(ps_bridge->gpio_reset)) 354bc1aee7fSJitao Shi return PTR_ERR(ps_bridge->gpio_reset); 355bc1aee7fSJitao Shi 356bc1aee7fSJitao Shi ps_bridge->bridge.funcs = &ps8640_bridge_funcs; 357bc1aee7fSJitao Shi ps_bridge->bridge.of_node = dev->of_node; 358d82c12abSEnric Balletbo i Serra ps_bridge->bridge.ops = DRM_BRIDGE_OP_EDID; 359d82c12abSEnric Balletbo i Serra ps_bridge->bridge.type = DRM_MODE_CONNECTOR_eDP; 360bc1aee7fSJitao Shi 361bc1aee7fSJitao Shi ps_bridge->page[PAGE0_DP_CNTL] = client; 362bc1aee7fSJitao Shi 363bc1aee7fSJitao Shi for (i = 1; i < ARRAY_SIZE(ps_bridge->page); i++) { 364bc1aee7fSJitao Shi ps_bridge->page[i] = devm_i2c_new_dummy_device(&client->dev, 365bc1aee7fSJitao Shi client->adapter, 366bc1aee7fSJitao Shi client->addr + i); 367bc1aee7fSJitao Shi if (IS_ERR(ps_bridge->page[i])) { 368bc1aee7fSJitao Shi dev_err(dev, "failed i2c dummy device, address %02x\n", 369bc1aee7fSJitao Shi client->addr + i); 370bc1aee7fSJitao Shi return PTR_ERR(ps_bridge->page[i]); 371bc1aee7fSJitao Shi } 372bc1aee7fSJitao Shi } 373bc1aee7fSJitao Shi 374bc1aee7fSJitao Shi i2c_set_clientdata(client, ps_bridge); 375bc1aee7fSJitao Shi 376bc1aee7fSJitao Shi drm_bridge_add(&ps_bridge->bridge); 377bc1aee7fSJitao Shi 378bc1aee7fSJitao Shi return 0; 379bc1aee7fSJitao Shi } 380bc1aee7fSJitao Shi 381bc1aee7fSJitao Shi static int ps8640_remove(struct i2c_client *client) 382bc1aee7fSJitao Shi { 383bc1aee7fSJitao Shi struct ps8640 *ps_bridge = i2c_get_clientdata(client); 384bc1aee7fSJitao Shi 385bc1aee7fSJitao Shi drm_bridge_remove(&ps_bridge->bridge); 386bc1aee7fSJitao Shi 387bc1aee7fSJitao Shi return 0; 388bc1aee7fSJitao Shi } 389bc1aee7fSJitao Shi 390bc1aee7fSJitao Shi static const struct of_device_id ps8640_match[] = { 391bc1aee7fSJitao Shi { .compatible = "parade,ps8640" }, 392bc1aee7fSJitao Shi { } 393bc1aee7fSJitao Shi }; 394bc1aee7fSJitao Shi MODULE_DEVICE_TABLE(of, ps8640_match); 395bc1aee7fSJitao Shi 396bc1aee7fSJitao Shi static struct i2c_driver ps8640_driver = { 397bc1aee7fSJitao Shi .probe_new = ps8640_probe, 398bc1aee7fSJitao Shi .remove = ps8640_remove, 399bc1aee7fSJitao Shi .driver = { 400bc1aee7fSJitao Shi .name = "ps8640", 401bc1aee7fSJitao Shi .of_match_table = ps8640_match, 402bc1aee7fSJitao Shi }, 403bc1aee7fSJitao Shi }; 404bc1aee7fSJitao Shi module_i2c_driver(ps8640_driver); 405bc1aee7fSJitao Shi 406bc1aee7fSJitao Shi MODULE_AUTHOR("Jitao Shi <jitao.shi@mediatek.com>"); 407bc1aee7fSJitao Shi MODULE_AUTHOR("CK Hu <ck.hu@mediatek.com>"); 408bc1aee7fSJitao Shi MODULE_AUTHOR("Enric Balletbo i Serra <enric.balletbo@collabora.com>"); 409bc1aee7fSJitao Shi MODULE_DESCRIPTION("PARADE ps8640 DSI-eDP converter driver"); 410bc1aee7fSJitao Shi MODULE_LICENSE("GPL v2"); 411