From cbdaffd8ec00c42338527f427815139106783e6a Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Wed, 8 Jun 2016 22:51:04 -0700 Subject: [PATCH 1/1] gpio: Drop smp2p and smsm implementations The smem state implementations where rejected by the GPIO maintainer and has been superseeded. Remove these old and rejected implementations. Signed-off-by: Bjorn Andersson --- drivers/gpio/Kconfig | 15 - drivers/gpio/Makefile | 2 - drivers/gpio/gpio-qcom-smp2p.c | 590 --------------------------------- drivers/gpio/gpio-qcom-smsm.c | 327 ------------------ 4 files changed, 934 deletions(-) delete mode 100644 drivers/gpio/gpio-qcom-smp2p.c delete mode 100644 drivers/gpio/gpio-qcom-smsm.c diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index caf36519f410..b18bea08ff25 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -337,21 +337,6 @@ config GPIO_PXA help Say yes here to support the PXA GPIO device -config GPIO_QCOM_SMSM - bool "Qualcomm Shared Memory State Machine" - depends on QCOM_SMEM - help - Say yes here to support the Qualcomm Shared Memory State Machine. - The state machine is represented by bits in shared memory and is - exposed to the system as GPIOs. - -config GPIO_QCOM_SMP2P - bool "Qualcomm Shared Memory Point to Point support" - depends on QCOM_SMEM - help - Say yes here to support the Qualcomm Shared Memory Point to Point - protocol, exposed to the system as GPIOs. - config GPIO_RCAR tristate "Renesas R-Car GPIO" depends on ARCH_SHMOBILE || COMPILE_TEST diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 6c9d22e86b31..986dbd838cea 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -76,8 +76,6 @@ obj-$(CONFIG_GPIO_PCF857X) += gpio-pcf857x.o obj-$(CONFIG_GPIO_PCH) += gpio-pch.o obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o obj-$(CONFIG_GPIO_PXA) += gpio-pxa.o -obj-$(CONFIG_GPIO_QCOM_SMSM) += gpio-qcom-smsm.o -obj-$(CONFIG_GPIO_QCOM_SMP2P) += gpio-qcom-smp2p.o obj-$(CONFIG_GPIO_RC5T583) += gpio-rc5t583.o obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc321x.o obj-$(CONFIG_GPIO_RCAR) += gpio-rcar.o diff --git a/drivers/gpio/gpio-qcom-smp2p.c b/drivers/gpio/gpio-qcom-smp2p.c deleted file mode 100644 index 164f39afebb3..000000000000 --- a/drivers/gpio/gpio-qcom-smp2p.c +++ /dev/null @@ -1,590 +0,0 @@ -/* - * Copyright (c) 2015, Sony Mobile Communications AB. - * Copyright (c) 2012-2013, 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -/* - * The Shared Memory Point to Point (SMP2P) protocol facilitates communication - * of a single 32-bit value between two processors. Each value has a single - * writer (the local side) and a single reader (the remote side). Values are - * uniquely identified in the system by the directed edge (local processor ID - * to remote processor ID) and a string identifier. - * - * Each processor is responsible for creating the outgoing SMEM items and each - * item is writable by the local processor and readable by the remote - * processor. By using two separate SMEM items that are single-reader and - * single-writer, SMP2P does not require any remote locking mechanisms. - * - * The driver uses the Linux GPIO and interrupt framework to expose a virtual - * GPIO for each outbound entry and a virtual interrupt controller for each - * inbound entry. - */ - -#define SMP2P_MAX_ENTRY 16 -#define SMP2P_MAX_ENTRY_NAME 16 - -#define SMP2P_FEATURE_SSR_ACK 0x1 - -#define SMP2P_MAGIC 0x504d5324 - -/** - * struct smp2p_smem_item - in memory communication structure - * @magic: magic number - * @version: version - must be 1 - * @features: features flag - currently unused - * @local_pid: processor id of sending end - * @remote_pid: processor id of receiving end - * @total_entries: number of entries - always SMP2P_MAX_ENTRY - * @valid_entries: number of allocated entries - * @flags: - * @entries: individual communication entries - * @name: name of the entry - * @value: content of the entry - */ -struct smp2p_smem_item { - u32 magic; - u8 version; - unsigned features:24; - u16 local_pid; - u16 remote_pid; - u16 total_entries; - u16 valid_entries; - u32 flags; - - struct { - u8 name[SMP2P_MAX_ENTRY_NAME]; - u32 value; - } entries[SMP2P_MAX_ENTRY]; -} __packed; - -/** - * struct smp2p_entry - driver context matching one entry - * @node: list entry to keep track of allocated entries - * @smp2p: reference to the device driver context - * @name: name of the entry, to match against smp2p_smem_item - * @value: pointer to smp2p_smem_item entry value - * @last_value: last handled value - * @domain: irq_domain for inbound entries - * @irq_enabled:bitmap to track enabled irq bits - * @irq_rising: bitmap to mark irq bits for rising detection - * @irq_falling:bitmap to mark irq bits for falling detection - * @chip: gpio_chip for outbound entries - */ -struct smp2p_entry { - struct list_head node; - struct qcom_smp2p *smp2p; - - const char *name; - u32 *value; - u32 last_value; - - struct irq_domain *domain; - DECLARE_BITMAP(irq_enabled, 32); - DECLARE_BITMAP(irq_rising, 32); - DECLARE_BITMAP(irq_falling, 32); - - struct gpio_chip chip; -}; - -#define SMP2P_INBOUND 0 -#define SMP2P_OUTBOUND 1 - -/** - * struct qcom_smp2p - device driver context - * @dev: device driver handle - * @in: pointer to the inbound smem item - * @smem_items: ids of the two smem items - * @valid_entries: already scanned inbound entries - * @local_pid: processor id of the inbound edge - * @remote_pid: processor id of the outbound edge - * @ipc_regmap: regmap for the outbound ipc - * @ipc_offset: offset within the regmap - * @ipc_bit: bit in regmap@offset to kick to signal remote processor - * @inbound: list of inbound entries - * @outbound: list of outbound entries - */ -struct qcom_smp2p { - struct device *dev; - - struct smp2p_smem_item *in; - struct smp2p_smem_item *out; - - unsigned smem_items[SMP2P_OUTBOUND + 1]; - - unsigned valid_entries; - - unsigned local_pid; - unsigned remote_pid; - - struct regmap *ipc_regmap; - int ipc_offset; - int ipc_bit; - - struct list_head inbound; - struct list_head outbound; -}; - -static void qcom_smp2p_kick(struct qcom_smp2p *smp2p) -{ - /* Make sure any updated data is written before the kick */ - wmb(); - regmap_write(smp2p->ipc_regmap, smp2p->ipc_offset, BIT(smp2p->ipc_bit)); -} - -static irqreturn_t qcom_smp2p_intr(int irq, void *data) -{ - struct smp2p_smem_item *in; - struct smp2p_entry *entry; - struct qcom_smp2p *smp2p = data; - unsigned smem_id = smp2p->smem_items[SMP2P_INBOUND]; - unsigned pid = smp2p->remote_pid; - size_t size; - int irq_pin; - u32 status; - u32 val; - int i; - u8 tmp_name[SMP2P_MAX_ENTRY_NAME]; - - in = smp2p->in; - - /* Acquire smem item, if not already found */ - if (!in) { - in = qcom_smem_get(pid, smem_id, &size); - if (IS_ERR(in)) { - dev_err(smp2p->dev, - "Unable to acquire remote smp2p item\n"); - return IRQ_HANDLED; - } - - smp2p->in = in; - } - - /* Match newly created entries */ - for (i = smp2p->valid_entries; i < in->valid_entries; i++) { - list_for_each_entry(entry, &smp2p->inbound, node) { - memcpy_fromio(tmp_name, in->entries[i].name, - SMP2P_MAX_ENTRY_NAME); - if (!strcmp(tmp_name, entry->name)) { - entry->value = &in->entries[i].value; - break; - } - } - } - smp2p->valid_entries = i; - - /* Fire interrupts based on any value changes */ - list_for_each_entry(entry, &smp2p->inbound, node) { - /* Ignore entries not yet allocated by the remote side */ - if (!entry->value) - continue; - - val = *entry->value; - - status = val ^ entry->last_value; - entry->last_value = val; - - /* No changes of this entry? */ - if (!status) - continue; - - for_each_set_bit(i, entry->irq_enabled, 32) { - if (!(status & BIT(i))) - continue; - - if (val & BIT(i)) { - if (test_bit(i, entry->irq_rising)) { - irq_pin = irq_find_mapping(entry->domain, i); - handle_nested_irq(irq_pin); - } - } else { - if (test_bit(i, entry->irq_falling)) { - irq_pin = irq_find_mapping(entry->domain, i); - handle_nested_irq(irq_pin); - } - } - - } - } - - return IRQ_HANDLED; -} - -static void smp2p_mask_irq(struct irq_data *irqd) -{ - struct smp2p_entry *entry = irq_data_get_irq_chip_data(irqd); - irq_hw_number_t irq = irqd_to_hwirq(irqd); - - clear_bit(irq, entry->irq_enabled); -} - -static void smp2p_unmask_irq(struct irq_data *irqd) -{ - struct smp2p_entry *entry = irq_data_get_irq_chip_data(irqd); - irq_hw_number_t irq = irqd_to_hwirq(irqd); - - set_bit(irq, entry->irq_enabled); -} - -static int smp2p_set_irq_type(struct irq_data *irqd, unsigned int type) -{ - struct smp2p_entry *entry = irq_data_get_irq_chip_data(irqd); - irq_hw_number_t irq = irqd_to_hwirq(irqd); - - if (!(type & IRQ_TYPE_EDGE_BOTH)) - return -EINVAL; - - if (type & IRQ_TYPE_EDGE_RISING) - set_bit(irq, entry->irq_rising); - else - clear_bit(irq, entry->irq_rising); - - if (type & IRQ_TYPE_EDGE_FALLING) - set_bit(irq, entry->irq_falling); - else - clear_bit(irq, entry->irq_falling); - - return 0; -} - -static struct irq_chip smp2p_irq_chip = { - .name = "smp2p", - .irq_mask = smp2p_mask_irq, - .irq_unmask = smp2p_unmask_irq, - .irq_set_type = smp2p_set_irq_type, -}; - -static int smp2p_irq_map(struct irq_domain *d, - unsigned int irq, - irq_hw_number_t hw) -{ - struct smp2p_entry *entry = d->host_data; - - irq_set_chip_and_handler(irq, &smp2p_irq_chip, handle_level_irq); - irq_set_chip_data(irq, entry); - irq_set_nested_thread(irq, 1); - - irq_set_noprobe(irq); - - return 0; -} - -static const struct irq_domain_ops smp2p_irq_ops = { - .map = smp2p_irq_map, - .xlate = irq_domain_xlate_twocell, -}; - -static int smp2p_gpio_direction_output(struct gpio_chip *chip, - unsigned offset, - int value) -{ - struct smp2p_entry *entry = container_of(chip, struct smp2p_entry, chip); - - if (value) - *entry->value |= BIT(offset); - else - *entry->value &= ~BIT(offset); - - qcom_smp2p_kick(entry->smp2p); - - return 0; -} - -static void smp2p_gpio_set(struct gpio_chip *chip, unsigned offset, int value) -{ - smp2p_gpio_direction_output(chip, offset, value); -} - -static int qcom_smp2p_inbound_entry(struct qcom_smp2p *smp2p, - struct smp2p_entry *entry, - struct device_node *node) -{ - entry->domain = irq_domain_add_linear(node, 32, &smp2p_irq_ops, entry); - if (!entry->domain) { - dev_err(smp2p->dev, "failed to add irq_domain\n"); - return -ENOMEM; - } - - return 0; -} - -static int qcom_smp2p_outbound_entry(struct qcom_smp2p *smp2p, - struct smp2p_entry *entry, - struct device_node *node) -{ - struct smp2p_smem_item *out = smp2p->out; - struct gpio_chip *chip; - int ret; - - /* Allocate an entry from the smem item */ - memcpy_toio(out->entries[out->valid_entries].name, entry->name, SMP2P_MAX_ENTRY_NAME); - out->valid_entries++; - - /* Make the logical entry reference the physical value */ - entry->value = &out->entries[out->valid_entries].value; - - chip = &entry->chip; - chip->base = -1; - chip->ngpio = 32; - chip->label = entry->name; - chip->dev = smp2p->dev; - chip->owner = THIS_MODULE; - chip->of_node = node; - - chip->set = smp2p_gpio_set; - chip->direction_output = smp2p_gpio_direction_output; - - ret = gpiochip_add(chip); - if (ret) - dev_err(smp2p->dev, "failed register gpiochip\n"); - - return 0; -} - -static int qcom_smp2p_alloc_outbound_item(struct qcom_smp2p *smp2p) -{ - struct smp2p_smem_item *out; - unsigned smem_id = smp2p->smem_items[SMP2P_OUTBOUND]; - unsigned pid = smp2p->remote_pid; - int ret; - - ret = qcom_smem_alloc(pid, smem_id, sizeof(*out)); - if (ret < 0 && ret != -EEXIST) { - if (ret != -EPROBE_DEFER) - dev_err(smp2p->dev, - "unable to allocate local smp2p item\n"); - return ret; - } - - out = qcom_smem_get(pid, smem_id, NULL); - if (IS_ERR(out)) { - dev_err(smp2p->dev, "Unable to acquire local smp2p item\n"); - return PTR_ERR(out); - } - - memset_io(out, 0, sizeof(*out)); - out->magic = SMP2P_MAGIC; - out->local_pid = smp2p->local_pid; - out->remote_pid = smp2p->remote_pid; - out->total_entries = SMP2P_MAX_ENTRY; - out->valid_entries = 0; - - /* - * Make sure the rest of the header is written before we validate the - * item by writing a valid version number. - */ - wmb(); - out->version = 1; - - qcom_smp2p_kick(smp2p); - - smp2p->out = out; - - return 0; -} - -static int smp2p_parse_ipc(struct qcom_smp2p *smp2p) -{ - struct device_node *syscon; - struct device *dev = smp2p->dev; - const char *key; - int ret; - - syscon = of_parse_phandle(dev->of_node, "qcom,ipc", 0); - if (!syscon) { - dev_err(dev, "no qcom,ipc node\n"); - return -ENODEV; - } - - smp2p->ipc_regmap = syscon_node_to_regmap(syscon); - if (IS_ERR(smp2p->ipc_regmap)) - return PTR_ERR(smp2p->ipc_regmap); - - key = "qcom,ipc"; - ret = of_property_read_u32_index(dev->of_node, key, 1, &smp2p->ipc_offset); - if (ret < 0) { - dev_err(dev, "no offset in %s\n", key); - return -EINVAL; - } - - ret = of_property_read_u32_index(dev->of_node, key, 2, &smp2p->ipc_bit); - if (ret < 0) { - dev_err(dev, "no bit in %s\n", key); - return -EINVAL; - } - - return 0; -} - -static int qcom_smp2p_probe(struct platform_device *pdev) -{ - struct smp2p_entry *entry; - struct device_node *node; - struct qcom_smp2p *smp2p; - const char *key; - int irq; - int ret; - - smp2p = devm_kzalloc(&pdev->dev, sizeof(*smp2p), GFP_KERNEL); - if (!smp2p) - return -ENOMEM; - - smp2p->dev = &pdev->dev; - INIT_LIST_HEAD(&smp2p->inbound); - INIT_LIST_HEAD(&smp2p->outbound); - - platform_set_drvdata(pdev, smp2p); - - ret = smp2p_parse_ipc(smp2p); - if (ret) - return ret; - - key = "qcom,smem"; - ret = of_property_read_u32_array(pdev->dev.of_node, key, - smp2p->smem_items, 2); - if (ret) - return ret; - - key = "qcom,local-pid"; - ret = of_property_read_u32(pdev->dev.of_node, key, &smp2p->local_pid); - if (ret < 0) { - dev_err(&pdev->dev, "failed to read %s\n", key); - return -EINVAL; - } - - key = "qcom,remote-pid"; - ret = of_property_read_u32(pdev->dev.of_node, key, &smp2p->remote_pid); - if (ret < 0) { - dev_err(&pdev->dev, "failed to read %s\n", key); - return -EINVAL; - } - - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "unable to acquire smp2p interrupt\n"); - return irq; - } - - ret = qcom_smp2p_alloc_outbound_item(smp2p); - if (ret < 0) - return ret; - - for_each_available_child_of_node(pdev->dev.of_node, node) { - entry = devm_kzalloc(&pdev->dev, sizeof(*entry), GFP_KERNEL); - if (!entry) { - ret = -ENOMEM; - goto unwind_interfaces; - } - - entry->smp2p = smp2p; - - ret = of_property_read_string(node, "qcom,entry-name", &entry->name); - if (ret < 0) - goto unwind_interfaces; - - if (of_property_read_bool(node, "qcom,inbound")) { - ret = qcom_smp2p_inbound_entry(smp2p, entry, node); - if (ret < 0) - goto unwind_interfaces; - - list_add(&entry->node, &smp2p->inbound); - } else if (of_property_read_bool(node, "qcom,outbound")) { - ret = qcom_smp2p_outbound_entry(smp2p, entry, node); - if (ret < 0) - goto unwind_interfaces; - - list_add(&entry->node, &smp2p->outbound); - } else { - dev_err(&pdev->dev, "neither inbound nor outbound\n"); - ret = -EINVAL; - goto unwind_interfaces; - } - } - - /* Kick the outgoing edge after allocating entries */ - qcom_smp2p_kick(smp2p); - - ret = devm_request_threaded_irq(&pdev->dev, irq, - NULL, qcom_smp2p_intr, - IRQF_ONESHOT, - "smp2p", (void *)smp2p); - if (ret) { - dev_err(&pdev->dev, "failed to request interrupt\n"); - goto unwind_interfaces; - } - - - return 0; - -unwind_interfaces: - list_for_each_entry(entry, &smp2p->inbound, node) - irq_domain_remove(entry->domain); - - list_for_each_entry(entry, &smp2p->outbound, node) - gpiochip_remove(&entry->chip); - - smp2p->out->valid_entries = 0; - - return ret; -} - -static int qcom_smp2p_remove(struct platform_device *pdev) -{ - struct qcom_smp2p *smp2p = platform_get_drvdata(pdev); - struct smp2p_entry *entry; - - list_for_each_entry(entry, &smp2p->inbound, node) - irq_domain_remove(entry->domain); - - list_for_each_entry(entry, &smp2p->outbound, node) - gpiochip_remove(&entry->chip); - - smp2p->out->valid_entries = 0; - - return 0; -} - -static const struct of_device_id qcom_smp2p_of_match[] = { - { .compatible = "qcom,smp2p" }, - {} -}; -MODULE_DEVICE_TABLE(of, qcom_smp2p_of_match); - -static struct platform_driver qcom_smp2p_driver = { - .probe = qcom_smp2p_probe, - .remove = qcom_smp2p_remove, - .driver = { - .name = "qcom_smp2p", - .of_match_table = qcom_smp2p_of_match, - }, -}; -module_platform_driver(qcom_smp2p_driver); - -MODULE_DESCRIPTION("Qualcomm Shared Memory Point to Point driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpio/gpio-qcom-smsm.c b/drivers/gpio/gpio-qcom-smsm.c deleted file mode 100644 index c3e510364d14..000000000000 --- a/drivers/gpio/gpio-qcom-smsm.c +++ /dev/null @@ -1,327 +0,0 @@ -/* - * Copyright (c) 2014, Sony Mobile Communications AB. - * Copyright (c) 2012-2013, 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#define SMSM_APPS_STATE 0 -#define SMEM_SMSM_SHARED_STATE 85 - -#define SMSM_MAX_STATES 8 - -struct qcom_smsm_state { - unsigned state_id; - struct gpio_chip chip; - - int irq; - - struct regmap *ipc_regmap; - int ipc_bit; - int ipc_offset; -}; - -struct qcom_smsm { - struct device *dev; - - u32 *shared_state; - size_t shared_state_size; - - struct qcom_smsm_state states[SMSM_MAX_STATES]; -}; - -#if 0 -int qcom_smsm_change_state(struct qcom_smsm *smsm, u32 clear_mask, u32 set_mask) -{ - u32 state; - - dev_dbg(smsm->dev, "SMSM_APPS_STATE clear 0x%x set 0x%x\n", clear_mask, set_mask); - print_hex_dump(KERN_DEBUG, "raw data: ", DUMP_PREFIX_OFFSET, 16, 1, smsm->shared_state, smsm->shared_state_size, true); - - state = readl(&smsm->shared_state[SMSM_APPS_STATE]); - state &= ~clear_mask; - state |= set_mask; - writel(state, &smsm->shared_state[SMSM_APPS_STATE]); - - print_hex_dump(KERN_DEBUG, "raw data: ", DUMP_PREFIX_OFFSET, 16, 1, smsm->shared_state, smsm->shared_state_size, true); - - // qcom_smem_signal(-1, smsm->smem, smsm->signal_offset, smsm->signal_bit); - - return 0; -} -EXPORT_SYMBOL(qcom_smsm_change_state); -#endif - -static struct qcom_smsm_state *to_smsm_state(struct gpio_chip *chip) -{ - return container_of(chip, struct qcom_smsm_state, chip); -} - -static struct qcom_smsm *to_smsm(struct qcom_smsm_state *state) -{ - return container_of(state, struct qcom_smsm, states[state->state_id]); -} - -static int smsm_gpio_direction_input(struct gpio_chip *chip, - unsigned offset) -{ - struct qcom_smsm_state *state = to_smsm_state(chip); - - if (state->state_id == SMSM_APPS_STATE) - return -EINVAL; - return 0; -} - -static int smsm_gpio_direction_output(struct gpio_chip *chip, - unsigned offset, - int value) -{ - struct qcom_smsm_state *ipc_state; - struct qcom_smsm_state *state = to_smsm_state(chip); - struct qcom_smsm *smsm = to_smsm(state); - unsigned word; - unsigned bit; - u32 val; - int i; - - /* Only SMSM_APPS_STATE supports writing */ - if (state->state_id != SMSM_APPS_STATE) - return -EINVAL; - - offset += state->state_id * 32; - - word = ALIGN(offset / 32, 4); - bit = offset % 32; - - val = readl(smsm->shared_state + word); - if (value) - val |= BIT(bit); - else - val &= ~BIT(bit); - writel(val, smsm->shared_state + word); - - /* XXX: send out interrupts */ - for (i = 0; i < SMSM_MAX_STATES; i++) { - ipc_state = &smsm->states[i]; - if (!ipc_state->ipc_regmap) - continue; - - regmap_write(ipc_state->ipc_regmap, ipc_state->ipc_offset, BIT(ipc_state->ipc_bit)); - } - - dev_err(smsm->dev, "set %d %d\n", offset, value); - - return 0; -} - -static int smsm_gpio_get(struct gpio_chip *chip, unsigned offset) -{ - struct qcom_smsm_state *state = to_smsm_state(chip); - struct qcom_smsm *smsm = to_smsm(state); - unsigned word; - unsigned bit; - u32 val; - - offset += state->state_id * 32; - - word = ALIGN(offset / 32, 4); - bit = offset % 32; - - val = readl(smsm->shared_state + word); - - return !!(val & BIT(bit)); -} - -static void smsm_gpio_set(struct gpio_chip *chip, unsigned offset, int value) -{ - smsm_gpio_direction_output(chip, offset, value); -} - -static int smsm_gpio_to_irq(struct gpio_chip *chip, unsigned offset) -{ - return -EINVAL; -} - -#ifdef CONFIG_DEBUG_FS -#include - -static void smsm_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) -{ - struct qcom_smsm_state *state = to_smsm_state(chip); - struct qcom_smsm *smsm = to_smsm(state); - unsigned i; - u32 val; - - val = readl(smsm->shared_state + state->state_id * 4); - - for (i = 0; i < 32; i++) { - if (val & BIT(i)) - seq_puts(s, "1"); - else - seq_puts(s, "0"); - - if (i == 7 || i == 15 || i == 23) - seq_puts(s, " "); - } - seq_puts(s, "\n"); -} - -#else -#define smsm_gpio_dbg_show NULL -#endif - -static struct gpio_chip smsm_gpio_template = { - .direction_input = smsm_gpio_direction_input, - .direction_output = smsm_gpio_direction_output, - .get = smsm_gpio_get, - .set = smsm_gpio_set, - .to_irq = smsm_gpio_to_irq, - .dbg_show = smsm_gpio_dbg_show, - .owner = THIS_MODULE, -}; - -static int qcom_smsm_probe(struct platform_device *pdev) -{ - struct qcom_smsm_state *state; - struct device_node *syscon_np; - struct device_node *node; - struct qcom_smsm *smsm; - char *key; - u32 sid; - int ret; - - smsm = devm_kzalloc(&pdev->dev, sizeof(*smsm), GFP_KERNEL); - if (!smsm) - return -ENOMEM; - smsm->dev = &pdev->dev; - - ret = qcom_smem_alloc(-1, SMEM_SMSM_SHARED_STATE, 8 * sizeof(uint32_t)); - if (ret < 0 && ret != -EEXIST) { - dev_err(&pdev->dev, "unable to allocate shared state entry\n"); - return ret; - } - - smsm->shared_state = qcom_smem_get(-1, SMEM_SMSM_SHARED_STATE, - &smsm->shared_state_size); - if (IS_ERR(smsm->shared_state)) { - dev_err(&pdev->dev, "Unable to acquire shared state entry\n"); - return PTR_ERR(smsm->shared_state); - } - - dev_err(smsm->dev, "SMEM_SMSM_SHARED_STATE: %d, %zu\n", ret, smsm->shared_state_size); - print_hex_dump(KERN_DEBUG, "raw data: ", DUMP_PREFIX_OFFSET, 16, 1, smsm->shared_state, smsm->shared_state_size, true); - - for_each_child_of_node(pdev->dev.of_node, node) { - key = "reg"; - ret = of_property_read_u32(node, key, &sid); - if (ret || sid >= SMSM_MAX_STATES) { - dev_err(&pdev->dev, "smsm state missing %s\n", key); - return -EINVAL; - } - state = &smsm->states[sid]; - state->state_id = sid; - - state->chip = smsm_gpio_template; - state->chip.base = -1; - state->chip.dev = &pdev->dev; - state->chip.of_node = node; - state->chip.label = node->name; - state->chip.ngpio = 8 * sizeof(u32); - ret = gpiochip_add(&state->chip); - if (ret) { - dev_err(&pdev->dev, "failed register gpiochip\n"); - // goto wooha; - } - - /* The remaining properties are only for non-apps state */ - if (sid == SMSM_APPS_STATE) - continue; - - state->irq = irq_of_parse_and_map(node, 0); - if (state->irq < 0 && state->irq != -EINVAL) { - dev_err(&pdev->dev, "failed to parse smsm interrupt\n"); - return -EINVAL; - } - - syscon_np = of_parse_phandle(node, "qcom,ipc", 0); - if (!syscon_np) { - dev_err(&pdev->dev, "no qcom,ipc node\n"); - return -ENODEV; - } - - state->ipc_regmap = syscon_node_to_regmap(syscon_np); - if (IS_ERR(state->ipc_regmap)) - return PTR_ERR(state->ipc_regmap); - - key = "qcom,ipc"; - ret = of_property_read_u32_index(node, key, 1, &state->ipc_offset); - if (ret < 0) { - dev_err(&pdev->dev, "no offset in %s\n", key); - return -EINVAL; - } - - ret = of_property_read_u32_index(node, key, 2, &state->ipc_bit); - if (ret < 0) { - dev_err(&pdev->dev, "no bit in %s\n", key); - return -EINVAL; - } - - } - - return 0; -} - -static const struct of_device_id qcom_smsm_of_match[] = { - { .compatible = "qcom,smsm" }, - {} -}; -MODULE_DEVICE_TABLE(of, qcom_smsm_of_match); - -static struct platform_driver qcom_smsm_driver = { - .probe = qcom_smsm_probe, - .driver = { - .name = "qcom_smsm", - .owner = THIS_MODULE, - .of_match_table = qcom_smsm_of_match, - }, -}; - -static int __init qcom_smsm_init(void) -{ - return platform_driver_register(&qcom_smsm_driver); -} -arch_initcall(qcom_smsm_init); - -static void __exit qcom_smsm_exit(void) -{ - platform_driver_unregister(&qcom_smsm_driver); -} -module_exit(qcom_smsm_exit) - -MODULE_DESCRIPTION("Qualcomm Shared Memory Signaling Mechanism"); -MODULE_LICENSE("GPLv2"); -- 2.39.2