You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
218 lines
4.6 KiB
218 lines
4.6 KiB
/* Copyright (c) 2017-2018, 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 <linux/module.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/spi/spi.h>
|
|
|
|
#include "mdss_spi_client.h"
|
|
|
|
#define MAX_READ_SPEED_HZ 9600000
|
|
#define SPI_PANEL_COMMAND_LEN 1
|
|
static struct spi_device *mdss_spi_client;
|
|
|
|
int mdss_spi_read_data(u8 reg_addr, u8 *data, u8 len)
|
|
{
|
|
int rc = 0;
|
|
u32 max_speed_hz;
|
|
u8 memory_write_reg = 0x2c;
|
|
u8 empty_pack[] = {0x29, 0x29, 0x29};
|
|
struct spi_transfer t[4] = {
|
|
[0] = {
|
|
.tx_buf = ®_addr,
|
|
.len = 1,
|
|
},
|
|
[1] = {
|
|
.rx_buf = data,
|
|
.len = len,
|
|
},
|
|
[2] = {
|
|
.tx_buf = &empty_pack,
|
|
.len = 3,
|
|
},
|
|
[3] = {
|
|
.tx_buf = &memory_write_reg,
|
|
.len = 1,
|
|
}
|
|
};
|
|
struct spi_message m;
|
|
|
|
if (!mdss_spi_client) {
|
|
pr_err("%s: spi client not available\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
mdss_spi_client->bits_per_word = 8;
|
|
max_speed_hz = mdss_spi_client->max_speed_hz;
|
|
mdss_spi_client->max_speed_hz = MAX_READ_SPEED_HZ;
|
|
|
|
spi_message_init(&m);
|
|
spi_message_add_tail(&t[0], &m);
|
|
spi_message_add_tail(&t[1], &m);
|
|
rc = spi_sync(mdss_spi_client, &m);
|
|
if (rc) {
|
|
pr_err("%s: send panel reg failed\n", __func__);
|
|
return rc;
|
|
}
|
|
|
|
spi_message_init(&m);
|
|
spi_message_add_tail(&t[2], &m);
|
|
rc = spi_sync(mdss_spi_client, &m);
|
|
if (rc) {
|
|
pr_err("%s: send empty package failed\n", __func__);
|
|
return rc;
|
|
}
|
|
|
|
spi_message_init(&m);
|
|
spi_message_add_tail(&t[3], &m);
|
|
rc = spi_sync(mdss_spi_client, &m);
|
|
mdss_spi_client->max_speed_hz = max_speed_hz;
|
|
if (rc) {
|
|
pr_err("%s: send memory write reg failed\n", __func__);
|
|
return rc;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
int mdss_spi_tx_command(const void *buf)
|
|
{
|
|
int rc = 0;
|
|
struct spi_transfer t = {
|
|
.tx_buf = buf,
|
|
.len = SPI_PANEL_COMMAND_LEN,
|
|
};
|
|
struct spi_message m;
|
|
|
|
if (!mdss_spi_client) {
|
|
pr_err("%s: spi client not available\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
mdss_spi_client->bits_per_word = 8;
|
|
|
|
spi_message_init(&m);
|
|
spi_message_add_tail(&t, &m);
|
|
rc = spi_sync(mdss_spi_client, &m);
|
|
if (rc)
|
|
pr_err("%s: send panel command failed\n", __func__);
|
|
return rc;
|
|
}
|
|
|
|
int mdss_spi_tx_parameter(const void *buf, size_t len)
|
|
{
|
|
int rc = 0;
|
|
struct spi_transfer t = {
|
|
.tx_buf = buf,
|
|
.len = len,
|
|
};
|
|
struct spi_message m;
|
|
|
|
if (!mdss_spi_client) {
|
|
pr_err("%s: spi client not available\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
mdss_spi_client->bits_per_word = 8;
|
|
|
|
spi_message_init(&m);
|
|
spi_message_add_tail(&t, &m);
|
|
rc = spi_sync(mdss_spi_client, &m);
|
|
if (rc)
|
|
pr_err("%s: send panel parameter failed\n", __func__);
|
|
|
|
return rc;
|
|
}
|
|
|
|
int mdss_spi_tx_pixel(const void *buf, size_t len,
|
|
void (*spi_tx_compelet)(void *), void *ctx)
|
|
{
|
|
int rc = 0;
|
|
static struct spi_transfer t;
|
|
static struct spi_message m;
|
|
|
|
if (!mdss_spi_client) {
|
|
pr_err("%s: spi client not available\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
mdss_spi_client->bits_per_word = 16;
|
|
t.tx_buf = buf;
|
|
t.len = len;
|
|
spi_message_init(&m);
|
|
m.complete = spi_tx_compelet;
|
|
m.context = ctx;
|
|
|
|
spi_message_add_tail(&t, &m);
|
|
rc = spi_async(mdss_spi_client, &m);
|
|
|
|
if (rc)
|
|
pr_err("%s: send FrameBuffer data failed\n", __func__);
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int mdss_spi_client_probe(struct spi_device *spidev)
|
|
{
|
|
int irq;
|
|
int cs;
|
|
int cpha, cpol, cs_high;
|
|
u32 max_speed;
|
|
|
|
irq = spidev->irq;
|
|
cs = spidev->chip_select;
|
|
cpha = (spidev->mode & SPI_CPHA) ? 1:0;
|
|
cpol = (spidev->mode & SPI_CPOL) ? 1:0;
|
|
cs_high = (spidev->mode & SPI_CS_HIGH) ? 1:0;
|
|
max_speed = spidev->max_speed_hz;
|
|
|
|
pr_debug("cs[%x] CPHA[%x] CPOL[%x] CS_HIGH[%x] Max_speed[%d]\n",
|
|
cs, cpha, cpol, cs_high, max_speed);
|
|
mdss_spi_client = spidev;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct of_device_id mdss_spi_dt_match[] = {
|
|
{ .compatible = "qcom,mdss-spi-client" },
|
|
{},
|
|
};
|
|
|
|
static struct spi_driver mdss_spi_client_driver = {
|
|
.probe = mdss_spi_client_probe,
|
|
.driver = {
|
|
.name = "mdss-spi-client",
|
|
.owner = THIS_MODULE,
|
|
.of_match_table = mdss_spi_dt_match,
|
|
},
|
|
};
|
|
|
|
static int __init mdss_spi_init(void)
|
|
{
|
|
int ret;
|
|
|
|
ret = spi_register_driver(&mdss_spi_client_driver);
|
|
if (ret) {
|
|
pr_err("register mdss spi client driver failed!\n");
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
module_init(mdss_spi_init);
|
|
|
|
static void __exit mdss_spi_exit(void)
|
|
{
|
|
spi_unregister_driver(&mdss_spi_client_driver);
|
|
}
|
|
module_exit(mdss_spi_exit);
|
|
|
|
|