diff mbox series

[02/10] spi: espi_amd: Add eSPI set config IOCTL command

Message ID 20250313183440.261872-3-Raju.Rangoju@amd.com (mailing list archive)
State New
Headers show
Series spi: Add driver to support AMD eSPI controller | expand

Commit Message

Raju Rangoju March 13, 2025, 6:34 p.m. UTC
This patch introduces an IOCTL command to set the configuration of the
eSPI controller and eSPI slave0. The configuration options include
parameters like frequency, channel, and IO mode. The new IOCTL command
allow users to dynamically configure the eSPI controller and slave.

Co-developed-by: Krishnamoorthi M <krishnamoorthi.m@amd.com>
Signed-off-by: Krishnamoorthi M <krishnamoorthi.m@amd.com>
Co-developed-by: Akshata MukundShetty <akshata.mukundshetty@amd.com>
Signed-off-by: Akshata MukundShetty <akshata.mukundshetty@amd.com>
Signed-off-by: Raju Rangoju <Raju.Rangoju@amd.com>
---
 drivers/spi/espi-amd-dev.c | 94 ++++++++++++++++++++++++++++++++++++++
 drivers/spi/espi-amd.h     |  4 ++
 2 files changed, 98 insertions(+)
diff mbox series

Patch

diff --git a/drivers/spi/espi-amd-dev.c b/drivers/spi/espi-amd-dev.c
index 4e46c30d3405..5f25ad2b1eef 100644
--- a/drivers/spi/espi-amd-dev.c
+++ b/drivers/spi/espi-amd-dev.c
@@ -28,6 +28,99 @@  static DEFINE_MUTEX(device_list_lock);
 static struct class *amd_espi_dev_class;
 static struct cdev cdev;
 
+static int amd_espi_ioctl_set_conf(struct amd_espi *amd_espi, unsigned long arg)
+{
+	struct config *dev_conf, *config;
+	u32 slave_config;
+	int ret;
+
+	dev_conf = kzalloc(sizeof(*dev_conf), GFP_KERNEL);
+	if (!dev_conf)
+		return -ENOMEM;
+
+	config = kzalloc(sizeof(*config), GFP_KERNEL);
+	if (!config) {
+		kfree(dev_conf);
+		return -ENOMEM;
+	}
+
+	if (copy_from_user(config, (void __user *)arg, sizeof(struct config))) {
+		ret = -EFAULT;
+		goto set_config_free;
+	}
+
+	/* IO mode configuration */
+	if (config->io_mode != IO_MODE_SINGLE && config->io_mode != IO_MODE_DUAL &&
+	    config->io_mode != IO_MODE_QUAD) {
+		dev_err(amd_espi->dev, "Invalid IO mode\n");
+		ret = -EOPNOTSUPP;
+		goto set_config_free;
+	} else {
+		dev_conf->io_mode = config->io_mode;
+	}
+
+	/* Set operating frequency configuration */
+	if (config->op_freq != SLAVE_OP_FREQ_16 && config->op_freq != SLAVE_OP_FREQ_33 &&
+	    config->op_freq != SLAVE_OP_FREQ_66) {
+		dev_err(amd_espi->dev, "Invalid operating frequency\n");
+		ret = -EOPNOTSUPP;
+		goto set_config_free;
+	} else {
+		dev_conf->op_freq = config->op_freq;
+	}
+
+	ret = amd_espi_set_general_conf(amd_espi, dev_conf);
+	if (ret != CB_SUCCESS)
+		goto set_config_free;
+
+	/* Set channel configuration */
+	ret = amd_espi_get_general_config(amd_espi, &slave_config);
+	if (ret != CB_SUCCESS)
+		goto set_config_free;
+
+	if (config->channel_mode == CHANNEL_MODE_PC) {
+		ret = amd_espi_setup_periph_channel(amd_espi, slave_config);
+		if (ret) {
+			dev_err(amd_espi->dev, "Peripheral channel setup failed\n");
+			goto set_config_free;
+		}
+	} else if (config->channel_mode == CHANNEL_MODE_VW) {
+		ret = amd_espi_setup_vw_channel(amd_espi, slave_config);
+		if (ret) {
+			dev_err(amd_espi->dev, "Virtual wire channel setup failed\n");
+			goto set_config_free;
+		}
+	} else {
+		ret = -EOPNOTSUPP;
+	}
+
+set_config_free:
+	kfree(dev_conf);
+	kfree(config);
+	return ret;
+}
+
+static long amd_espi_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	struct amd_espi *amd_espi = filp->private_data;
+	int ret = 0;
+
+	/* Check type and command number */
+	if (_IOC_TYPE(cmd) != ESPI_MAGIC_NUMBER)
+		return -EINVAL;
+
+	switch (cmd) {
+	case ESPI_SET_CONFIG:
+		ret = amd_espi_ioctl_set_conf(amd_espi, arg);
+		break;
+	default:
+		dev_err(amd_espi->dev, "ESPI command not found, returning error\n");
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
 static int amd_espi_open(struct inode *inode, struct file *filp)
 {
 	struct amd_espi *espi;
@@ -68,6 +161,7 @@  static int amd_espi_release(struct inode *inode, struct file *filp)
 
 static const struct file_operations amd_espi_fops = {
 	.owner = THIS_MODULE,
+	.unlocked_ioctl = amd_espi_ioctl,
 	.open = amd_espi_open,
 	.release = amd_espi_release,
 };
diff --git a/drivers/spi/espi-amd.h b/drivers/spi/espi-amd.h
index 57b156fb0a05..1de53426059b 100644
--- a/drivers/spi/espi-amd.h
+++ b/drivers/spi/espi-amd.h
@@ -138,6 +138,10 @@ 
 
 #define ESPI_BASE		((u8 __iomem *)amd_espi->io_remap_addr)
 
+/* IOCTL calls */
+#define ESPI_MAGIC_NUMBER            'i'
+#define ESPI_SET_CONFIG              _IOW(ESPI_MAGIC_NUMBER, 0x1, struct config)
+
 /*
  * enum amd_espi_versions - eSPI controller versions
  * @AMD_ESPI_V1:		AMDI0070 hardware version