/* Copyright (c) 2013, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and * only version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mdss_qpic.h" #include "mdss_qpic_panel.h" enum { OP_ILI9341_TEARING_EFFECT_LINE_ON = OP_SIZE_PAIR(0x35, 1), OP_ILI9341_INTERFACE_CONTROL = OP_SIZE_PAIR(0xf6, 3), OP_ILI9341_WRITE_CTRL_DISPLAY = OP_SIZE_PAIR(0x53, 1), OP_ILI9341_POWER_CONTROL_A = OP_SIZE_PAIR(0xcb, 5), OP_ILI9341_POWER_CONTROL_B = OP_SIZE_PAIR(0xcf, 3), OP_ILI9341_DRIVER_TIMING_CONTROL_A = OP_SIZE_PAIR(0xe8, 3), OP_ILI9341_DRIVER_TIMING_CONTROL_B = OP_SIZE_PAIR(0xea, 3), OP_ILI9341_POWER_ON_SEQUENCE_CONTROL = OP_SIZE_PAIR(0xed, 4), OP_ILI9341_PUMP_RATIO_CONTROL = OP_SIZE_PAIR(0xf7, 1), OP_ILI9341_POWER_CONTROL_1 = OP_SIZE_PAIR(0xc0, 1), OP_ILI9341_POWER_CONTROL_2 = OP_SIZE_PAIR(0xc1, 1), OP_ILI9341_VCOM_CONTROL_1 = OP_SIZE_PAIR(0xc5, 2), OP_ILI9341_VCOM_CONTROL_2 = OP_SIZE_PAIR(0xc7, 1), OP_ILI9341_MEMORY_ACCESS_CONTROL = OP_SIZE_PAIR(0x36, 1), OP_ILI9341_FRAME_RATE_CONTROL = OP_SIZE_PAIR(0xb1, 2), OP_ILI9341_DISPLAY_FUNCTION_CONTROL = OP_SIZE_PAIR(0xb6, 4), OP_ILI9341_ENABLE_3G = OP_SIZE_PAIR(0xf2, 1), OP_ILI9341_COLMOD_PIXEL_FORMAT_SET = OP_SIZE_PAIR(0x3a, 1), OP_ILI9341_GAMMA_SET = OP_SIZE_PAIR(0x26, 1), OP_ILI9341_POSITIVE_GAMMA_CORRECTION = OP_SIZE_PAIR(0xe0, 15), OP_ILI9341_NEGATIVE_GAMMA_CORRECTION = OP_SIZE_PAIR(0xe1, 15), OP_ILI9341_READ_DISPLAY_ID = OP_SIZE_PAIR(0x04, 4), OP_ILI9341_READ_DISPLAY_POWER_MODE = OP_SIZE_PAIR(0x0a, 2), OP_ILI9341_READ_DISPLAY_MADCTL = OP_SIZE_PAIR(0x0b, 2), }; static int rst_gpio; static int cs_gpio; static int ad8_gpio; static int te_gpio; struct regulator *vdd_vreg; struct regulator *avdd_vreg; int ili9341_init(struct platform_device *pdev, struct device_node *np) { int rc = 0; rst_gpio = of_get_named_gpio(np, "qcom,rst-gpio", 0); cs_gpio = of_get_named_gpio(np, "qcom,cs-gpio", 0); ad8_gpio = of_get_named_gpio(np, "qcom,ad8-gpio", 0); te_gpio = of_get_named_gpio(np, "qcom,te-gpio", 0); if (!gpio_is_valid(rst_gpio)) { pr_err("%s: reset gpio not specified\n" , __func__); return -EINVAL; } if (!gpio_is_valid(cs_gpio)) { pr_err("%s: cs gpio not specified\n", __func__); return -EINVAL; } if (!gpio_is_valid(ad8_gpio)) { pr_err("%s: ad8 gpio not specified\n", __func__); return -EINVAL; } if (!gpio_is_valid(te_gpio)) { pr_err("%s: te gpio not specified\n", __func__); return -EINVAL; } vdd_vreg = devm_regulator_get(&pdev->dev, "vdd"); if (IS_ERR(vdd_vreg)) { pr_err("%s could not get vdd,", __func__); return -ENODEV; } avdd_vreg = devm_regulator_get(&pdev->dev, "avdd"); if (IS_ERR(avdd_vreg)) { pr_err("%s could not get avdd,", __func__); return -ENODEV; } rc = regulator_set_voltage(vdd_vreg, 1800000, 1800000); if (rc) { pr_err("vdd_vreg->set_voltage failed, rc=%d\n", rc); return -EINVAL; } rc = regulator_set_voltage(avdd_vreg, 2700000, 2700000); if (rc) { pr_err("vdd_vreg->set_voltage failed, rc=%d\n", rc); return -EINVAL; } return 0; } static int ili9341_panel_power_on(void) { int rc; rc = regulator_enable(vdd_vreg); if (rc) { pr_err("enable vdd failed, rc=%d\n", rc); return -ENODEV; } rc = regulator_enable(avdd_vreg); if (rc) { pr_err("enable avdd failed, rc=%d\n", rc); return -ENODEV; } if (gpio_request(rst_gpio, "disp_rst_n")) { pr_err("%s request reset gpio failed\n", __func__); return -EINVAL; } if (gpio_request(cs_gpio, "disp_cs_n")) { gpio_free(rst_gpio); pr_err("%s request cs gpio failed\n", __func__); return -EINVAL; } if (gpio_request(ad8_gpio, "disp_ad8_n")) { gpio_free(cs_gpio); gpio_free(rst_gpio); pr_err("%s request ad8 gpio failed\n", __func__); return -EINVAL; } if (gpio_request(te_gpio, "disp_te_n")) { gpio_free(ad8_gpio); gpio_free(cs_gpio); gpio_free(rst_gpio); pr_err("%s request te gpio failed\n", __func__); return -EINVAL; } /* wait for 20 ms after enable gpio as suggested by hw */ msleep(20); return 0; } static void ili9341_panel_power_off(void) { gpio_free(ad8_gpio); gpio_free(cs_gpio); gpio_free(rst_gpio); gpio_free(te_gpio); regulator_disable(vdd_vreg); regulator_disable(avdd_vreg); } int ili9341_on(void) { u32 param[20]; int ret; ret = ili9341_panel_power_on(); if (ret) return ret; qpic_panel_set_cmd_only(OP_SOFT_RESET); /* wait for 120 ms after reset as panel spec suggests */ msleep(120); qpic_panel_set_cmd_only(OP_SET_DISPLAY_OFF); /* wait for 20 ms after disply off */ msleep(20); /* set memory access control */ param[0] = ((0x48)<<0) | ((0x00)<<8) | ((0x00)<<16) | ((0x00U)<<24U); qpic_send_panel_cmd(OP_ILI9341_MEMORY_ACCESS_CONTROL, param, 0); /* wait for 20 ms after command sent as panel spec suggests */ msleep(20); /* set COLMOD: Pixel Format Set */ param[0] = ((0x66)<<0) | ((0x00)<<8) | ((0x00)<<16) | ((0x00U)<<24U); qpic_send_panel_cmd(OP_ILI9341_COLMOD_PIXEL_FORMAT_SET, param, 0); /* wait for 20 ms after command sent as panel spec suggests */ msleep(20); /* set interface */ param[0] = ((0x01)<<0) | ((0x00)<<8) | ((0x00)<<16) | ((0x00U)<<24U); qpic_send_panel_cmd(OP_ILI9341_INTERFACE_CONTROL, ¶m[0], 0); /* wait for 20 ms after command sent */ msleep(20); /* exit sleep mode */ qpic_panel_set_cmd_only(OP_EXIT_SLEEP_MODE); /* wait for 20 ms after command sent as panel spec suggests */ msleep(20); /* normal mode */ qpic_panel_set_cmd_only(OP_ENTER_NORMAL_MODE); /* wait for 20 ms after command sent as panel spec suggests */ msleep(20); /* display on */ qpic_panel_set_cmd_only(OP_SET_DISPLAY_ON); /* wait for 20 ms after command sent as panel spec suggests */ msleep(20); /* tearing effect */ param[0] = ((0x00)<<0) | ((0x00)<<8) | ((0x00)<<16) | ((0x00U)<<24U); qpic_send_panel_cmd(OP_ILI9341_TEARING_EFFECT_LINE_ON, param, 0); /* wait for 20 ms after command sent as panel spec suggests */ msleep(20); return 0; } void ili9341_off(void) { ili9341_panel_power_off(); }