From e791d8951d749bcfddd9741c730fed4cafb0f38e Mon Sep 17 00:00:00 2001 From: brian Date: Tue, 30 Oct 2018 11:18:48 +0800 Subject: [PATCH 08/97] add mcu driver for rockpi lcd module Change-Id: I4d9eb75bc69bb59ffe2b7b110431c9ceab2cb3b8 --- arch/arm64/configs/rockchip_linux_defconfig | 1 + drivers/misc/Kconfig | 7 + drivers/misc/Makefile | 1 + drivers/misc/rockpi_mcu.c | 242 ++++++++++++++++++++ drivers/misc/rockpi_mcu.h | 14 ++ 5 files changed, 265 insertions(+) create mode 100644 drivers/misc/rockpi_mcu.c create mode 100644 drivers/misc/rockpi_mcu.h diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 77fa126eb1f2..eec5802fd989 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -564,6 +564,13 @@ config GPIO_DET help Enable this driver will support gpio detection. +config ROCKPI_MCU + tristate "rockpi mcu" + default y + depends on I2C + help + Control the power of touch screen for rockpi board. + source "drivers/misc/c2port/Kconfig" source "drivers/misc/eeprom/Kconfig" source "drivers/misc/cb710/Kconfig" diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index b58f922dd5a0..059722165095 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -61,3 +61,4 @@ obj-$(CONFIG_CXL_BASE) += cxl/ obj-$(CONFIG_UID_SYS_STATS) += uid_sys_stats.o obj-$(CONFIG_MEMORY_STATE_TIME) += memory_state_time.o obj-$(CONFIG_USB_CAM_GPIO) += usb_cam_gpio.o +obj-$(CONFIG_ROCKPI_MCU) += rockpi_mcu.o diff --git a/drivers/misc/rockpi_mcu.c b/drivers/misc/rockpi_mcu.c new file mode 100644 index 000000000000..38e7af802119 --- /dev/null +++ b/drivers/misc/rockpi_mcu.c @@ -0,0 +1,242 @@ +/* + * + * Rockpi board Touchscreen MCU driver. + * + * Copyright (c) 2016 ASUSTek Computer Inc. + * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 "rockpi_mcu.h" + +static struct rockpi_mcu_data *g_mcu_data; +static int connected = 0; + +static int is_hex(char num) +{ + //0-9, a-f, A-F + if ((47 < num && num < 58) || (64 < num && num < 71) || (96 < num && num < 103)) + return 1; + return 0; +} + +static int string_to_byte(const char *source, unsigned char *destination, int size) +{ + int i = 0, counter = 0; + char c[3] = {0}; + unsigned char bytes; + + if (size%2 == 1) + return -EINVAL; + + for(i = 0; i < size; i++){ + if(!is_hex(source[i])) { + return -EINVAL; + } + if(0 == i%2){ + c[0] = source[i]; + c[1] = source[i+1]; + sscanf(c, "%hhx", &bytes); + destination[counter] = bytes; + counter++; + } + } + return 0; +} + +static int send_cmds(struct i2c_client *client, const char *buf) +{ + int ret, size = strlen(buf); + unsigned char byte_cmd[size/2]; + + if ((size%2) != 0) { + LOG_ERR("size should be even\n"); + return -EINVAL; + } + + LOG_INFO("%s\n", buf); + + string_to_byte(buf, byte_cmd, size); + + ret = i2c_master_send(client, byte_cmd, size/2); + if (ret <= 0) { + //LOG_ERR("send command failed, ret = %d\n", ret); + printk("send command failed, ret = %d\n", ret); + return ret!=0 ? ret : -ECOMM; + } + msleep(20); + return 0; +} + +static int recv_cmds(struct i2c_client *client, char *buf, int size) +{ + int ret; + + ret = i2c_master_recv(client, buf, size); + if (ret <= 0) { + LOG_ERR("receive commands failed, %d\n", ret); + return ret!=0 ? ret : -ECOMM; + } + msleep(20); + return 0; +} + +static int init_cmd_check(struct rockpi_mcu_data *mcu_data) +{ + int ret; + char recv_buf[1] = {0}; + + ret = send_cmds(mcu_data->client, "80"); + if (ret < 0) + goto error; + + recv_cmds(mcu_data->client, recv_buf, 1); + if (ret < 0) + goto error; + + LOG_INFO("recv_cmds: 0x%X\n", recv_buf[0]); + if (recv_buf[0] != 0xDE && recv_buf[0] != 0xC3) { + LOG_ERR("read wrong info\n"); + ret = -EINVAL; + goto error; + + } + return 0; + +error: + return ret; +} + +int rockpi_mcu_screen_power_up(void) +{ + int res = 0; + if (!connected) + return -ENODEV; + + LOG_INFO("\n"); + + res = send_cmds(g_mcu_data->client, "8500"); + if(res < 0) + printk("send 8500 failed\n"); + msleep(800); + res = send_cmds(g_mcu_data->client, "8501"); + if(res < 0) + printk("send 8501 failed\n"); + msleep(800); + res = send_cmds(g_mcu_data->client, "8104"); + if(res < 0) + printk("send 8104 failed\n"); + + return 0; +} +EXPORT_SYMBOL_GPL(rockpi_mcu_screen_power_up); + +int rockpi_mcu_set_bright(int bright) +{ + unsigned char cmd[2]; + int ret; + + if (!connected) + return -ENODEV; + + if (bright > 0xff || bright < 0) + return -EINVAL; + + LOG_INFO("bright = 0x%x\n", bright); + + cmd[0] = 0x86; + cmd[1] = bright; + + ret = i2c_master_send(g_mcu_data->client, cmd, 2); + if (ret <= 0) { + LOG_ERR("send command failed, ret = %d\n", ret); + return ret != 0 ? ret : -ECOMM; + } + + return 0; +} +EXPORT_SYMBOL_GPL(rockpi_mcu_set_bright); + +int rockpi_mcu_is_connected(void) +{ + return connected; +} +EXPORT_SYMBOL_GPL(rockpi_mcu_is_connected); + +static int rockpi_mcu_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct rockpi_mcu_data *mcu_data; + int ret; + + LOG_INFO("address = 0x%x\n", client->addr); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + LOG_ERR("I2C check functionality failed\n"); + return -ENODEV; + } + + mcu_data = kzalloc(sizeof(struct rockpi_mcu_data), GFP_KERNEL); + if (mcu_data == NULL) { + LOG_ERR("no memory for device\n"); + return -ENOMEM; + } + + mcu_data->client = client; + i2c_set_clientdata(client, mcu_data); + g_mcu_data = mcu_data; + + ret = init_cmd_check(mcu_data); + if (ret < 0) { + LOG_ERR("init_cmd_check failed, %d\n", ret); + goto error; + } + connected = 1; + + return 0; + +error: + kfree(mcu_data); + return ret; +} + +static int rockpi_mcu_remove(struct i2c_client *client) +{ + struct rockpi_mcu_data *mcu_data = i2c_get_clientdata(client); + connected = 0; + kfree(mcu_data); + return 0; +} + +static const struct i2c_device_id rockpi_mcu_id[] = { + {"rockpi_mcu", 0}, + {}, +}; + +static struct i2c_driver rockpi_mcu_driver = { + .driver = { + .name = "rockpi_mcu", + }, + .probe = rockpi_mcu_probe, + .remove = rockpi_mcu_remove, + .id_table = rockpi_mcu_id, +}; +module_i2c_driver(rockpi_mcu_driver); + +MODULE_DESCRIPTION("rockpi Board TouchScreen MCU driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/misc/rockpi_mcu.h b/drivers/misc/rockpi_mcu.h new file mode 100644 index 000000000000..5be872fa3b5d --- /dev/null +++ b/drivers/misc/rockpi_mcu.h @@ -0,0 +1,14 @@ +#ifndef _ROCKPI_MCU_H_ +#define _ROCKPI_MCU_H_ + +#define LOG_INFO(fmt,arg...) pr_info("rockpi-mcu: %s: "fmt, __func__, ##arg); +#define LOG_ERR(fmt,arg...) pr_err("rockpi-mcu: %s: "fmt, __func__, ##arg); + +#define MAX_I2C_LEN 255 + +struct rockpi_mcu_data { + struct device *dev; + struct i2c_client *client; +}; + +#endif -- 2.25.1