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> 12*692d8db0SPhilip Chen #include <linux/regmap.h> 13bc1aee7fSJitao Shi #include <linux/regulator/consumer.h> 14bc1aee7fSJitao Shi 15bc1aee7fSJitao Shi #include <drm/drm_bridge.h> 16bc1aee7fSJitao Shi #include <drm/drm_mipi_dsi.h> 17bc1aee7fSJitao Shi #include <drm/drm_of.h> 18bc1aee7fSJitao Shi #include <drm/drm_panel.h> 19bc1aee7fSJitao Shi #include <drm/drm_print.h> 20bc1aee7fSJitao Shi 21bc1aee7fSJitao Shi #define PAGE2_GPIO_H 0xa7 22bc1aee7fSJitao Shi #define PS_GPIO9 BIT(1) 23bc1aee7fSJitao Shi #define PAGE2_I2C_BYPASS 0xea 24bc1aee7fSJitao Shi #define I2C_BYPASS_EN 0xd0 25bc1aee7fSJitao Shi #define PAGE2_MCS_EN 0xf3 26bc1aee7fSJitao Shi #define MCS_EN BIT(0) 2728210a3fSPhilip Chen 28bc1aee7fSJitao Shi #define PAGE3_SET_ADD 0xfe 29bc1aee7fSJitao Shi #define VDO_CTL_ADD 0x13 30bc1aee7fSJitao Shi #define VDO_DIS 0x18 31bc1aee7fSJitao Shi #define VDO_EN 0x1c 3228210a3fSPhilip Chen 3328210a3fSPhilip Chen #define NUM_MIPI_LANES 4 34bc1aee7fSJitao Shi 35*692d8db0SPhilip Chen #define COMMON_PS8640_REGMAP_CONFIG \ 36*692d8db0SPhilip Chen .reg_bits = 8, \ 37*692d8db0SPhilip Chen .val_bits = 8, \ 38*692d8db0SPhilip Chen .cache_type = REGCACHE_NONE 39*692d8db0SPhilip Chen 40bc1aee7fSJitao Shi /* 41bc1aee7fSJitao Shi * PS8640 uses multiple addresses: 42bc1aee7fSJitao Shi * page[0]: for DP control 43bc1aee7fSJitao Shi * page[1]: for VIDEO Bridge 44bc1aee7fSJitao Shi * page[2]: for control top 45bc1aee7fSJitao Shi * page[3]: for DSI Link Control1 46bc1aee7fSJitao Shi * page[4]: for MIPI Phy 47bc1aee7fSJitao Shi * page[5]: for VPLL 48bc1aee7fSJitao Shi * page[6]: for DSI Link Control2 49bc1aee7fSJitao Shi * page[7]: for SPI ROM mapping 50bc1aee7fSJitao Shi */ 51bc1aee7fSJitao Shi enum page_addr_offset { 52bc1aee7fSJitao Shi PAGE0_DP_CNTL = 0, 53bc1aee7fSJitao Shi PAGE1_VDO_BDG, 54bc1aee7fSJitao Shi PAGE2_TOP_CNTL, 55bc1aee7fSJitao Shi PAGE3_DSI_CNTL1, 56bc1aee7fSJitao Shi PAGE4_MIPI_PHY, 57bc1aee7fSJitao Shi PAGE5_VPLL, 58bc1aee7fSJitao Shi PAGE6_DSI_CNTL2, 59bc1aee7fSJitao Shi PAGE7_SPI_CNTL, 60bc1aee7fSJitao Shi MAX_DEVS 61bc1aee7fSJitao Shi }; 62bc1aee7fSJitao Shi 63bc1aee7fSJitao Shi enum ps8640_vdo_control { 64bc1aee7fSJitao Shi DISABLE = VDO_DIS, 65bc1aee7fSJitao Shi ENABLE = VDO_EN, 66bc1aee7fSJitao Shi }; 67bc1aee7fSJitao Shi 68bc1aee7fSJitao Shi struct ps8640 { 69bc1aee7fSJitao Shi struct drm_bridge bridge; 70bc1aee7fSJitao Shi struct drm_bridge *panel_bridge; 71bc1aee7fSJitao Shi struct mipi_dsi_device *dsi; 72bc1aee7fSJitao Shi struct i2c_client *page[MAX_DEVS]; 73*692d8db0SPhilip Chen struct regmap *regmap[MAX_DEVS]; 74bc1aee7fSJitao Shi struct regulator_bulk_data supplies[2]; 75bc1aee7fSJitao Shi struct gpio_desc *gpio_reset; 76bc1aee7fSJitao Shi struct gpio_desc *gpio_powerdown; 7746f20630SEnric Balletbo i Serra bool powered; 78bc1aee7fSJitao Shi }; 79bc1aee7fSJitao Shi 80*692d8db0SPhilip Chen static const struct regmap_config ps8640_regmap_config[] = { 81*692d8db0SPhilip Chen [PAGE0_DP_CNTL] = { 82*692d8db0SPhilip Chen COMMON_PS8640_REGMAP_CONFIG, 83*692d8db0SPhilip Chen .max_register = 0xbf, 84*692d8db0SPhilip Chen }, 85*692d8db0SPhilip Chen [PAGE1_VDO_BDG] = { 86*692d8db0SPhilip Chen COMMON_PS8640_REGMAP_CONFIG, 87*692d8db0SPhilip Chen .max_register = 0xff, 88*692d8db0SPhilip Chen }, 89*692d8db0SPhilip Chen [PAGE2_TOP_CNTL] = { 90*692d8db0SPhilip Chen COMMON_PS8640_REGMAP_CONFIG, 91*692d8db0SPhilip Chen .max_register = 0xff, 92*692d8db0SPhilip Chen }, 93*692d8db0SPhilip Chen [PAGE3_DSI_CNTL1] = { 94*692d8db0SPhilip Chen COMMON_PS8640_REGMAP_CONFIG, 95*692d8db0SPhilip Chen .max_register = 0xff, 96*692d8db0SPhilip Chen }, 97*692d8db0SPhilip Chen [PAGE4_MIPI_PHY] = { 98*692d8db0SPhilip Chen COMMON_PS8640_REGMAP_CONFIG, 99*692d8db0SPhilip Chen .max_register = 0xff, 100*692d8db0SPhilip Chen }, 101*692d8db0SPhilip Chen [PAGE5_VPLL] = { 102*692d8db0SPhilip Chen COMMON_PS8640_REGMAP_CONFIG, 103*692d8db0SPhilip Chen .max_register = 0x7f, 104*692d8db0SPhilip Chen }, 105*692d8db0SPhilip Chen [PAGE6_DSI_CNTL2] = { 106*692d8db0SPhilip Chen COMMON_PS8640_REGMAP_CONFIG, 107*692d8db0SPhilip Chen .max_register = 0xff, 108*692d8db0SPhilip Chen }, 109*692d8db0SPhilip Chen [PAGE7_SPI_CNTL] = { 110*692d8db0SPhilip Chen COMMON_PS8640_REGMAP_CONFIG, 111*692d8db0SPhilip Chen .max_register = 0xff, 112*692d8db0SPhilip Chen }, 113*692d8db0SPhilip Chen }; 114*692d8db0SPhilip Chen 115bc1aee7fSJitao Shi static inline struct ps8640 *bridge_to_ps8640(struct drm_bridge *e) 116bc1aee7fSJitao Shi { 117bc1aee7fSJitao Shi return container_of(e, struct ps8640, bridge); 118bc1aee7fSJitao Shi } 119bc1aee7fSJitao Shi 120bc1aee7fSJitao Shi static int ps8640_bridge_vdo_control(struct ps8640 *ps_bridge, 121bc1aee7fSJitao Shi const enum ps8640_vdo_control ctrl) 122bc1aee7fSJitao Shi { 123*692d8db0SPhilip Chen struct regmap *map = ps_bridge->regmap[PAGE3_DSI_CNTL1]; 124bc1aee7fSJitao Shi u8 vdo_ctrl_buf[] = { VDO_CTL_ADD, ctrl }; 125bc1aee7fSJitao Shi int ret; 126bc1aee7fSJitao Shi 127*692d8db0SPhilip Chen ret = regmap_bulk_write(map, PAGE3_SET_ADD, 128*692d8db0SPhilip Chen vdo_ctrl_buf, sizeof(vdo_ctrl_buf)); 129*692d8db0SPhilip Chen 13094d4c132SEnric Balletbo i Serra if (ret < 0) { 13194d4c132SEnric Balletbo i Serra DRM_ERROR("failed to %sable VDO: %d\n", 13294d4c132SEnric Balletbo i Serra ctrl == ENABLE ? "en" : "dis", ret); 133bc1aee7fSJitao Shi return ret; 13494d4c132SEnric Balletbo i Serra } 135bc1aee7fSJitao Shi 136bc1aee7fSJitao Shi return 0; 137bc1aee7fSJitao Shi } 138bc1aee7fSJitao Shi 13946f20630SEnric Balletbo i Serra static void ps8640_bridge_poweron(struct ps8640 *ps_bridge) 140bc1aee7fSJitao Shi { 141*692d8db0SPhilip Chen struct regmap *map = ps_bridge->regmap[PAGE2_TOP_CNTL]; 142bc1aee7fSJitao Shi int ret, status; 143bc1aee7fSJitao Shi 14446f20630SEnric Balletbo i Serra if (ps_bridge->powered) 14546f20630SEnric Balletbo i Serra return; 14646f20630SEnric Balletbo i Serra 147bc1aee7fSJitao Shi ret = regulator_bulk_enable(ARRAY_SIZE(ps_bridge->supplies), 148bc1aee7fSJitao Shi ps_bridge->supplies); 149bc1aee7fSJitao Shi if (ret < 0) { 150bc1aee7fSJitao Shi DRM_ERROR("cannot enable regulators %d\n", ret); 151bc1aee7fSJitao Shi return; 152bc1aee7fSJitao Shi } 153bc1aee7fSJitao Shi 154bc1aee7fSJitao Shi gpiod_set_value(ps_bridge->gpio_powerdown, 0); 155bc1aee7fSJitao Shi gpiod_set_value(ps_bridge->gpio_reset, 1); 156bc1aee7fSJitao Shi usleep_range(2000, 2500); 157bc1aee7fSJitao Shi gpiod_set_value(ps_bridge->gpio_reset, 0); 158bc1aee7fSJitao Shi 159bc1aee7fSJitao Shi /* 160bc1aee7fSJitao Shi * Wait for the ps8640 embedded MCU to be ready 161bc1aee7fSJitao Shi * First wait 200ms and then check the MCU ready flag every 20ms 162bc1aee7fSJitao Shi */ 163bc1aee7fSJitao Shi msleep(200); 164bc1aee7fSJitao Shi 165*692d8db0SPhilip Chen ret = regmap_read_poll_timeout(map, PAGE2_GPIO_H, status, 166*692d8db0SPhilip Chen status & PS_GPIO9, 20 * 1000, 200 * 1000); 167bc1aee7fSJitao Shi 168*692d8db0SPhilip Chen if (ret < 0) { 169*692d8db0SPhilip Chen DRM_ERROR("failed read PAGE2_GPIO_H: %d\n", ret); 170bc1aee7fSJitao Shi goto err_regulators_disable; 171bc1aee7fSJitao Shi } 172bc1aee7fSJitao Shi 173bc1aee7fSJitao Shi msleep(50); 174bc1aee7fSJitao Shi 175bc1aee7fSJitao Shi /* 176bc1aee7fSJitao Shi * The Manufacturer Command Set (MCS) is a device dependent interface 177bc1aee7fSJitao Shi * intended for factory programming of the display module default 178bc1aee7fSJitao Shi * parameters. Once the display module is configured, the MCS shall be 179bc1aee7fSJitao Shi * disabled by the manufacturer. Once disabled, all MCS commands are 180bc1aee7fSJitao Shi * ignored by the display interface. 181bc1aee7fSJitao Shi */ 182bc1aee7fSJitao Shi 183*692d8db0SPhilip Chen ret = regmap_update_bits(map, PAGE2_MCS_EN, MCS_EN, 0); 184bc1aee7fSJitao Shi if (ret < 0) { 185bc1aee7fSJitao Shi DRM_ERROR("failed write PAGE2_MCS_EN: %d\n", ret); 186bc1aee7fSJitao Shi goto err_regulators_disable; 187bc1aee7fSJitao Shi } 188bc1aee7fSJitao Shi 189bc1aee7fSJitao Shi /* Switch access edp panel's edid through i2c */ 190*692d8db0SPhilip Chen ret = regmap_write(map, PAGE2_I2C_BYPASS, I2C_BYPASS_EN); 191bc1aee7fSJitao Shi if (ret < 0) { 192bc1aee7fSJitao Shi DRM_ERROR("failed write PAGE2_I2C_BYPASS: %d\n", ret); 193bc1aee7fSJitao Shi goto err_regulators_disable; 194bc1aee7fSJitao Shi } 195bc1aee7fSJitao Shi 19646f20630SEnric Balletbo i Serra ps_bridge->powered = true; 19746f20630SEnric Balletbo i Serra 198bc1aee7fSJitao Shi return; 199bc1aee7fSJitao Shi 200bc1aee7fSJitao Shi err_regulators_disable: 201bc1aee7fSJitao Shi regulator_bulk_disable(ARRAY_SIZE(ps_bridge->supplies), 202bc1aee7fSJitao Shi ps_bridge->supplies); 203bc1aee7fSJitao Shi } 204bc1aee7fSJitao Shi 20546f20630SEnric Balletbo i Serra static void ps8640_bridge_poweroff(struct ps8640 *ps_bridge) 206bc1aee7fSJitao Shi { 207bc1aee7fSJitao Shi int ret; 208bc1aee7fSJitao Shi 20946f20630SEnric Balletbo i Serra if (!ps_bridge->powered) 21046f20630SEnric Balletbo i Serra return; 211bc1aee7fSJitao Shi 212bc1aee7fSJitao Shi gpiod_set_value(ps_bridge->gpio_reset, 1); 213bc1aee7fSJitao Shi gpiod_set_value(ps_bridge->gpio_powerdown, 1); 214bc1aee7fSJitao Shi ret = regulator_bulk_disable(ARRAY_SIZE(ps_bridge->supplies), 215bc1aee7fSJitao Shi ps_bridge->supplies); 216bc1aee7fSJitao Shi if (ret < 0) 217bc1aee7fSJitao Shi DRM_ERROR("cannot disable regulators %d\n", ret); 21846f20630SEnric Balletbo i Serra 21946f20630SEnric Balletbo i Serra ps_bridge->powered = false; 22046f20630SEnric Balletbo i Serra } 22146f20630SEnric Balletbo i Serra 22246f20630SEnric Balletbo i Serra static void ps8640_pre_enable(struct drm_bridge *bridge) 22346f20630SEnric Balletbo i Serra { 22446f20630SEnric Balletbo i Serra struct ps8640 *ps_bridge = bridge_to_ps8640(bridge); 22546f20630SEnric Balletbo i Serra int ret; 22646f20630SEnric Balletbo i Serra 22746f20630SEnric Balletbo i Serra ps8640_bridge_poweron(ps_bridge); 22846f20630SEnric Balletbo i Serra 22946f20630SEnric Balletbo i Serra ret = ps8640_bridge_vdo_control(ps_bridge, ENABLE); 23046f20630SEnric Balletbo i Serra if (ret < 0) 23146f20630SEnric Balletbo i Serra ps8640_bridge_poweroff(ps_bridge); 23246f20630SEnric Balletbo i Serra } 23346f20630SEnric Balletbo i Serra 23446f20630SEnric Balletbo i Serra static void ps8640_post_disable(struct drm_bridge *bridge) 23546f20630SEnric Balletbo i Serra { 23646f20630SEnric Balletbo i Serra struct ps8640 *ps_bridge = bridge_to_ps8640(bridge); 23746f20630SEnric Balletbo i Serra 23846f20630SEnric Balletbo i Serra ps8640_bridge_vdo_control(ps_bridge, DISABLE); 23946f20630SEnric Balletbo i Serra ps8640_bridge_poweroff(ps_bridge); 240bc1aee7fSJitao Shi } 241bc1aee7fSJitao Shi 242a25b988fSLaurent Pinchart static int ps8640_bridge_attach(struct drm_bridge *bridge, 243a25b988fSLaurent Pinchart enum drm_bridge_attach_flags flags) 244bc1aee7fSJitao Shi { 245bc1aee7fSJitao Shi struct ps8640 *ps_bridge = bridge_to_ps8640(bridge); 246bc1aee7fSJitao Shi struct device *dev = &ps_bridge->page[0]->dev; 247bc1aee7fSJitao Shi struct device_node *in_ep, *dsi_node; 248bc1aee7fSJitao Shi struct mipi_dsi_device *dsi; 249bc1aee7fSJitao Shi struct mipi_dsi_host *host; 250bc1aee7fSJitao Shi int ret; 251bc1aee7fSJitao Shi const struct mipi_dsi_device_info info = { .type = "ps8640", 252bc1aee7fSJitao Shi .channel = 0, 253bc1aee7fSJitao Shi .node = NULL, 254bc1aee7fSJitao Shi }; 255812a65baSEnric Balletbo i Serra 256812a65baSEnric Balletbo i Serra if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) 257812a65baSEnric Balletbo i Serra return -EINVAL; 258812a65baSEnric Balletbo i Serra 259bc1aee7fSJitao Shi /* port@0 is ps8640 dsi input port */ 260bc1aee7fSJitao Shi in_ep = of_graph_get_endpoint_by_regs(dev->of_node, 0, -1); 261bc1aee7fSJitao Shi if (!in_ep) 262bc1aee7fSJitao Shi return -ENODEV; 263bc1aee7fSJitao Shi 264bc1aee7fSJitao Shi dsi_node = of_graph_get_remote_port_parent(in_ep); 265bc1aee7fSJitao Shi of_node_put(in_ep); 266bc1aee7fSJitao Shi if (!dsi_node) 267bc1aee7fSJitao Shi return -ENODEV; 268bc1aee7fSJitao Shi 269bc1aee7fSJitao Shi host = of_find_mipi_dsi_host_by_node(dsi_node); 270bc1aee7fSJitao Shi of_node_put(dsi_node); 271bc1aee7fSJitao Shi if (!host) 272bc1aee7fSJitao Shi return -ENODEV; 273bc1aee7fSJitao Shi 274bc1aee7fSJitao Shi dsi = mipi_dsi_device_register_full(host, &info); 275bc1aee7fSJitao Shi if (IS_ERR(dsi)) { 276bc1aee7fSJitao Shi dev_err(dev, "failed to create dsi device\n"); 277bc1aee7fSJitao Shi ret = PTR_ERR(dsi); 278bc1aee7fSJitao Shi return ret; 279bc1aee7fSJitao Shi } 280bc1aee7fSJitao Shi 281bc1aee7fSJitao Shi ps_bridge->dsi = dsi; 282bc1aee7fSJitao Shi 283bc1aee7fSJitao Shi dsi->host = host; 284bc1aee7fSJitao Shi dsi->mode_flags = MIPI_DSI_MODE_VIDEO | 285bc1aee7fSJitao Shi MIPI_DSI_MODE_VIDEO_SYNC_PULSE; 286bc1aee7fSJitao Shi dsi->format = MIPI_DSI_FMT_RGB888; 28728210a3fSPhilip Chen dsi->lanes = NUM_MIPI_LANES; 288bc1aee7fSJitao Shi ret = mipi_dsi_attach(dsi); 289bc1aee7fSJitao Shi if (ret) 290bc1aee7fSJitao Shi goto err_dsi_attach; 291bc1aee7fSJitao Shi 292bc1aee7fSJitao Shi /* Attach the panel-bridge to the dsi bridge */ 293bc1aee7fSJitao Shi return drm_bridge_attach(bridge->encoder, ps_bridge->panel_bridge, 294a25b988fSLaurent Pinchart &ps_bridge->bridge, flags); 295bc1aee7fSJitao Shi 296bc1aee7fSJitao Shi err_dsi_attach: 297bc1aee7fSJitao Shi mipi_dsi_device_unregister(dsi); 298bc1aee7fSJitao Shi return ret; 299bc1aee7fSJitao Shi } 300bc1aee7fSJitao Shi 301d82c12abSEnric Balletbo i Serra static struct edid *ps8640_bridge_get_edid(struct drm_bridge *bridge, 302d82c12abSEnric Balletbo i Serra struct drm_connector *connector) 303d82c12abSEnric Balletbo i Serra { 304d82c12abSEnric Balletbo i Serra struct ps8640 *ps_bridge = bridge_to_ps8640(bridge); 30546f20630SEnric Balletbo i Serra bool poweroff = !ps_bridge->powered; 30646f20630SEnric Balletbo i Serra struct edid *edid; 307d82c12abSEnric Balletbo i Serra 30846f20630SEnric Balletbo i Serra /* 30946f20630SEnric Balletbo i Serra * When we end calling get_edid() triggered by an ioctl, i.e 31046f20630SEnric Balletbo i Serra * 31146f20630SEnric Balletbo i Serra * drm_mode_getconnector (ioctl) 31246f20630SEnric Balletbo i Serra * -> drm_helper_probe_single_connector_modes 31346f20630SEnric Balletbo i Serra * -> drm_bridge_connector_get_modes 31446f20630SEnric Balletbo i Serra * -> ps8640_bridge_get_edid 31546f20630SEnric Balletbo i Serra * 31646f20630SEnric Balletbo i Serra * We need to make sure that what we need is enabled before reading 31746f20630SEnric Balletbo i Serra * EDID, for this chip, we need to do a full poweron, otherwise it will 31846f20630SEnric Balletbo i Serra * fail. 31946f20630SEnric Balletbo i Serra */ 32046f20630SEnric Balletbo i Serra drm_bridge_chain_pre_enable(bridge); 32146f20630SEnric Balletbo i Serra 32246f20630SEnric Balletbo i Serra edid = drm_get_edid(connector, 323d82c12abSEnric Balletbo i Serra ps_bridge->page[PAGE0_DP_CNTL]->adapter); 32446f20630SEnric Balletbo i Serra 32546f20630SEnric Balletbo i Serra /* 32646f20630SEnric Balletbo i Serra * If we call the get_edid() function without having enabled the chip 32746f20630SEnric Balletbo i Serra * before, return the chip to its original power state. 32846f20630SEnric Balletbo i Serra */ 32946f20630SEnric Balletbo i Serra if (poweroff) 33046f20630SEnric Balletbo i Serra drm_bridge_chain_post_disable(bridge); 33146f20630SEnric Balletbo i Serra 33246f20630SEnric Balletbo i Serra return edid; 333d82c12abSEnric Balletbo i Serra } 334d82c12abSEnric Balletbo i Serra 335bc1aee7fSJitao Shi static const struct drm_bridge_funcs ps8640_bridge_funcs = { 336bc1aee7fSJitao Shi .attach = ps8640_bridge_attach, 337d82c12abSEnric Balletbo i Serra .get_edid = ps8640_bridge_get_edid, 338bc1aee7fSJitao Shi .post_disable = ps8640_post_disable, 339bc1aee7fSJitao Shi .pre_enable = ps8640_pre_enable, 340bc1aee7fSJitao Shi }; 341bc1aee7fSJitao Shi 342bc1aee7fSJitao Shi static int ps8640_probe(struct i2c_client *client) 343bc1aee7fSJitao Shi { 344bc1aee7fSJitao Shi struct device *dev = &client->dev; 345bc1aee7fSJitao Shi struct device_node *np = dev->of_node; 346bc1aee7fSJitao Shi struct ps8640 *ps_bridge; 347bc1aee7fSJitao Shi struct drm_panel *panel; 348bc1aee7fSJitao Shi int ret; 349bc1aee7fSJitao Shi u32 i; 350bc1aee7fSJitao Shi 351bc1aee7fSJitao Shi ps_bridge = devm_kzalloc(dev, sizeof(*ps_bridge), GFP_KERNEL); 352bc1aee7fSJitao Shi if (!ps_bridge) 353bc1aee7fSJitao Shi return -ENOMEM; 354bc1aee7fSJitao Shi 355bc1aee7fSJitao Shi /* port@1 is ps8640 output port */ 356bc1aee7fSJitao Shi ret = drm_of_find_panel_or_bridge(np, 1, 0, &panel, NULL); 357bc1aee7fSJitao Shi if (ret < 0) 358bc1aee7fSJitao Shi return ret; 359bc1aee7fSJitao Shi if (!panel) 360bc1aee7fSJitao Shi return -ENODEV; 361bc1aee7fSJitao Shi 362bc1aee7fSJitao Shi ps_bridge->panel_bridge = devm_drm_panel_bridge_add(dev, panel); 363bc1aee7fSJitao Shi if (IS_ERR(ps_bridge->panel_bridge)) 364bc1aee7fSJitao Shi return PTR_ERR(ps_bridge->panel_bridge); 365bc1aee7fSJitao Shi 366bc1aee7fSJitao Shi ps_bridge->supplies[0].supply = "vdd33"; 367bc1aee7fSJitao Shi ps_bridge->supplies[1].supply = "vdd12"; 368bc1aee7fSJitao Shi ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ps_bridge->supplies), 369bc1aee7fSJitao Shi ps_bridge->supplies); 370bc1aee7fSJitao Shi if (ret) 371bc1aee7fSJitao Shi return ret; 372bc1aee7fSJitao Shi 373bc1aee7fSJitao Shi ps_bridge->gpio_powerdown = devm_gpiod_get(&client->dev, "powerdown", 374bc1aee7fSJitao Shi GPIOD_OUT_HIGH); 375bc1aee7fSJitao Shi if (IS_ERR(ps_bridge->gpio_powerdown)) 376bc1aee7fSJitao Shi return PTR_ERR(ps_bridge->gpio_powerdown); 377bc1aee7fSJitao Shi 378bc1aee7fSJitao Shi /* 379bc1aee7fSJitao Shi * Assert the reset to avoid the bridge being initialized prematurely 380bc1aee7fSJitao Shi */ 381bc1aee7fSJitao Shi ps_bridge->gpio_reset = devm_gpiod_get(&client->dev, "reset", 382bc1aee7fSJitao Shi GPIOD_OUT_HIGH); 383bc1aee7fSJitao Shi if (IS_ERR(ps_bridge->gpio_reset)) 384bc1aee7fSJitao Shi return PTR_ERR(ps_bridge->gpio_reset); 385bc1aee7fSJitao Shi 386bc1aee7fSJitao Shi ps_bridge->bridge.funcs = &ps8640_bridge_funcs; 387bc1aee7fSJitao Shi ps_bridge->bridge.of_node = dev->of_node; 388d82c12abSEnric Balletbo i Serra ps_bridge->bridge.ops = DRM_BRIDGE_OP_EDID; 389d82c12abSEnric Balletbo i Serra ps_bridge->bridge.type = DRM_MODE_CONNECTOR_eDP; 390bc1aee7fSJitao Shi 391bc1aee7fSJitao Shi ps_bridge->page[PAGE0_DP_CNTL] = client; 392bc1aee7fSJitao Shi 393*692d8db0SPhilip Chen ps_bridge->regmap[PAGE0_DP_CNTL] = devm_regmap_init_i2c(client, ps8640_regmap_config); 394*692d8db0SPhilip Chen if (IS_ERR(ps_bridge->regmap[PAGE0_DP_CNTL])) 395*692d8db0SPhilip Chen return PTR_ERR(ps_bridge->regmap[PAGE0_DP_CNTL]); 396*692d8db0SPhilip Chen 397bc1aee7fSJitao Shi for (i = 1; i < ARRAY_SIZE(ps_bridge->page); i++) { 398bc1aee7fSJitao Shi ps_bridge->page[i] = devm_i2c_new_dummy_device(&client->dev, 399bc1aee7fSJitao Shi client->adapter, 400bc1aee7fSJitao Shi client->addr + i); 401*692d8db0SPhilip Chen if (IS_ERR(ps_bridge->page[i])) 402bc1aee7fSJitao Shi return PTR_ERR(ps_bridge->page[i]); 403*692d8db0SPhilip Chen 404*692d8db0SPhilip Chen ps_bridge->regmap[i] = devm_regmap_init_i2c(ps_bridge->page[i], 405*692d8db0SPhilip Chen ps8640_regmap_config + i); 406*692d8db0SPhilip Chen if (IS_ERR(ps_bridge->regmap[i])) 407*692d8db0SPhilip Chen return PTR_ERR(ps_bridge->regmap[i]); 408bc1aee7fSJitao Shi } 409bc1aee7fSJitao Shi 410bc1aee7fSJitao Shi i2c_set_clientdata(client, ps_bridge); 411bc1aee7fSJitao Shi 412bc1aee7fSJitao Shi drm_bridge_add(&ps_bridge->bridge); 413bc1aee7fSJitao Shi 414bc1aee7fSJitao Shi return 0; 415bc1aee7fSJitao Shi } 416bc1aee7fSJitao Shi 417bc1aee7fSJitao Shi static int ps8640_remove(struct i2c_client *client) 418bc1aee7fSJitao Shi { 419bc1aee7fSJitao Shi struct ps8640 *ps_bridge = i2c_get_clientdata(client); 420bc1aee7fSJitao Shi 421bc1aee7fSJitao Shi drm_bridge_remove(&ps_bridge->bridge); 422bc1aee7fSJitao Shi 423bc1aee7fSJitao Shi return 0; 424bc1aee7fSJitao Shi } 425bc1aee7fSJitao Shi 426bc1aee7fSJitao Shi static const struct of_device_id ps8640_match[] = { 427bc1aee7fSJitao Shi { .compatible = "parade,ps8640" }, 428bc1aee7fSJitao Shi { } 429bc1aee7fSJitao Shi }; 430bc1aee7fSJitao Shi MODULE_DEVICE_TABLE(of, ps8640_match); 431bc1aee7fSJitao Shi 432bc1aee7fSJitao Shi static struct i2c_driver ps8640_driver = { 433bc1aee7fSJitao Shi .probe_new = ps8640_probe, 434bc1aee7fSJitao Shi .remove = ps8640_remove, 435bc1aee7fSJitao Shi .driver = { 436bc1aee7fSJitao Shi .name = "ps8640", 437bc1aee7fSJitao Shi .of_match_table = ps8640_match, 438bc1aee7fSJitao Shi }, 439bc1aee7fSJitao Shi }; 440bc1aee7fSJitao Shi module_i2c_driver(ps8640_driver); 441bc1aee7fSJitao Shi 442bc1aee7fSJitao Shi MODULE_AUTHOR("Jitao Shi <jitao.shi@mediatek.com>"); 443bc1aee7fSJitao Shi MODULE_AUTHOR("CK Hu <ck.hu@mediatek.com>"); 444bc1aee7fSJitao Shi MODULE_AUTHOR("Enric Balletbo i Serra <enric.balletbo@collabora.com>"); 445bc1aee7fSJitao Shi MODULE_DESCRIPTION("PARADE ps8640 DSI-eDP converter driver"); 446bc1aee7fSJitao Shi MODULE_LICENSE("GPL v2"); 447