All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 11/11] pm80xx : gpio feature support for motherboard controllers
@ 2013-10-22 12:20 Viswas G
  2013-10-29 10:19 ` Jack Wang
  0 siblings, 1 reply; 8+ messages in thread
From: Viswas G @ 2013-10-22 12:20 UTC (permalink / raw)
  To: linux-scsi
  Cc: xjtuwjp, Sangeetha.Gnanasekaran, Nikith.Ganigarakoppal, Viswas.G,
	AnandKumar.Santhanam


Signed-off-by: Viswas G <Viswas.G@pmcs.com>
---
 drivers/scsi/pm8001/pm8001_ctl.c  |  248 ++++++++++++++++++++++++++++++++++++-
 drivers/scsi/pm8001/pm8001_ctl.h  |   55 ++++++++
 drivers/scsi/pm8001/pm8001_init.c |   37 ++++++
 drivers/scsi/pm8001/pm8001_sas.h  |   30 +++++
 drivers/scsi/pm8001/pm80xx_hwi.c  |  106 ++++++++++++++++
 drivers/scsi/pm8001/pm80xx_hwi.h  |   49 +++++++
 6 files changed, 524 insertions(+), 1 deletions(-)

diff --git a/drivers/scsi/pm8001/pm8001_ctl.c b/drivers/scsi/pm8001/pm8001_ctl.c
index 247cb1c..3c9ca21 100644
--- a/drivers/scsi/pm8001/pm8001_ctl.c
+++ b/drivers/scsi/pm8001/pm8001_ctl.c
@@ -40,7 +40,8 @@
 #include <linux/firmware.h>
 #include <linux/slab.h>
 #include "pm8001_sas.h"
-#include "pm8001_ctl.h"
+
+int pm8001_major = -1;
 
 /* scsi host attributes */
 
@@ -759,3 +760,248 @@ struct device_attribute *pm8001_host_attrs[] = {
 	NULL,
 };
 
+/**
+ * pm8001_open - open the configuration file
+ * @inode: inode being opened
+ * @file: file handle attached
+ *
+ * Called when the configuration device is opened. Does the needed
+ * set up on the handle and then returns
+ *
+ */
+static int pm8001_open(struct inode *inode, struct file *file)
+{
+	struct pm8001_hba_info *pm8001_ha;
+	unsigned minor_number = iminor(inode);
+	int err = -ENODEV;
+
+	list_for_each_entry(pm8001_ha, &hba_list, list) {
+		if (pm8001_ha->id == minor_number) {
+			file->private_data = pm8001_ha;
+			err = 0;
+			break;
+		}
+	}
+
+	return err;
+}
+
+/**
+ * pm8001_close - close the configuration file
+ * @inode: inode being opened
+ * @file: file handle attached
+ *
+ * Called when the configuration device is closed. Does the needed
+ * set up on the handle and then returns
+ *
+ */
+static int pm8001_close(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static long pm8001_info_ioctl(struct pm8001_hba_info *pm8001_ha,
+			      unsigned long arg)
+{
+	u32 ret = 0;
+	struct ioctl_info_buffer info_buf;
+	union main_cfg_table main_tbl =  pm8001_ha->main_cfg_tbl;
+
+	strcpy(info_buf.information.sz_name, DRV_NAME);
+
+	info_buf.information.usmajor_revision = DRV_MAJOR;
+	info_buf.information.usminor_revision = DRV_MINOR;
+	info_buf.information.usbuild_revision = DRV_BUILD;
+	if (pm8001_ha->chip_id == chip_8001) {
+		info_buf.information.maxoutstandingIO =
+			main_tbl.pm8001_tbl.max_out_io;
+		info_buf.information.maxdevices =
+			(main_tbl.pm8001_tbl.max_sgl >> 16) & 0xFFFF;
+	} else {
+		info_buf.information.maxoutstandingIO =
+			main_tbl.pm80xx_tbl.max_out_io;
+		info_buf.information.maxdevices =
+			(main_tbl.pm80xx_tbl.max_sgl >> 16) & 0xFFFF;
+	}
+	info_buf.header.return_code = ADPT_IOCTL_CALL_SUCCESS;
+
+	if (copy_to_user((void *)arg, (void *)&info_buf,
+			 sizeof(struct ioctl_info_buffer))) {
+		ret = ADPT_IOCTL_CALL_FAILED;
+	}
+
+	return ret;
+}
+
+static long pm8001_gpio_ioctl(struct pm8001_hba_info *pm8001_ha,
+			      unsigned long arg)
+{
+	struct gpio_buffer buffer;
+	struct pm8001_gpio *payload;
+	struct gpio_ioctl_resp *gpio_resp;
+	DECLARE_COMPLETION_ONSTACK(completion);
+	unsigned long timeout;
+	u32 ret = 0, operation;
+
+	mutex_lock(&pm8001_ha->ioctl_mutex);
+
+	if (copy_from_user(&buffer, (struct gpio_buffer *)arg,
+		sizeof(struct gpio_buffer))) {
+		ret = ADPT_IOCTL_CALL_FAILED;
+		goto exit;
+	}
+
+	pm8001_ha->ioctl_completion = &completion;
+	payload = &buffer.gpio_payload;
+	operation = payload->operation;
+	ret = PM8001_CHIP_DISP->gpio_req(pm8001_ha, payload);
+	if (ret != 0) {
+		ret = ADPT_IOCTL_CALL_FAILED;
+		goto exit;
+	}
+
+	timeout = (unsigned long)buffer.header.timeout * 1000;
+
+	mod_timer(&pm8001_ha->ioctl_timer, jiffies + msecs_to_jiffies(timeout));
+
+	wait_for_completion(&completion);
+
+	if (pm8001_ha->ioctl_timer_expired) {
+		ret = ADPT_IOCTL_CALL_TIMEOUT;
+		goto exit;
+	}
+	gpio_resp = &pm8001_ha->gpio_resp;
+
+	buffer.header.return_code = ADPT_IOCTL_CALL_SUCCESS;
+
+	if (operation == GPIO_READ) {
+		payload->rd_wr_val		= gpio_resp->gpio_rd_val;
+		payload->input_enable		= gpio_resp->gpio_in_enabled;
+		payload->pinsetup1		= gpio_resp->gpio_pinsetup1;
+		payload->pinsetup2		= gpio_resp->gpio_pinsetup2;
+		payload->event_level		= gpio_resp->gpio_evt_change;
+		payload->event_rising_edge	= gpio_resp->gpio_evt_rise;
+		payload->event_falling_edge	= gpio_resp->gpio_evt_fall;
+
+		if (copy_to_user((void *)arg, (void *)&buffer,
+				 sizeof(struct gpio_buffer))) {
+			ret = ADPT_IOCTL_CALL_FAILED;
+		}
+	} else {
+		if (copy_to_user((void *)arg, (void *)&buffer.header,
+				 sizeof(struct ioctl_header))) {
+			ret = ADPT_IOCTL_CALL_FAILED;
+		}
+	}
+exit:
+	pm8001_ha->ioctl_timer_expired = 0;
+	mutex_unlock(&pm8001_ha->ioctl_mutex);
+	return ret;
+}
+
+/**
+ * pm8001_ioctl - pm8001 configuration request
+ * @inode: inode of device
+ * @file: file handle
+ * @cmd: ioctl command code
+ * @arg: argument
+ *
+ * Handles a configuration ioctl.
+ *
+ */
+static long pm8001_ioctl(struct file *file,
+			 unsigned int cmd, unsigned long arg)
+{
+	u32 ret = -EACCES;
+	struct pm8001_hba_info *pm8001_ha;
+	struct ioctl_header header;
+
+	pm8001_ha = file->private_data;
+
+	switch (cmd) {
+
+	case ADPT_IOCTL_GPIO:
+		ret = pm8001_gpio_ioctl(pm8001_ha, arg);
+		break;
+	case ADPT_IOCTL_INFO:
+		ret = pm8001_info_ioctl(pm8001_ha, arg);
+		break;
+	default:
+		ret = ADPT_IOCTL_CALL_INVALID_CODE;
+	}
+	if (ret == 0)
+		return ret;
+	header.return_code = ret;
+	ret = -EACCES;
+	if (copy_to_user((void *)arg, (void *)&header,
+			sizeof(struct ioctl_header))) {
+		return -EFAULT;
+	}
+	PM8001_FAIL_DBG(pm8001_ha, pm8001_printk("IOCTL failed\n"));
+	return ret;
+}
+
+/**
+ * pm8001_poll - pm8001 poll request function
+ * @file: file handle
+ * @wait: poll table to wait
+ *
+ * Handles a poll request.
+ *
+ */
+unsigned int pm8001_poll(struct file *file, poll_table *wait)
+{
+	struct pm8001_hba_info *pm8001_ha;
+	unsigned int mask = 0;
+
+	pm8001_ha = file->private_data;
+
+	poll_wait(file, &pm8001_ha->pollq, wait);
+
+	if (pm8001_ha->gpio_event_occured == 1) {
+		pm8001_ha->gpio_event_occured = 0;
+		mask |= POLLIN | POLLRDNORM;
+	}
+
+	return mask;
+}
+
+static const struct file_operations pm8001_fops = {
+	.owner		= THIS_MODULE,
+	.open		= pm8001_open,
+	.release	= pm8001_close,
+	.unlocked_ioctl	= pm8001_ioctl,
+	.poll		= pm8001_poll,
+};
+
+/**
+ * pm8001_setup_chrdev - registers a char device
+ *
+ * Return value
+ *	0 in case of success, otherwise non-zero
+ */
+int pm8001_setup_chrdev(void)
+{
+	pm8001_major = register_chrdev(0, DRV_NAME, &pm8001_fops);
+	if (pm8001_major < 0) {
+		pr_warn("pm8001 : unable to register \"%s\" device\n",
+				DRV_NAME);
+		return pm8001_major;
+	}
+	return 0;
+}
+
+/**
+ * pm8001_release_chrdev - unregisters per-adapter management interface
+ *
+ * Return value
+ *	none
+ */
+void pm8001_release_chrdev(void)
+{
+	if (pm8001_major > -1) {
+		unregister_chrdev(pm8001_major, DRV_NAME);
+		pm8001_major = -1;
+	}
+}
+
diff --git a/drivers/scsi/pm8001/pm8001_ctl.h b/drivers/scsi/pm8001/pm8001_ctl.h
index d0d43a2..0064dd3 100644
--- a/drivers/scsi/pm8001/pm8001_ctl.h
+++ b/drivers/scsi/pm8001/pm8001_ctl.h
@@ -55,6 +55,61 @@
 #define FAIL_OUT_MEMORY                 0x000c00
 #define FLASH_IN_PROGRESS               0x001000
 
+#define ADPT_IOCTL_CALL_SUCCESS		0x00
+#define ADPT_IOCTL_CALL_FAILED		0x01
+#define ADPT_IOCTL_CALL_INVALID_CODE	0x03
+#define ADPT_IOCTL_CALL_INVALID_DEVICE	0x04
+#define ADPT_IOCTL_CALL_TIMEOUT		0x08
+
+#define GPIO_READ	0
+#define GPIO_WRITE	1
+#define GPIO_PINSETUP	2
+#define GPIO_EVENTSETUP	3
+
+struct ioctl_header {
+	u32 io_controller_num;
+	u32 length;
+	u32 return_code;
+	u32 timeout;
+	u32 direction;
+};
+
+struct ioctl_drv_info {
+	u8	sz_name[64];
+	u16	usmajor_revision;
+	u16	usminor_revision;
+	u16	usbuild_revision;
+	u16	reserved0;
+	u32	maxdevices;
+	u32	maxoutstandingIO;
+	u32	reserved[16];
+};
+
+struct pm8001_gpio {
+	u32 operation;
+	u32 mask;
+	u32 rd_wr_val;
+	u32 input_enable;
+	u32 pinsetup1;
+	u32 pinsetup2;
+	u32 event_level;
+	u32 event_rising_edge;
+	u32 event_falling_edge;
+};
+
+struct ioctl_info_buffer {
+	struct ioctl_header	header;
+	struct ioctl_drv_info	information;
+};
+
+struct gpio_buffer {
+	struct ioctl_header	header;
+	struct pm8001_gpio	gpio_payload;
+};
+
+#define ADPT_IOCTL_INFO		_IOR(0, 0, struct ioctl_info_buffer *)
+#define ADPT_IOCTL_GPIO		_IOWR(0, 1, struct  gpio_buffer *)
+
 #define IB_OB_READ_TIMES                256
 #define SYSFS_OFFSET                    1024
 #define PM80XX_IB_OB_QUEUE_SIZE         (32 * 1024)
diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c
index 662bf13..ba2e659 100644
--- a/drivers/scsi/pm8001/pm8001_init.c
+++ b/drivers/scsi/pm8001/pm8001_init.c
@@ -148,6 +148,8 @@ static void pm8001_free(struct pm8001_hba_info *pm8001_ha)
 	if (!pm8001_ha)
 		return;
 
+	del_timer(&pm8001_ha->ioctl_timer);
+
 	for (i = 0; i < USI_MAX_MEMCNT; i++) {
 		if (pm8001_ha->memoryMap.region[i].virt_ptr != NULL) {
 			pci_free_consistent(pm8001_ha->pdev,
@@ -444,6 +446,24 @@ static int pm8001_ioremap(struct pm8001_hba_info *pm8001_ha)
 	return 0;
 }
 
+void pm8001_ioctl_timer_callback(unsigned long data)
+{
+	struct pm8001_hba_info *pm8001_ha = (struct pm8001_hba_info *)data;
+
+	PM8001_FAIL_DBG(pm8001_ha,
+		pm8001_printk("Timer expired for GPIO response\n"));
+
+	spin_lock(&pm8001_ha->ioctl_lock);
+
+	if (pm8001_ha->ioctl_completion != NULL) {
+		pm8001_ha->ioctl_timer_expired = 1;
+		complete(pm8001_ha->ioctl_completion);
+		pm8001_ha->ioctl_completion = NULL;
+	}
+
+	spin_unlock(&pm8001_ha->ioctl_lock);
+}
+
 /**
  * pm8001_pci_alloc - initialize our ha card structure
  * @pdev: pci device.
@@ -479,6 +499,15 @@ static struct pm8001_hba_info *pm8001_pci_alloc(struct pci_dev *pdev,
 	else
 		pm8001_ha->iomb_size = IOMB_SIZE_SPC;
 
+	mutex_init(&pm8001_ha->ioctl_mutex);
+	pm8001_ha->ioctl_completion = NULL;
+	init_waitqueue_head(&pm8001_ha->pollq);
+	pm8001_ha->gpio_event_occured = 0;
+	spin_lock_init(&pm8001_ha->ioctl_lock);
+	setup_timer(&pm8001_ha->ioctl_timer, pm8001_ioctl_timer_callback,
+		     (unsigned long)pm8001_ha);
+
+
 #ifdef PM8001_USE_TASKLET
 	/**
 	* default tasklet for non msi-x interrupt handler/first msi-x
@@ -1147,8 +1176,15 @@ static int __init pm8001_init(void)
 	rc = pci_register_driver(&pm8001_pci_driver);
 	if (rc)
 		goto err_tp;
+
+	rc = pm8001_setup_chrdev();
+	if (rc)
+		goto err_ctl;
+
 	return 0;
 
+err_ctl:
+	pci_unregister_driver(&pm8001_pci_driver);
 err_tp:
 	sas_release_transport(pm8001_stt);
 err_wq:
@@ -1162,6 +1198,7 @@ static void __exit pm8001_exit(void)
 	pci_unregister_driver(&pm8001_pci_driver);
 	sas_release_transport(pm8001_stt);
 	destroy_workqueue(pm8001_wq);
+	pm8001_release_chrdev();
 }
 
 module_init(pm8001_init);
diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h
index 9241c04..9171f0a 100644
--- a/drivers/scsi/pm8001/pm8001_sas.h
+++ b/drivers/scsi/pm8001/pm8001_sas.h
@@ -51,14 +51,21 @@
 #include <linux/pci.h>
 #include <linux/interrupt.h>
 #include <linux/workqueue.h>
+#include <linux/poll.h>
+#include <linux/poll.h>
+#include <linux/timer.h>
 #include <scsi/libsas.h>
 #include <scsi/scsi_tcq.h>
 #include <scsi/sas_ata.h>
 #include <linux/atomic.h>
 #include "pm8001_defs.h"
+#include "pm8001_ctl.h"
 
 #define DRV_NAME		"pm80xx"
 #define DRV_VERSION		"0.1.37"
+#define DRV_MAJOR		1
+#define DRV_MINOR		0
+#define DRV_BUILD		15
 #define PM8001_FAIL_LOGGING	0x01 /* Error message logging */
 #define PM8001_INIT_LOGGING	0x02 /* driver init logging */
 #define PM8001_DISC_LOGGING	0x04 /* discovery layer logging */
@@ -132,6 +139,17 @@ struct pm8001_ioctl_payload {
 	u8	*func_specific;
 };
 
+struct gpio_ioctl_resp {
+	u32 tag;
+	u32 gpio_rd_val;
+	u32 gpio_in_enabled;
+	u32 gpio_pinsetup1;
+	u32 gpio_pinsetup2;
+	u32 gpio_evt_change;
+	u32 gpio_evt_rise;
+	u32 gpio_evt_fall;
+};
+
 #define MPI_FATAL_ERROR_TABLE_OFFSET_MASK 0xFFFFFF
 #define MPI_FATAL_ERROR_TABLE_SIZE(value) ((0xFF000000 & value) >> SHIFT24)
 #define MPI_FATAL_EDUMP_TABLE_LO_OFFSET            0x00     /* HNFBUFL */
@@ -229,6 +247,8 @@ struct pm8001_dispatch {
 	int (*sas_diag_execute_req)(struct pm8001_hba_info *pm8001_ha,
 		u32 state);
 	int (*sas_re_init_req)(struct pm8001_hba_info *pm8001_ha);
+	int (*gpio_req)(struct pm8001_hba_info *pm8001_ha,
+		struct pm8001_gpio *gpio_payload);
 };
 
 struct pm8001_chip_info {
@@ -527,6 +547,14 @@ struct pm8001_hba_info {
 	u32			int_vector;
 	const struct firmware 	*fw_image;
 	u8			outq[PM8001_MAX_MSIX_VEC];
+	struct completion	*ioctl_completion;
+	struct mutex		ioctl_mutex;
+	spinlock_t		ioctl_lock;
+	u32			gpio_event_occured;
+	u32			ioctl_timer_expired;
+	struct timer_list	ioctl_timer;
+	struct gpio_ioctl_resp	gpio_resp;
+	wait_queue_head_t	pollq;
 };
 
 struct pm8001_work {
@@ -705,5 +733,7 @@ ssize_t pm8001_get_gsm_dump(struct device *cdev, u32, char *buf);
 /* ctl shared API */
 extern struct device_attribute *pm8001_host_attrs[];
 
+int pm8001_setup_chrdev(void);
+void pm8001_release_chrdev(void);
 #endif
 
diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c
index 4ebc79b..5423844 100644
--- a/drivers/scsi/pm8001/pm80xx_hwi.c
+++ b/drivers/scsi/pm8001/pm80xx_hwi.c
@@ -3481,6 +3481,54 @@ static int ssp_coalesced_comp_resp(struct pm8001_hba_info *pm8001_ha,
 	return 0;
 }
 
+static int mpi_gpio_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
+{
+	int ret;
+	struct gpio_ioctl_resp *pgpio_resp;
+	struct gpio_resp *ppayload = (struct gpio_resp *)(piomb + 4);
+
+	spin_lock(&pm8001_ha->ioctl_lock);
+	if (pm8001_ha->ioctl_completion != NULL) {
+		ret = del_timer(&pm8001_ha->ioctl_timer);
+		if (ret)
+			PM8001_MSG_DBG(pm8001_ha,
+				pm8001_printk("The timer was still in use.\n"));
+		pm8001_ha->ioctl_timer_expired = 0;
+		pgpio_resp = &pm8001_ha->gpio_resp;
+		pgpio_resp->gpio_rd_val = le32_to_cpu(ppayload->gpio_rd_val);
+		pgpio_resp->gpio_in_enabled =
+			le32_to_cpu(ppayload->gpio_in_enabled);
+		pgpio_resp->gpio_pinsetup1 =
+			le32_to_cpu(ppayload->gpio_pinsetup1);
+		pgpio_resp->gpio_pinsetup2 =
+			le32_to_cpu(ppayload->gpio_pinsetup2);
+		pgpio_resp->gpio_evt_change =
+			le32_to_cpu(ppayload->gpio_evt_change);
+		pgpio_resp->gpio_evt_rise =
+			le32_to_cpu(ppayload->gpio_evt_rise);
+		pgpio_resp->gpio_evt_fall =
+			le32_to_cpu(ppayload->gpio_evt_fall);
+
+		complete(pm8001_ha->ioctl_completion);
+		pm8001_ha->ioctl_completion = NULL;
+	}
+	spin_unlock(&pm8001_ha->ioctl_lock);
+	return 0;
+}
+
+static int mpi_gpio_event(struct pm8001_hba_info *pm8001_ha, void *piomb)
+{
+
+	u32 gpio_event = 0;
+	struct gpio_event *ppayload = (struct gpio_event *)(piomb + 4);
+	gpio_event = le32_to_cpu(ppayload->gpio_event);
+	PM8001_MSG_DBG(pm8001_ha,
+		       pm8001_printk("GPIO event: 0x%X\n", gpio_event));
+	pm8001_ha->gpio_event_occured = 1;
+	wake_up_interruptible(&pm8001_ha->pollq);
+	return 0;
+}
+
 /**
  * process_one_iomb - process one outbound Queue memory block
  * @pm8001_ha: our hba card information
@@ -3567,10 +3615,12 @@ static void process_one_iomb(struct pm8001_hba_info *pm8001_ha, void *piomb)
 	case OPC_OUB_GPIO_RESPONSE:
 		PM8001_MSG_DBG(pm8001_ha,
 			pm8001_printk("OPC_OUB_GPIO_RESPONSE\n"));
+		mpi_gpio_resp(pm8001_ha, piomb);
 		break;
 	case OPC_OUB_GPIO_EVENT:
 		PM8001_MSG_DBG(pm8001_ha,
 			pm8001_printk("OPC_OUB_GPIO_EVENT\n"));
+		mpi_gpio_event(pm8001_ha, piomb);
 		break;
 	case OPC_OUB_GENERAL_EVENT:
 		PM8001_MSG_DBG(pm8001_ha,
@@ -4510,6 +4560,61 @@ static u32 pm80xx_chip_is_our_interupt(struct pm8001_hba_info *pm8001_ha)
 }
 
 /**
+ * pm80xx_chip_gpio_req - support for GPIO operation
+ * @pm8001_ha: our hba card information.
+ * @ioctl_payload: the payload for the GPIO operation
+ */
+
+int pm80xx_chip_gpio_req(struct pm8001_hba_info *pm8001_ha,
+				struct pm8001_gpio *gpio_payload)
+{
+	struct gpio_req payload;
+	struct inbound_queue_table *circularQ;
+	int ret;
+	u32 tag;
+	u32 opc = OPC_INB_GPIO;
+
+	if (pm8001_ha->pdev->subsystem_vendor == PCI_VENDOR_ID_ADAPTEC2)
+		return ADPT_IOCTL_CALL_INVALID_DEVICE;
+
+	ret = pm8001_tag_alloc(pm8001_ha, &tag);
+	if (ret)
+		return -1;
+
+	memset(&payload, 0, sizeof(payload));
+	circularQ = &pm8001_ha->inbnd_q_tbl[0];
+	payload.tag = cpu_to_le32(tag);
+	switch (gpio_payload->operation) {
+	case GPIO_READ:
+		payload.eobid_ge_gs_gr_gw = cpu_to_le32(GPIO_GR_BIT);
+		break;
+	case GPIO_WRITE:
+		payload.eobid_ge_gs_gr_gw = cpu_to_le32(GPIO_GW_BIT);
+		payload.gpio_wr_msk = cpu_to_le32(gpio_payload->mask);
+		payload.gpio_wr_val = cpu_to_le32(gpio_payload->rd_wr_val);
+		break;
+	case GPIO_PINSETUP:
+		payload.eobid_ge_gs_gr_gw = cpu_to_le32(GPIO_GS_BIT);
+		payload.gpio_in_enabled =
+			cpu_to_le32(gpio_payload->input_enable);
+		payload.gpio_pinsetup1 = cpu_to_le32(gpio_payload->pinsetup1);
+		payload.gpio_pinsetup2 = cpu_to_le32(gpio_payload->pinsetup2);
+		break;
+	case GPIO_EVENTSETUP:
+		payload.eobid_ge_gs_gr_gw = cpu_to_le32(GPIO_GE_BIT);
+		payload.gpio_evt_change =
+			cpu_to_le32(gpio_payload->event_level);
+		payload.gpio_evt_rise =
+			cpu_to_le32(gpio_payload->event_rising_edge);
+		payload.gpio_evt_fall =
+			cpu_to_le32(gpio_payload->event_falling_edge);
+		break;
+	}
+	ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0);
+	return ret;
+}
+
+/**
  * pm8001_chip_isr - PM8001 isr handler.
  * @pm8001_ha: our hba card information.
  * @irq: irq number.
@@ -4589,4 +4694,5 @@ const struct pm8001_dispatch pm8001_80xx_dispatch = {
 	.set_nvmd_req		= pm8001_chip_set_nvmd_req,
 	.fw_flash_update_req	= pm8001_chip_fw_flash_update_req,
 	.set_dev_state_req	= pm8001_chip_set_dev_state_req,
+	.gpio_req		= pm80xx_chip_gpio_req,
 };
diff --git a/drivers/scsi/pm8001/pm80xx_hwi.h b/drivers/scsi/pm8001/pm80xx_hwi.h
index c86816b..671940a 100644
--- a/drivers/scsi/pm8001/pm80xx_hwi.h
+++ b/drivers/scsi/pm8001/pm80xx_hwi.h
@@ -422,6 +422,55 @@ struct hw_event_ack_req {
 } __attribute__((packed, aligned(4)));
 
 /*
+ * brief the data structure of GPIO Commannd
+ * use to control MPI GPIOs (64 bytes)
+ */
+struct gpio_req {
+	__le32  tag;
+	__le32  eobid_ge_gs_gr_gw;
+	__le32  gpio_wr_msk;
+	__le32  gpio_wr_val;
+	__le32  gpio_in_enabled;
+	__le32  gpio_pinsetup1;
+	__le32  gpio_pinsetup2;
+	__le32  gpio_evt_change;
+	__le32  gpio_evt_rise;
+	__le32  gpio_evt_fall;
+	u32     reserved[5];
+} __attribute__((packed, aligned(4)));
+
+#define GPIO_GW_BIT 0x1
+#define GPIO_GR_BIT 0x2
+#define GPIO_GS_BIT 0x4
+#define GPIO_GE_BIT 0x8
+
+/*
+ * brief the data structure of GPIO Response
+ * indicates the completion of GPIO command (64 bytes)
+ */
+struct gpio_resp {
+	__le32  tag;
+	u32     reserved[2];
+	__le32  gpio_rd_val;
+	__le32  gpio_in_enabled;
+	__le32  gpio_pinsetup1;
+	__le32  gpio_pinsetup2;
+	__le32  gpio_evt_change;
+	__le32  gpio_evt_rise;
+	__le32  gpio_evt_fall;
+	u32     reserved1[5];
+} __attribute__((packed, aligned(4)));
+
+/*
+ * brief the data structure of GPIO Event
+ * indicates the generation of GPIO event (64 bytes)
+ */
+struct gpio_event {
+	__le32  gpio_event;
+	u32     reserved[14];
+} __attribute__((packed, aligned(4)));
+
+/*
  * brief the data structure of PHY_START Response Command
  * indicates the completion of PHY_START command (64 bytes)
  */
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2013-11-16 18:26 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-10-22 12:20 [PATCH 11/11] pm80xx : gpio feature support for motherboard controllers Viswas G
2013-10-29 10:19 ` Jack Wang
2013-11-04 10:13   ` Viswas G
2013-11-04 10:30     ` Jack Wang
2013-11-11  5:57       ` Viswas G
2013-11-11  8:58         ` Jack Wang
2013-11-15  6:14           ` Viswas G
2013-11-16 18:25           ` James Bottomley

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.