Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b6296469 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "misc: Add APQ8084 Docking Station driver"

parents 5b4bab05 b74f7d47
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
QTI APQ8084 Docking Station

This device describes the interface used when connecting to the
Docking Station's USB hub and Ethernet ports. The interface
consists of GPIOs used for controlling the main power supply
and reset lines.

Required properties:
 - compatible: Should be "qti,apq8084-dock"
 - qti,dock-detect-gpio: phandle to a GPIO node corresponding to the input
                         signal indicating when the dock is connected
 - qti,dock-enable-gpio: phandle to a GPIO node corresponding to the output
                         signal that turns on/off power to the ports
 - qti,dock-hub-reset-gpio: phandle to a GPIO node corresponding to the output
                            signal that resets the USB ports
 - qti,dock-eth-reset-gpio: phandle to a GPIO node corresponding to the output
                            signal that resets the Ethernet ports
+7 −0
Original line number Diff line number Diff line
@@ -602,6 +602,13 @@ config TI_DRV2667
	  To compile this driver as a module, choose M here: the
	  module will be called ti_drv2667.

config APQ8084_DOCKING_STATION
	tristate "QTI APQ8084 Docking Station USB/Ethernet support"
	depends on OF_GPIO
	help
	  This option enables support for the USB and Ethernet ports found on
	  the QTI APQ8084 Docking Station.

source "drivers/misc/c2port/Kconfig"
source "drivers/misc/eeprom/Kconfig"
source "drivers/misc/cb710/Kconfig"
+1 −0
Original line number Diff line number Diff line
@@ -61,3 +61,4 @@ obj-$(CONFIG_QSEECOM) += qseecom.o
obj-$(CONFIG_QFP_FUSE) += qfp_fuse.o
obj-$(CONFIG_TI_DRV2667) += ti_drv2667.o
obj-$(CONFIG_QPNP_MISC) += qpnp-misc.o
obj-$(CONFIG_APQ8084_DOCKING_STATION)	+= apq8084_dock.o
+168 −0
Original line number Diff line number Diff line
/* Copyright (c) 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 <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/pm_wakeup.h>
#include <linux/workqueue.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/of_gpio.h>

struct apq8084_dock {
	struct device		*dev;
	struct work_struct	dock_work;
	int			dock_detect;
	int			dock_hub_reset;
	int			dock_eth_reset;
	int			dock_enable;
};

static void dock_detected_work(struct work_struct *w)
{
	struct apq8084_dock *dock = container_of(w, struct apq8084_dock,
						 dock_work);
	int docked;

	docked = gpio_get_value(dock->dock_detect);
	gpio_direction_output(dock->dock_enable, 0);

	if (docked) {
		/* assert RESETs before turning on power */
		gpio_direction_output(dock->dock_hub_reset, 1);
		gpio_direction_output(dock->dock_eth_reset, 1);
		gpio_direction_output(dock->dock_enable, 1);

		msleep(20); /* short delay before de-asserting RESETs */
		gpio_direction_output(dock->dock_hub_reset, 0);
		gpio_direction_output(dock->dock_eth_reset, 0);
	}

	/* Allow system suspend */
	pm_relax(dock->dev);
}

static irqreturn_t dock_detected(int irq, void *data)
{
	struct apq8084_dock *dock = data;

	/* Ensure suspend can't happen until after work function commpletes */
	pm_stay_awake(dock->dev);
	schedule_work(&dock->dock_work);
	return IRQ_HANDLED;
}

static int apq8084_dock_probe(struct platform_device *pdev)
{
	struct device_node *node = pdev->dev.of_node;
	struct apq8084_dock *dock;
	int ret;

	dock = devm_kzalloc(&pdev->dev, sizeof(*dock), GFP_KERNEL);
	if (!dock)
		return -ENOMEM;

	dock->dev = &pdev->dev;
	platform_set_drvdata(pdev, dock);
	INIT_WORK(&dock->dock_work, dock_detected_work);

	dock->dock_detect = of_get_named_gpio(node, "qti,dock-detect-gpio", 0);
	if (dock->dock_detect < 0) {
		dev_err(dock->dev, "unable to get dock-detect-gpio\n");
		return dock->dock_detect;
	}

	ret = devm_gpio_request(dock->dev, dock->dock_detect, "dock_detect");
	if (ret)
		return ret;

	ret = devm_request_irq(&pdev->dev, gpio_to_irq(dock->dock_detect),
				dock_detected, IRQF_TRIGGER_RISING |
				IRQF_TRIGGER_FALLING | IRQF_SHARED,
				"dock_detect_irq", dock);
	if (ret)
		return ret;

	dock->dock_hub_reset = of_get_named_gpio(node,
						 "qti,dock-hub-reset-gpio", 0);
	if (dock->dock_hub_reset < 0) {
		dev_err(dock->dev, "unable to get dock-hub-reset-gpio\n");
		return dock->dock_hub_reset;
	}

	ret = devm_gpio_request(dock->dev, dock->dock_hub_reset,
				"dock_hub_reset");
	if (ret)
		return ret;

	dock->dock_eth_reset = of_get_named_gpio(node,
						 "qti,dock-eth-reset-gpio", 0);
	if (dock->dock_eth_reset < 0) {
		dev_err(dock->dev, "unable to get dock-eth-reset-gpio\n");
		return dock->dock_eth_reset;
	}

	ret = devm_gpio_request(dock->dev, dock->dock_eth_reset,
				"dock_eth_reset");
	if (ret)
		return ret;

	dock->dock_enable = of_get_named_gpio(node, "qti,dock-enable-gpio", 0);
	if (dock->dock_enable < 0) {
		dev_err(dock->dev, "unable to get dock-enable-gpio\n");
		return dock->dock_enable;
	}

	ret = devm_gpio_request(dock->dev, dock->dock_enable, "dock_enable");
	if (ret)
		return ret;

	schedule_work(&dock->dock_work);
	device_init_wakeup(dock->dev, true);
	enable_irq_wake(gpio_to_irq(dock->dock_detect));

	return 0;
}

static int apq8084_dock_remove(struct platform_device *pdev)
{
	struct apq8084_dock *dock = platform_get_drvdata(pdev);

	disable_irq_wake(gpio_to_irq(dock->dock_detect));
	cancel_work_sync(&dock->dock_work);

	return 0;
}

static struct of_device_id of_match_table[] = {
	{       .compatible = "qti,apq8084-dock",
	}
};

static struct platform_driver apq8084_dock_driver = {
	.driver         = {
		.name   = "apq8084-dock-driver",
		.of_match_table = of_match_table,
	},
	.probe          = apq8084_dock_probe,
	.remove		= apq8084_dock_remove,
};

module_platform_driver(apq8084_dock_driver);

MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("QTI APQ8084 Docking Station driver");