summaryrefslogtreecommitdiff
path: root/drivers/staging/cg2900/devices-cg2900-ux500.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/cg2900/devices-cg2900-ux500.c')
-rw-r--r--drivers/staging/cg2900/devices-cg2900-ux500.c206
1 files changed, 206 insertions, 0 deletions
diff --git a/drivers/staging/cg2900/devices-cg2900-ux500.c b/drivers/staging/cg2900/devices-cg2900-ux500.c
new file mode 100644
index 00000000000..00cd4a543b2
--- /dev/null
+++ b/drivers/staging/cg2900/devices-cg2900-ux500.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2011
+ * Authors:
+ * Par-Gunnar Hjalmdahl (par-gunnar.p.hjalmdahl@stericsson.com) for ST-Ericsson.
+ * Henrik Possung (henrik.possung@stericsson.com) for ST-Ericsson.
+ * Josef Kindberg (josef.kindberg@stericsson.com) for ST-Ericsson.
+ * Dariusz Szymszak (dariusz.xd.szymczak@stericsson.com) for ST-Ericsson.
+ * Kjell Andersson (kjell.k.andersson@stericsson.com) for ST-Ericsson.
+ * Hemant Gupta (hemant.gupta@stericsson.com) for ST-Ericsson.
+ * License terms: GNU General Public License (GPL), version 2
+ *
+ * Board specific device support for the Linux Bluetooth HCI H:4 Driver
+ * for ST-Ericsson connectivity controller.
+ */
+
+#include <asm/byteorder.h>
+#include <asm-generic/errno-base.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/mutex.h>
+#include <linux/mfd/abx500/ab5500.h>
+#include <linux/mfd/dbx500-prcmu.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <plat/pincfg.h>
+
+#include "devices-cg2900.h"
+
+void dcg2900_u8500_enable_chip(struct cg2900_chip_dev *dev)
+{
+ struct dcg2900_info *info = dev->b_data;
+
+ if (info->gbf_gpio == -1)
+ return;
+
+ /*
+ * - SET PMU_EN to high
+ * - Wait for 300usec
+ * - Set PDB to high.
+ */
+
+ if (info->pmuen_gpio != -1) {
+ /*
+ * We must first set PMU_EN pin high and then wait 300 us before
+ * setting the GBF_EN high.
+ */
+ gpio_set_value(info->pmuen_gpio, 1);
+ udelay(CHIP_ENABLE_PMU_EN_TIMEOUT);
+ }
+
+ gpio_set_value(info->gbf_gpio, 1);
+}
+
+void dcg2900_u8500_disable_chip(struct cg2900_chip_dev *dev)
+{
+ struct dcg2900_info *info = dev->b_data;
+
+ if (info->gbf_gpio != -1)
+ gpio_set_value(info->gbf_gpio, 0);
+ if (info->pmuen_gpio != -1)
+ gpio_set_value(info->pmuen_gpio, 0);
+}
+
+int dcg2900_u8500_setup(struct cg2900_chip_dev *dev,
+ struct dcg2900_info *info)
+{
+ int err = 0;
+ struct resource *resource;
+ const char *gbf_name;
+ const char *bt_name = NULL;
+ const char *pmuen_name = NULL;
+
+ resource = platform_get_resource_byname(dev->pdev, IORESOURCE_IO,
+ "gbf_ena_reset");
+ if (!resource) {
+ dev_err(dev->dev, "GBF GPIO does not exist\n");
+ err = -EINVAL;
+ goto err_handling;
+ }
+
+ info->gbf_gpio = resource->start;
+ gbf_name = resource->name;
+
+ resource = platform_get_resource_byname(dev->pdev, IORESOURCE_IO,
+ "bt_enable");
+ /* BT Enable GPIO may not exist */
+ if (resource) {
+ info->bt_gpio = resource->start;
+ bt_name = resource->name;
+ }
+
+ resource = platform_get_resource_byname(dev->pdev, IORESOURCE_IO,
+ "pmu_en");
+ /* PMU_EN GPIO may not exist */
+ if (resource) {
+ info->pmuen_gpio = resource->start;
+ pmuen_name = resource->name;
+ }
+
+ /* Now setup the GPIOs */
+ err = gpio_request(info->gbf_gpio, gbf_name);
+ if (err < 0) {
+ dev_err(dev->dev, "gpio_request %s failed with err: %d\n",
+ gbf_name, err);
+ goto err_handling;
+ }
+
+ err = gpio_direction_output(info->gbf_gpio, 0);
+ if (err < 0) {
+ dev_err(dev->dev,
+ "gpio_direction_output %s failed with err: %d\n",
+ gbf_name, err);
+ goto err_handling_free_gpio_gbf;
+ }
+
+ if (!pmuen_name)
+ goto set_bt_gpio;
+
+ err = gpio_request(info->pmuen_gpio, pmuen_name);
+ if (err < 0) {
+ dev_err(dev->dev, "gpio_request %s failed with err: %d\n",
+ pmuen_name, err);
+ goto err_handling_free_gpio_gbf;
+ }
+
+ err = gpio_direction_output(info->pmuen_gpio, 0);
+ if (err < 0) {
+ dev_err(dev->dev,
+ "gpio_direction_output %s failed with err: %d\n",
+ pmuen_name, err);
+ goto err_handling_free_gpio_pmuen;
+ }
+
+set_bt_gpio:
+ if (!bt_name)
+ goto finished;
+
+ err = gpio_request(info->bt_gpio, bt_name);
+ if (err < 0) {
+ dev_err(dev->dev, "gpio_request %s failed with err: %d\n",
+ bt_name, err);
+ goto err_handling_free_gpio_pmuen;
+ }
+
+ err = gpio_direction_output(info->bt_gpio, 1);
+ if (err < 0) {
+ dev_err(dev->dev,
+ "gpio_direction_output %s failed with err: %d\n",
+ bt_name, err);
+ goto err_handling_free_gpio_bt;
+ }
+
+finished:
+
+ return 0;
+
+err_handling_free_gpio_bt:
+ gpio_free(info->bt_gpio);
+ info->bt_gpio = -1;
+err_handling_free_gpio_pmuen:
+ if (info->pmuen_gpio != -1) {
+ gpio_free(info->pmuen_gpio);
+ info->pmuen_gpio = -1;
+ }
+err_handling_free_gpio_gbf:
+ gpio_free(info->gbf_gpio);
+ info->gbf_gpio = -1;
+err_handling:
+
+ return err;
+}
+
+/* prcmu resout1 pin is used for CG2900 reset*/
+void dcg2900_u5500_enable_chip(struct cg2900_chip_dev *dev)
+{
+ struct dcg2900_info *info = dev->b_data;
+
+ clk_enable(info->lpoclk);
+ /*
+ * - Set PDB to high.
+ */
+ prcmu_resetout(1, 1);
+}
+
+void dcg2900_u5500_disable_chip(struct cg2900_chip_dev *dev)
+{
+ struct dcg2900_info *info = dev->b_data;
+
+ prcmu_resetout(1, 0);
+ clk_disable(info->lpoclk);
+}
+
+int dcg2900_u5500_setup(struct cg2900_chip_dev *dev,
+ struct dcg2900_info *info)
+{
+ info->lpoclk = clk_get(dev->dev, "lpoclk");
+ if (IS_ERR(info->lpoclk))
+ return PTR_ERR(info->lpoclk);
+
+ return 0;
+}
+