162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * BOE BF060Y8M-AJ0 5.99" MIPI-DSI OLED Panel on SW43404 DriverIC 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2020 AngeloGioacchino Del Regno 662306a36Sopenharmony_ci * <angelogioacchino.delregno@somainline.org> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/backlight.h> 1062306a36Sopenharmony_ci#include <linux/delay.h> 1162306a36Sopenharmony_ci#include <linux/gpio/consumer.h> 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/of.h> 1462306a36Sopenharmony_ci#include <linux/regulator/consumer.h> 1562306a36Sopenharmony_ci#include <video/mipi_display.h> 1662306a36Sopenharmony_ci#include <drm/drm_mipi_dsi.h> 1762306a36Sopenharmony_ci#include <drm/drm_modes.h> 1862306a36Sopenharmony_ci#include <drm/drm_panel.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#define DCS_ALLOW_HBM_RANGE 0x0c 2162306a36Sopenharmony_ci#define DCS_DISALLOW_HBM_RANGE 0x08 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cienum boe_bf060y8m_aj0_supplies { 2462306a36Sopenharmony_ci BF060Y8M_VREG_VCC, 2562306a36Sopenharmony_ci BF060Y8M_VREG_VDDIO, 2662306a36Sopenharmony_ci BF060Y8M_VREG_VCI, 2762306a36Sopenharmony_ci BF060Y8M_VREG_EL_VDD, 2862306a36Sopenharmony_ci BF060Y8M_VREG_EL_VSS, 2962306a36Sopenharmony_ci BF060Y8M_VREG_MAX 3062306a36Sopenharmony_ci}; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistruct boe_bf060y8m_aj0 { 3362306a36Sopenharmony_ci struct drm_panel panel; 3462306a36Sopenharmony_ci struct mipi_dsi_device *dsi; 3562306a36Sopenharmony_ci struct regulator_bulk_data vregs[BF060Y8M_VREG_MAX]; 3662306a36Sopenharmony_ci struct gpio_desc *reset_gpio; 3762306a36Sopenharmony_ci bool prepared; 3862306a36Sopenharmony_ci}; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic inline 4162306a36Sopenharmony_cistruct boe_bf060y8m_aj0 *to_boe_bf060y8m_aj0(struct drm_panel *panel) 4262306a36Sopenharmony_ci{ 4362306a36Sopenharmony_ci return container_of(panel, struct boe_bf060y8m_aj0, panel); 4462306a36Sopenharmony_ci} 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic void boe_bf060y8m_aj0_reset(struct boe_bf060y8m_aj0 *boe) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci gpiod_set_value_cansleep(boe->reset_gpio, 0); 4962306a36Sopenharmony_ci usleep_range(2000, 3000); 5062306a36Sopenharmony_ci gpiod_set_value_cansleep(boe->reset_gpio, 1); 5162306a36Sopenharmony_ci usleep_range(15000, 16000); 5262306a36Sopenharmony_ci gpiod_set_value_cansleep(boe->reset_gpio, 0); 5362306a36Sopenharmony_ci usleep_range(5000, 6000); 5462306a36Sopenharmony_ci} 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic int boe_bf060y8m_aj0_on(struct boe_bf060y8m_aj0 *boe) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci struct mipi_dsi_device *dsi = boe->dsi; 5962306a36Sopenharmony_ci struct device *dev = &dsi->dev; 6062306a36Sopenharmony_ci int ret; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci mipi_dsi_dcs_write_seq(dsi, 0xb0, 0xa5, 0x00); 6362306a36Sopenharmony_ci mipi_dsi_dcs_write_seq(dsi, 0xb2, 0x00, 0x4c); 6462306a36Sopenharmony_ci mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_3D_CONTROL, 0x10); 6562306a36Sopenharmony_ci mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_POWER_SAVE, DCS_ALLOW_HBM_RANGE); 6662306a36Sopenharmony_ci mipi_dsi_dcs_write_seq(dsi, 0xf8, 6762306a36Sopenharmony_ci 0x00, 0x08, 0x10, 0x00, 0x22, 0x00, 0x00, 0x2d); 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci ret = mipi_dsi_dcs_exit_sleep_mode(dsi); 7062306a36Sopenharmony_ci if (ret < 0) { 7162306a36Sopenharmony_ci dev_err(dev, "Failed to exit sleep mode: %d\n", ret); 7262306a36Sopenharmony_ci return ret; 7362306a36Sopenharmony_ci } 7462306a36Sopenharmony_ci msleep(30); 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci mipi_dsi_dcs_write_seq(dsi, 0xb0, 0xa5, 0x00); 7762306a36Sopenharmony_ci mipi_dsi_dcs_write_seq(dsi, 0xc0, 7862306a36Sopenharmony_ci 0x08, 0x48, 0x65, 0x33, 0x33, 0x33, 7962306a36Sopenharmony_ci 0x2a, 0x31, 0x39, 0x20, 0x09); 8062306a36Sopenharmony_ci mipi_dsi_dcs_write_seq(dsi, 0xc1, 0x00, 0x00, 0x00, 0x1f, 0x1f, 8162306a36Sopenharmony_ci 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 8262306a36Sopenharmony_ci 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f); 8362306a36Sopenharmony_ci mipi_dsi_dcs_write_seq(dsi, 0xe2, 0x20, 0x04, 0x10, 0x12, 0x92, 8462306a36Sopenharmony_ci 0x4f, 0x8f, 0x44, 0x84, 0x83, 0x83, 0x83, 8562306a36Sopenharmony_ci 0x5c, 0x5c, 0x5c); 8662306a36Sopenharmony_ci mipi_dsi_dcs_write_seq(dsi, 0xde, 0x01, 0x2c, 0x00, 0x77, 0x3e); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci msleep(30); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci ret = mipi_dsi_dcs_set_display_on(dsi); 9162306a36Sopenharmony_ci if (ret < 0) { 9262306a36Sopenharmony_ci dev_err(dev, "Failed to set display on: %d\n", ret); 9362306a36Sopenharmony_ci return ret; 9462306a36Sopenharmony_ci } 9562306a36Sopenharmony_ci msleep(50); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci return 0; 9862306a36Sopenharmony_ci} 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cistatic int boe_bf060y8m_aj0_off(struct boe_bf060y8m_aj0 *boe) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci struct mipi_dsi_device *dsi = boe->dsi; 10362306a36Sopenharmony_ci struct device *dev = &dsi->dev; 10462306a36Sopenharmony_ci int ret; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci /* OFF commands sent in HS mode */ 10762306a36Sopenharmony_ci dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; 10862306a36Sopenharmony_ci ret = mipi_dsi_dcs_set_display_off(dsi); 10962306a36Sopenharmony_ci if (ret < 0) { 11062306a36Sopenharmony_ci dev_err(dev, "Failed to set display off: %d\n", ret); 11162306a36Sopenharmony_ci return ret; 11262306a36Sopenharmony_ci } 11362306a36Sopenharmony_ci msleep(20); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci ret = mipi_dsi_dcs_enter_sleep_mode(dsi); 11662306a36Sopenharmony_ci if (ret < 0) { 11762306a36Sopenharmony_ci dev_err(dev, "Failed to enter sleep mode: %d\n", ret); 11862306a36Sopenharmony_ci return ret; 11962306a36Sopenharmony_ci } 12062306a36Sopenharmony_ci usleep_range(1000, 2000); 12162306a36Sopenharmony_ci dsi->mode_flags |= MIPI_DSI_MODE_LPM; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci return 0; 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cistatic int boe_bf060y8m_aj0_prepare(struct drm_panel *panel) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci struct boe_bf060y8m_aj0 *boe = to_boe_bf060y8m_aj0(panel); 12962306a36Sopenharmony_ci struct device *dev = &boe->dsi->dev; 13062306a36Sopenharmony_ci int ret; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci if (boe->prepared) 13362306a36Sopenharmony_ci return 0; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci /* 13662306a36Sopenharmony_ci * Enable EL Driving Voltage first - doing that at the beginning 13762306a36Sopenharmony_ci * or at the end of the power sequence doesn't matter, so enable 13862306a36Sopenharmony_ci * it here to avoid yet another usleep at the end. 13962306a36Sopenharmony_ci */ 14062306a36Sopenharmony_ci ret = regulator_enable(boe->vregs[BF060Y8M_VREG_EL_VDD].consumer); 14162306a36Sopenharmony_ci if (ret) 14262306a36Sopenharmony_ci return ret; 14362306a36Sopenharmony_ci ret = regulator_enable(boe->vregs[BF060Y8M_VREG_EL_VSS].consumer); 14462306a36Sopenharmony_ci if (ret) 14562306a36Sopenharmony_ci goto err_elvss; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci ret = regulator_enable(boe->vregs[BF060Y8M_VREG_VCC].consumer); 14862306a36Sopenharmony_ci if (ret) 14962306a36Sopenharmony_ci goto err_vcc; 15062306a36Sopenharmony_ci usleep_range(1000, 2000); 15162306a36Sopenharmony_ci ret = regulator_enable(boe->vregs[BF060Y8M_VREG_VDDIO].consumer); 15262306a36Sopenharmony_ci if (ret) 15362306a36Sopenharmony_ci goto err_vddio; 15462306a36Sopenharmony_ci usleep_range(500, 1000); 15562306a36Sopenharmony_ci ret = regulator_enable(boe->vregs[BF060Y8M_VREG_VCI].consumer); 15662306a36Sopenharmony_ci if (ret) 15762306a36Sopenharmony_ci goto err_vci; 15862306a36Sopenharmony_ci usleep_range(2000, 3000); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci boe_bf060y8m_aj0_reset(boe); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci ret = boe_bf060y8m_aj0_on(boe); 16362306a36Sopenharmony_ci if (ret < 0) { 16462306a36Sopenharmony_ci dev_err(dev, "Failed to initialize panel: %d\n", ret); 16562306a36Sopenharmony_ci gpiod_set_value_cansleep(boe->reset_gpio, 1); 16662306a36Sopenharmony_ci return ret; 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci boe->prepared = true; 17062306a36Sopenharmony_ci return 0; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cierr_vci: 17362306a36Sopenharmony_ci regulator_disable(boe->vregs[BF060Y8M_VREG_VDDIO].consumer); 17462306a36Sopenharmony_cierr_vddio: 17562306a36Sopenharmony_ci regulator_disable(boe->vregs[BF060Y8M_VREG_VCC].consumer); 17662306a36Sopenharmony_cierr_vcc: 17762306a36Sopenharmony_ci regulator_disable(boe->vregs[BF060Y8M_VREG_EL_VSS].consumer); 17862306a36Sopenharmony_cierr_elvss: 17962306a36Sopenharmony_ci regulator_disable(boe->vregs[BF060Y8M_VREG_EL_VDD].consumer); 18062306a36Sopenharmony_ci return ret; 18162306a36Sopenharmony_ci} 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_cistatic int boe_bf060y8m_aj0_unprepare(struct drm_panel *panel) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci struct boe_bf060y8m_aj0 *boe = to_boe_bf060y8m_aj0(panel); 18662306a36Sopenharmony_ci struct device *dev = &boe->dsi->dev; 18762306a36Sopenharmony_ci int ret; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci if (!boe->prepared) 19062306a36Sopenharmony_ci return 0; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci ret = boe_bf060y8m_aj0_off(boe); 19362306a36Sopenharmony_ci if (ret < 0) 19462306a36Sopenharmony_ci dev_err(dev, "Failed to un-initialize panel: %d\n", ret); 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci gpiod_set_value_cansleep(boe->reset_gpio, 1); 19762306a36Sopenharmony_ci ret = regulator_bulk_disable(ARRAY_SIZE(boe->vregs), boe->vregs); 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci boe->prepared = false; 20062306a36Sopenharmony_ci return 0; 20162306a36Sopenharmony_ci} 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_cistatic const struct drm_display_mode boe_bf060y8m_aj0_mode = { 20462306a36Sopenharmony_ci .clock = 165268, 20562306a36Sopenharmony_ci .hdisplay = 1080, 20662306a36Sopenharmony_ci .hsync_start = 1080 + 36, 20762306a36Sopenharmony_ci .hsync_end = 1080 + 36 + 24, 20862306a36Sopenharmony_ci .htotal = 1080 + 36 + 24 + 96, 20962306a36Sopenharmony_ci .vdisplay = 2160, 21062306a36Sopenharmony_ci .vsync_start = 2160 + 16, 21162306a36Sopenharmony_ci .vsync_end = 2160 + 16 + 1, 21262306a36Sopenharmony_ci .vtotal = 2160 + 16 + 1 + 15, 21362306a36Sopenharmony_ci .width_mm = 68, /* 68.04 mm */ 21462306a36Sopenharmony_ci .height_mm = 136, /* 136.08 mm */ 21562306a36Sopenharmony_ci}; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_cistatic int boe_bf060y8m_aj0_get_modes(struct drm_panel *panel, 21862306a36Sopenharmony_ci struct drm_connector *connector) 21962306a36Sopenharmony_ci{ 22062306a36Sopenharmony_ci struct drm_display_mode *mode; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci mode = drm_mode_duplicate(connector->dev, &boe_bf060y8m_aj0_mode); 22362306a36Sopenharmony_ci if (!mode) 22462306a36Sopenharmony_ci return -ENOMEM; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci drm_mode_set_name(mode); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; 22962306a36Sopenharmony_ci connector->display_info.width_mm = mode->width_mm; 23062306a36Sopenharmony_ci connector->display_info.height_mm = mode->height_mm; 23162306a36Sopenharmony_ci drm_mode_probed_add(connector, mode); 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci return 1; 23462306a36Sopenharmony_ci} 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistatic const struct drm_panel_funcs boe_bf060y8m_aj0_panel_funcs = { 23762306a36Sopenharmony_ci .prepare = boe_bf060y8m_aj0_prepare, 23862306a36Sopenharmony_ci .unprepare = boe_bf060y8m_aj0_unprepare, 23962306a36Sopenharmony_ci .get_modes = boe_bf060y8m_aj0_get_modes, 24062306a36Sopenharmony_ci}; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_cistatic int boe_bf060y8m_aj0_bl_update_status(struct backlight_device *bl) 24362306a36Sopenharmony_ci{ 24462306a36Sopenharmony_ci struct mipi_dsi_device *dsi = bl_get_data(bl); 24562306a36Sopenharmony_ci u16 brightness = backlight_get_brightness(bl); 24662306a36Sopenharmony_ci int ret; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci ret = mipi_dsi_dcs_set_display_brightness(dsi, brightness); 24962306a36Sopenharmony_ci if (ret < 0) 25062306a36Sopenharmony_ci return ret; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci return 0; 25362306a36Sopenharmony_ci} 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_cistatic int boe_bf060y8m_aj0_bl_get_brightness(struct backlight_device *bl) 25662306a36Sopenharmony_ci{ 25762306a36Sopenharmony_ci struct mipi_dsi_device *dsi = bl_get_data(bl); 25862306a36Sopenharmony_ci u16 brightness; 25962306a36Sopenharmony_ci int ret; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci ret = mipi_dsi_dcs_get_display_brightness(dsi, &brightness); 26262306a36Sopenharmony_ci if (ret < 0) 26362306a36Sopenharmony_ci return ret; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci return brightness & 0xff; 26662306a36Sopenharmony_ci} 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_cistatic const struct backlight_ops boe_bf060y8m_aj0_bl_ops = { 26962306a36Sopenharmony_ci .update_status = boe_bf060y8m_aj0_bl_update_status, 27062306a36Sopenharmony_ci .get_brightness = boe_bf060y8m_aj0_bl_get_brightness, 27162306a36Sopenharmony_ci}; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_cistatic struct backlight_device * 27462306a36Sopenharmony_ciboe_bf060y8m_aj0_create_backlight(struct mipi_dsi_device *dsi) 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci struct device *dev = &dsi->dev; 27762306a36Sopenharmony_ci const struct backlight_properties props = { 27862306a36Sopenharmony_ci .type = BACKLIGHT_RAW, 27962306a36Sopenharmony_ci .brightness = 127, 28062306a36Sopenharmony_ci .max_brightness = 255, 28162306a36Sopenharmony_ci .scale = BACKLIGHT_SCALE_NON_LINEAR, 28262306a36Sopenharmony_ci }; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci return devm_backlight_device_register(dev, dev_name(dev), dev, dsi, 28562306a36Sopenharmony_ci &boe_bf060y8m_aj0_bl_ops, &props); 28662306a36Sopenharmony_ci} 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_cistatic int boe_bf060y8m_aj0_init_vregs(struct boe_bf060y8m_aj0 *boe, 28962306a36Sopenharmony_ci struct device *dev) 29062306a36Sopenharmony_ci{ 29162306a36Sopenharmony_ci struct regulator *vreg; 29262306a36Sopenharmony_ci int ret; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci boe->vregs[BF060Y8M_VREG_VCC].supply = "vcc"; 29562306a36Sopenharmony_ci boe->vregs[BF060Y8M_VREG_VDDIO].supply = "vddio"; 29662306a36Sopenharmony_ci boe->vregs[BF060Y8M_VREG_VCI].supply = "vci"; 29762306a36Sopenharmony_ci boe->vregs[BF060Y8M_VREG_EL_VDD].supply = "elvdd"; 29862306a36Sopenharmony_ci boe->vregs[BF060Y8M_VREG_EL_VSS].supply = "elvss"; 29962306a36Sopenharmony_ci ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(boe->vregs), 30062306a36Sopenharmony_ci boe->vregs); 30162306a36Sopenharmony_ci if (ret < 0) { 30262306a36Sopenharmony_ci dev_err(dev, "Failed to get regulators: %d\n", ret); 30362306a36Sopenharmony_ci return ret; 30462306a36Sopenharmony_ci } 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci vreg = boe->vregs[BF060Y8M_VREG_VCC].consumer; 30762306a36Sopenharmony_ci ret = regulator_is_supported_voltage(vreg, 2700000, 3600000); 30862306a36Sopenharmony_ci if (!ret) 30962306a36Sopenharmony_ci return ret; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci vreg = boe->vregs[BF060Y8M_VREG_VDDIO].consumer; 31262306a36Sopenharmony_ci ret = regulator_is_supported_voltage(vreg, 1620000, 1980000); 31362306a36Sopenharmony_ci if (!ret) 31462306a36Sopenharmony_ci return ret; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci vreg = boe->vregs[BF060Y8M_VREG_VCI].consumer; 31762306a36Sopenharmony_ci ret = regulator_is_supported_voltage(vreg, 2600000, 3600000); 31862306a36Sopenharmony_ci if (!ret) 31962306a36Sopenharmony_ci return ret; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci vreg = boe->vregs[BF060Y8M_VREG_EL_VDD].consumer; 32262306a36Sopenharmony_ci ret = regulator_is_supported_voltage(vreg, 4400000, 4800000); 32362306a36Sopenharmony_ci if (!ret) 32462306a36Sopenharmony_ci return ret; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci /* ELVSS is negative: -5.00V to -1.40V */ 32762306a36Sopenharmony_ci vreg = boe->vregs[BF060Y8M_VREG_EL_VSS].consumer; 32862306a36Sopenharmony_ci ret = regulator_is_supported_voltage(vreg, 1400000, 5000000); 32962306a36Sopenharmony_ci if (!ret) 33062306a36Sopenharmony_ci return ret; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci /* 33362306a36Sopenharmony_ci * Set min/max rated current, known only for VCI and VDDIO and, 33462306a36Sopenharmony_ci * in case of failure, just go on gracefully, as this step is not 33562306a36Sopenharmony_ci * guaranteed to succeed on all regulator HW but do a debug print 33662306a36Sopenharmony_ci * to inform the developer during debugging. 33762306a36Sopenharmony_ci * In any case, these two supplies are also optional, so they may 33862306a36Sopenharmony_ci * be fixed-regulator which, at the time of writing, does not 33962306a36Sopenharmony_ci * support fake current limiting. 34062306a36Sopenharmony_ci */ 34162306a36Sopenharmony_ci vreg = boe->vregs[BF060Y8M_VREG_VDDIO].consumer; 34262306a36Sopenharmony_ci ret = regulator_set_current_limit(vreg, 1500, 2500); 34362306a36Sopenharmony_ci if (ret) 34462306a36Sopenharmony_ci dev_dbg(dev, "Current limit cannot be set on %s: %d\n", 34562306a36Sopenharmony_ci boe->vregs[1].supply, ret); 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci vreg = boe->vregs[BF060Y8M_VREG_VCI].consumer; 34862306a36Sopenharmony_ci ret = regulator_set_current_limit(vreg, 20000, 40000); 34962306a36Sopenharmony_ci if (ret) 35062306a36Sopenharmony_ci dev_dbg(dev, "Current limit cannot be set on %s: %d\n", 35162306a36Sopenharmony_ci boe->vregs[2].supply, ret); 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci return 0; 35462306a36Sopenharmony_ci} 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_cistatic int boe_bf060y8m_aj0_probe(struct mipi_dsi_device *dsi) 35762306a36Sopenharmony_ci{ 35862306a36Sopenharmony_ci struct device *dev = &dsi->dev; 35962306a36Sopenharmony_ci struct boe_bf060y8m_aj0 *boe; 36062306a36Sopenharmony_ci int ret; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci boe = devm_kzalloc(dev, sizeof(*boe), GFP_KERNEL); 36362306a36Sopenharmony_ci if (!boe) 36462306a36Sopenharmony_ci return -ENOMEM; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci ret = boe_bf060y8m_aj0_init_vregs(boe, dev); 36762306a36Sopenharmony_ci if (ret) 36862306a36Sopenharmony_ci return dev_err_probe(dev, ret, 36962306a36Sopenharmony_ci "Failed to initialize supplies.\n"); 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci boe->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_ASIS); 37262306a36Sopenharmony_ci if (IS_ERR(boe->reset_gpio)) 37362306a36Sopenharmony_ci return dev_err_probe(dev, PTR_ERR(boe->reset_gpio), 37462306a36Sopenharmony_ci "Failed to get reset-gpios\n"); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci boe->dsi = dsi; 37762306a36Sopenharmony_ci mipi_dsi_set_drvdata(dsi, boe); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci dsi->lanes = 4; 38062306a36Sopenharmony_ci dsi->format = MIPI_DSI_FMT_RGB888; 38162306a36Sopenharmony_ci dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_NO_EOT_PACKET | 38262306a36Sopenharmony_ci MIPI_DSI_MODE_VIDEO_SYNC_PULSE | 38362306a36Sopenharmony_ci MIPI_DSI_CLOCK_NON_CONTINUOUS | 38462306a36Sopenharmony_ci MIPI_DSI_MODE_LPM; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci drm_panel_init(&boe->panel, dev, &boe_bf060y8m_aj0_panel_funcs, 38762306a36Sopenharmony_ci DRM_MODE_CONNECTOR_DSI); 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci boe->panel.backlight = boe_bf060y8m_aj0_create_backlight(dsi); 39062306a36Sopenharmony_ci if (IS_ERR(boe->panel.backlight)) 39162306a36Sopenharmony_ci return dev_err_probe(dev, PTR_ERR(boe->panel.backlight), 39262306a36Sopenharmony_ci "Failed to create backlight\n"); 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci drm_panel_add(&boe->panel); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci ret = mipi_dsi_attach(dsi); 39762306a36Sopenharmony_ci if (ret < 0) { 39862306a36Sopenharmony_ci dev_err(dev, "Failed to attach to DSI host: %d\n", ret); 39962306a36Sopenharmony_ci return ret; 40062306a36Sopenharmony_ci } 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci return 0; 40362306a36Sopenharmony_ci} 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_cistatic void boe_bf060y8m_aj0_remove(struct mipi_dsi_device *dsi) 40662306a36Sopenharmony_ci{ 40762306a36Sopenharmony_ci struct boe_bf060y8m_aj0 *boe = mipi_dsi_get_drvdata(dsi); 40862306a36Sopenharmony_ci int ret; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci ret = mipi_dsi_detach(dsi); 41162306a36Sopenharmony_ci if (ret < 0) 41262306a36Sopenharmony_ci dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci drm_panel_remove(&boe->panel); 41562306a36Sopenharmony_ci} 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_cistatic const struct of_device_id boe_bf060y8m_aj0_of_match[] = { 41862306a36Sopenharmony_ci { .compatible = "boe,bf060y8m-aj0" }, 41962306a36Sopenharmony_ci { /* sentinel */ } 42062306a36Sopenharmony_ci}; 42162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, boe_bf060y8m_aj0_of_match); 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_cistatic struct mipi_dsi_driver boe_bf060y8m_aj0_driver = { 42462306a36Sopenharmony_ci .probe = boe_bf060y8m_aj0_probe, 42562306a36Sopenharmony_ci .remove = boe_bf060y8m_aj0_remove, 42662306a36Sopenharmony_ci .driver = { 42762306a36Sopenharmony_ci .name = "panel-sw43404-boe-fhd-amoled", 42862306a36Sopenharmony_ci .of_match_table = boe_bf060y8m_aj0_of_match, 42962306a36Sopenharmony_ci }, 43062306a36Sopenharmony_ci}; 43162306a36Sopenharmony_cimodule_mipi_dsi_driver(boe_bf060y8m_aj0_driver); 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ciMODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>"); 43462306a36Sopenharmony_ciMODULE_DESCRIPTION("BOE BF060Y8M-AJ0 MIPI-DSI OLED panel"); 43562306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 436