summaryrefslogtreecommitdiff
path: root/ese/st33spi.c
diff options
context:
space:
mode:
Diffstat (limited to 'ese/st33spi.c')
-rw-r--r--ese/st33spi.c177
1 files changed, 158 insertions, 19 deletions
diff --git a/ese/st33spi.c b/ese/st33spi.c
index f2c057f..f07d441 100644
--- a/ese/st33spi.c
+++ b/ese/st33spi.c
@@ -35,6 +35,7 @@
#include <linux/of_gpio.h>
#include <linux/uaccess.h>
+#include <linux/platform_data/spi-s3c64xx.h>
#undef ST33NFC_QCOM
@@ -108,6 +109,11 @@ struct st33spi_data {
int nfcc_needs_poweron;
int sehal_needs_poweron;
int se_is_poweron;
+
+ /* GPIO for SPI_CS */
+ struct s3c64xx_spi_csinfo *st33spi_csinfo;
+ struct pinctrl *pinctrl;
+ int spi_state;
};
#define POWER_MODE_NONE -1
@@ -125,6 +131,94 @@ MODULE_PARM_DESC(bufsiz, "data bytes in biggest supported SPI message");
#define DRIVER_VERSION "2.2.0"
/*-------------------------------------------------------------------------*/
+static int st33spi_pinctrl_configure(struct st33spi_data *st33spi, bool enable)
+{
+ struct pinctrl_state *state;
+ int rc;
+
+ dev_info(&st33spi->spi->dev, "st33spi: configure pinctrl: %d\n", enable);
+
+ if (IS_ERR(st33spi->pinctrl)) {
+ dev_err(&st33spi->spi->dev, "could not get pinctrl\n");
+ return -ENODEV;
+ }
+ if (enable)
+ state = pinctrl_lookup_state(st33spi->pinctrl, "on");
+ else
+ state = pinctrl_lookup_state(st33spi->pinctrl, "off");
+
+ if (!IS_ERR_OR_NULL(state)) {
+ rc = pinctrl_select_state(st33spi->pinctrl, state);
+ if (unlikely(rc))
+ dev_err(&st33spi->spi->dev, "st33spi: failed to set pinctrl state\n");
+ return rc;
+ }
+ dev_err(&st33spi->spi->dev, "st33spi: failed to get pinctrl state\n");
+
+ return -EIO;
+}
+
+static ssize_t st33spi_state_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct spi_device *spi;
+ struct st33spi_data *st33spi;
+ spi = to_spi_device(dev);
+ if (spi == NULL)
+ return -ENODEV;
+
+ st33spi = spi_get_drvdata(spi);
+ if (st33spi == NULL)
+ return -ENODEV;
+
+ return scnprintf(buf, PAGE_SIZE, "state:%d, st33spi_cs:%d\n",
+ st33spi->spi_state, gpio_get_value(st33spi->st33spi_csinfo->line));
+}
+
+static ssize_t st33spi_state_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct spi_device *spi;
+ struct st33spi_data *st33spi;
+ struct s3c64xx_spi_csinfo *cs;
+ int new_spi_state;
+
+ spi = to_spi_device(dev);
+ if (spi == NULL)
+ return -ENODEV;
+
+ st33spi = spi_get_drvdata(spi);
+ if (st33spi == NULL)
+ return -ENODEV;
+
+ cs = st33spi->st33spi_csinfo;
+ if (cs == NULL)
+ return -ENODEV;
+
+ if (!kstrtoint(buf, 10, &new_spi_state)) {
+ st33spi->spi_state = new_spi_state;
+ if (new_spi_state == 0) {
+ st33spi_pinctrl_configure(st33spi, false);
+ } else if (new_spi_state == 33) {
+ st33spi_pinctrl_configure(st33spi, true);
+ } else {
+ dev_err(dev, "%s: incorrect parameter\n", __func__);
+ return -EINVAL;
+ }
+ }
+ return count;
+}
+
+static DEVICE_ATTR_RW(st33spi_state);
+
+static struct attribute *st33spi_attrs[] = {
+ &dev_attr_st33spi_state.attr,
+ NULL,
+};
+
+static struct attribute_group st33spi_attr_grp = {
+ .attrs = st33spi_attrs,
+};
static ssize_t st33spi_sync(struct st33spi_data *st33spi,
struct spi_message *message)
@@ -192,6 +286,11 @@ static ssize_t st33spi_read(struct file *filp, char __user *buf, size_t count,
st33spi = filp->private_data;
+ if (st33spi == NULL || !st33spi->spi_state) {
+ dev_warn(&st33spi->spi->dev, "st33spi: spi is not enabled, abort read process\n");
+ return -EFAULT;
+ }
+
dev_dbg(&st33spi->spi->dev, "st33spi Read: %zu bytes\n", count);
mutex_lock(&st33spi->buf_lock);
@@ -226,6 +325,11 @@ static ssize_t st33spi_write(struct file *filp, const char __user *buf,
st33spi = filp->private_data;
+ if (st33spi == NULL || !st33spi->spi_state) {
+ dev_warn(&st33spi->spi->dev, "st33spi: spi is not enabled, abort write process\n");
+ return -EFAULT;
+ }
+
dev_dbg(&st33spi->spi->dev, "st33spi Write: %zu bytes\n", count);
mutex_lock(&st33spi->buf_lock);
@@ -587,10 +691,9 @@ static long st33spi_ioctl(struct file *filp, unsigned int cmd,
retval = __get_user(tmp, (__u32 __user *)arg);
dev_dbg(&st33spi->spi->dev,
"st33spi ST33SPI_IOC_WR_POWER %d\n", retval);
- if (retval == 0) {
+ if (retval == 0 && st33spi->spi_state) {
st33spi_power_set(st33spi, tmp ? 1 : 0);
- dev_dbg(&st33spi->spi->dev, "SE_POWER_REQ set: %d\n",
- tmp);
+ dev_dbg(&st33spi->spi->dev, "SE_POWER_REQ set: %d\n", tmp);
}
break;
default:
@@ -710,6 +813,13 @@ static int st33spi_open(struct inode *inode, struct file *filp)
goto err_find_dev;
}
+ if (st33spi == NULL || !st33spi->spi_state) {
+ dev_warn(&st33spi->spi->dev,
+ "st33spi: spi is not enabled, abort open process\n");
+ mutex_unlock(&device_list_lock);
+ return -EFAULT;
+ }
+
/* Authorize only 1 process to open the device. */
if (st33spi->users > 0) {
dev_err(&st33spi->spi->dev, "already open\n");
@@ -867,33 +977,32 @@ static inline void st33spi_probe_acpi(struct spi_device *spi)
static int st33spi_parse_dt(struct device *dev, struct st33spi_data *pdata)
{
- int r = 0;
struct device_node *np = dev->of_node;
+ struct device_node *data_np;
const char *power_mode;
+ int st33spi_state;
#ifndef GKI_MODULE
np = of_find_compatible_node(NULL, NULL, "st,st33spi");
#endif
if (!np) {
- return r;
+ return -ENODEV;
}
/* Read power mode. */
power_mode = of_get_property(np, "power_mode", NULL);
if (!power_mode) {
- dev_info(dev, "%s: Default power mode: ST33\n",
- __FILE__);
+ dev_info(dev, "Default power mode: ST33\n");
pdata->power_gpio_mode = POWER_MODE_ST33;
} else if (!strcmp(power_mode, "ST33")) {
- dev_info(dev, "%s: Power mode: ST33\n", __FILE__);
+ dev_info(dev, "Power mode: ST33\n");
pdata->power_gpio_mode = POWER_MODE_ST33;
} else if (!strcmp(power_mode, "none")) {
- dev_info(dev, "%s: Power mode: none\n", __FILE__);
+ dev_info(dev, "Power mode: none\n");
pdata->power_gpio_mode = POWER_MODE_NONE;
} else {
- dev_err(dev, "%s: Power mode unknown: %s\n", __FILE__,
- power_mode);
+ dev_err(dev, "Power mode unknown: %s\n", power_mode);
return -EFAULT;
}
@@ -902,16 +1011,35 @@ static int st33spi_parse_dt(struct device *dev, struct st33spi_data *pdata)
pdata->gpiod_se_reset =
devm_gpiod_get(dev, "esereset", GPIOD_OUT_LOW);
if (IS_ERR(pdata->gpiod_se_reset)) {
- dev_err(dev,
- "%s : Unable to request esereset %d\n",
- __func__,
- IS_ERR(pdata->gpiod_se_reset));
+ dev_err(dev, "Unable to request esereset %d\n",
+ IS_ERR(pdata->gpiod_se_reset));
return -ENODEV;
}
} else {
- dev_err(dev, "%s: ST54H mode not supported", __FILE__);
+ dev_err(dev, "ST54H mode not supported");
+ }
+
+ /* Read default st33spi state. */
+ data_np = of_get_child_by_name(np, "controller-data");
+ if (!data_np) {
+ dev_err(dev, "child node 'controller-data' not found\n");
+ return -ENODEV;
}
- return r;
+
+ if (!of_property_read_u32(data_np, "cs-init-state", &st33spi_state)) {
+ pdata->spi_state = st33spi_state;
+ } else {
+ pdata->spi_state = 0;
+ }
+ dev_info(dev, "Default st33spi state: %d\n", pdata->spi_state);
+
+ pdata->pinctrl = devm_pinctrl_get(dev);
+ if (IS_ERR(pdata->pinctrl)) {
+ dev_err(dev, "could not get pinctrl\n");
+ return -ENODEV;
+ }
+
+ return 0;
}
static int st33spi_probe(struct spi_device *spi)
@@ -932,8 +1060,7 @@ static int st33spi_probe(struct spi_device *spi)
BUILD_BUG_ON(N_SPI_MINORS > 256);
st33spi_major =
__register_chrdev(0, 0, N_SPI_MINORS, "spi", &st33spi_fops);
- dev_info(&spi->dev, "Loading st33spi driver, major: %d\n",
- st33spi_major);
+ dev_info(&spi->dev, "Loading st33spi driver, major: %d\n", st33spi_major);
st33spi_class = class_create(THIS_MODULE, "st33spi");
if (IS_ERR(st33spi_class)) {
@@ -974,6 +1101,12 @@ static int st33spi_probe(struct spi_device *spi)
dev = device_create(st33spi_class, &spi->dev, st33spi->devt,
st33spi, "st33spi");
status = PTR_ERR_OR_ZERO(dev);
+
+ status = sysfs_create_group(&dev->kobj, &st33spi_attr_grp);
+ if (status) {
+ dev_err(&spi->dev, "sysfs_create_group failed\n");
+ }
+ st33spi->st33spi_csinfo = spi_get_ctldata(spi);
} else {
dev_dbg(&spi->dev, "%s : no minor number available!\n",
__FILE__);
@@ -1013,6 +1146,12 @@ static int st33spi_probe(struct spi_device *spi)
if (status == 0) {
spi_set_drvdata(spi, st33spi);
(void)st33spi_parse_dt(&spi->dev, st33spi);
+ if (!st33spi->spi_state) {
+ dev_dbg(&spi->dev, "st33spi: probe - put spi pins to low \n");
+ st33spi_pinctrl_configure(st33spi, false);
+ } else {
+ st33spi_pinctrl_configure(st33spi, true);
+ }
} else {
kfree(st33spi);
}