From 787dfa9e951dacab0e8b9deb80a72ebbcc29cdc7 Mon Sep 17 00:00:00 2001 From: Liron Kuch Date: Tue, 1 Jan 2013 18:29:47 +0200 Subject: [PATCH] tspp: support device tree mechanism in the driver Update the TSPP driver to support using the device tree mechanism for getting platform-dependent data. Change-Id: I5ac0f90266c3f30621865cf097db4dba1ee07fc6 Signed-off-by: Liron Kuch --- .../devicetree/bindings/arm/msm/msm_tspp.txt | 73 +++++ arch/arm/mach-msm/board-8960.c | 31 +- arch/arm/mach-msm/clock-8974.c | 4 +- arch/arm/mach-msm/devices-8064.c | 31 +- drivers/misc/tspp.c | 308 ++++++++++++------ 5 files changed, 335 insertions(+), 112 deletions(-) create mode 100644 Documentation/devicetree/bindings/arm/msm/msm_tspp.txt diff --git a/Documentation/devicetree/bindings/arm/msm/msm_tspp.txt b/Documentation/devicetree/bindings/arm/msm/msm_tspp.txt new file mode 100644 index 00000000000..2b5e1438fe3 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/msm/msm_tspp.txt @@ -0,0 +1,73 @@ +TSPP Driver + +For information on the TSPP driver, please refer to the TSPP driver +documentation: Documentation/arm/msm/tspp.txt. + +The devicetree representation of the TSPP block should be: + +Required properties: + +- compatible: "qcom,msm_tspp" +- cell-index: <0> - represents device ID. +- reg: physical memory base addresses and sizes for the following: + TSIF0, TSIF1, TSPP and TSPP_BAM. +- reg-names: names of the memory regions. +- interrupts: represents IRQ numbers for the following: + TSIF_TSPP_IRQ, TSIF0_IRQ, TSIF1_IRQ, TSIF_BAM_IRQ. +- interrupt-names: TSPP, TSIF and BAM interrupt names. +- qcom,tsif-pclk: interface clock name. +- qcom,tsif-ref-clk: reference clock name. + The driver uses clk_get to get the clocks by name. The clocks + should be defined in the relevant clock file (e.g. clock-8974.c). +- gpios: GPIO numbers for TSIF0 (CLK, EN, DATA and SYNC) and TSIF1 (same). +- qcom,gpio-names: GPIO names - strings describing the GPIO functionality. +- qcom,gpios-func: GPIO functionality according to the GPIO functionality table. + GPIO pins can have more than a single functionality, and the TSPP driver + is responsible for configuring the GPIOs to work in TSIF functionality + based on this parameter. + Note: it is assumed that the functionality value (e.g. 1 in 8974 case) + is applicable to all TSIF GPIOs. + +Example (for 8974 platform, avaialble at msm8974.dtsi): + + tspp: msm_tspp@f99d8000 { + compatible = "qcom,msm_tspp"; + cell-index = <0>; + reg = <0xf99d8000 0x1000>, /* MSM_TSIF0_PHYS */ + <0xf99d9000 0x1000>, /* MSM_TSIF1_PHYS */ + <0xf99da000 0x1000>, /* MSM_TSPP_PHYS */ + <0xf99c4000 0x14000>; /* MSM_TSPP_BAM_PHYS */ + reg-names = "MSM_TSIF0_PHYS", + "MSM_TSIF1_PHYS", + "MSM_TSPP_PHYS", + "MSM_TSPP_BAM_PHYS"; + interrupts = <0 153 0>, /* TSIF_TSPP_IRQ */ + <0 151 0>, /* TSIF0_IRQ */ + <0 152 0>, /* TSIF1_IRQ */ + <0 154 0>; /* TSIF_BAM_IRQ */ + interrupt-names = "TSIF_TSPP_IRQ", + "TSIF0_IRQ", + "TSIF1_IRQ", + "TSIF_BAM_IRQ"; + qcom,tsif-pclk = "iface_clk"; + qcom,tsif-ref-clk = "ref_clk"; + gpios = <&msmgpio 89 0>, /* TSIF0 CLK */ + <&msmgpio 90 0>, /* TSIF0 EN */ + <&msmgpio 91 0>, /* TSIF0 DATA */ + <&msmgpio 92 0>, /* TSIF0 SYNC */ + <&msmgpio 93 0>, /* TSIF1 CLK */ + <&msmgpio 94 0>, /* TSIF1 EN */ + <&msmgpio 95 0>, /* TSIF1 DATA */ + <&msmgpio 96 0>; /* TSIF1 SYNC */ + qcom,gpio-names = "tsif_clk", + "tsif_en", + "tsif_data", + "tsif_sync", + "tsif_clk", + "tsif_en", + "tsif_data", + "tsif_sync"; + qcom,gpios-func = <1>; + }; + + diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c index 7a94e7417ca..4b4d653d23b 100644 --- a/arch/arm/mach-msm/board-8960.c +++ b/arch/arm/mach-msm/board-8960.c @@ -1455,26 +1455,49 @@ static const struct msm_gpio tsif_gpios[] = { static struct resource tspp_resources[] = { [0] = { + .name = "TSIF_TSPP_IRQ", .flags = IORESOURCE_IRQ, .start = TSIF_TSPP_IRQ, - .end = TSIF1_IRQ, + .end = TSIF_TSPP_IRQ, }, [1] = { + .name = "TSIF0_IRQ", + .flags = IORESOURCE_IRQ, + .start = TSIF1_IRQ, + .end = TSIF1_IRQ, + }, + [2] = { + .name = "TSIF1_IRQ", + .flags = IORESOURCE_IRQ, + .start = TSIF2_IRQ, + .end = TSIF2_IRQ, + }, + [3] = { + .name = "TSIF_BAM_IRQ", + .flags = IORESOURCE_IRQ, + .start = TSIF_BAM_IRQ, + .end = TSIF_BAM_IRQ, + }, + [4] = { + .name = "MSM_TSIF0_PHYS", .flags = IORESOURCE_MEM, .start = MSM_TSIF0_PHYS, .end = MSM_TSIF0_PHYS + MSM_TSIF_SIZE - 1, }, - [2] = { + [5] = { + .name = "MSM_TSIF1_PHYS", .flags = IORESOURCE_MEM, .start = MSM_TSIF1_PHYS, .end = MSM_TSIF1_PHYS + MSM_TSIF_SIZE - 1, }, - [3] = { + [6] = { + .name = "MSM_TSPP_PHYS", .flags = IORESOURCE_MEM, .start = MSM_TSPP_PHYS, .end = MSM_TSPP_PHYS + MSM_TSPP_SIZE - 1, }, - [4] = { + [7] = { + .name = "MSM_TSPP_BAM_PHYS", .flags = IORESOURCE_MEM, .start = MSM_TSPP_BAM_PHYS, .end = MSM_TSPP_BAM_PHYS + MSM_TSPP_BAM_SIZE - 1, diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c index 8969be9441f..4e22a61014f 100644 --- a/arch/arm/mach-msm/clock-8974.c +++ b/arch/arm/mach-msm/clock-8974.c @@ -5071,8 +5071,8 @@ static struct clk_lookup msm_clocks_8974[] = { CLK_LOOKUP("core_clk", gcc_sdcc4_apps_clk.c, "msm_sdcc.4"), CLK_LOOKUP("bus_clk", pnoc_sdcc4_clk.c, "msm_sdcc.4"), - CLK_LOOKUP("iface_clk", gcc_tsif_ahb_clk.c, ""), - CLK_LOOKUP("ref_clk", gcc_tsif_ref_clk.c, ""), + CLK_LOOKUP("iface_clk", gcc_tsif_ahb_clk.c, "f99d8000.msm_tspp"), + CLK_LOOKUP("ref_clk", gcc_tsif_ref_clk.c, "f99d8000.msm_tspp"), CLK_LOOKUP("core_clk", gcc_usb30_master_clk.c, "msm_dwc3"), CLK_LOOKUP("utmi_clk", gcc_usb30_mock_utmi_clk.c, "msm_dwc3"), diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c index c1f7f6508fe..3d8f0da9020 100644 --- a/arch/arm/mach-msm/devices-8064.c +++ b/arch/arm/mach-msm/devices-8064.c @@ -652,26 +652,49 @@ static const struct msm_gpio tspp_gpios[] = { static struct resource tspp_resources[] = { [0] = { + .name = "TSIF_TSPP_IRQ", .flags = IORESOURCE_IRQ, .start = TSIF_TSPP_IRQ, - .end = TSIF1_IRQ, + .end = TSIF_TSPP_IRQ, }, [1] = { + .name = "TSIF0_IRQ", + .flags = IORESOURCE_IRQ, + .start = TSIF1_IRQ, + .end = TSIF1_IRQ, + }, + [2] = { + .name = "TSIF1_IRQ", + .flags = IORESOURCE_IRQ, + .start = TSIF2_IRQ, + .end = TSIF2_IRQ, + }, + [3] = { + .name = "TSIF_BAM_IRQ", + .flags = IORESOURCE_IRQ, + .start = TSIF_BAM_IRQ, + .end = TSIF_BAM_IRQ, + }, + [4] = { + .name = "MSM_TSIF0_PHYS", .flags = IORESOURCE_MEM, .start = MSM_TSIF0_PHYS, .end = MSM_TSIF0_PHYS + MSM_TSIF_SIZE - 1, }, - [2] = { + [5] = { + .name = "MSM_TSIF1_PHYS", .flags = IORESOURCE_MEM, .start = MSM_TSIF1_PHYS, .end = MSM_TSIF1_PHYS + MSM_TSIF_SIZE - 1, }, - [3] = { + [6] = { + .name = "MSM_TSPP_PHYS", .flags = IORESOURCE_MEM, .start = MSM_TSPP_PHYS, .end = MSM_TSPP_PHYS + MSM_TSPP_SIZE - 1, }, - [4] = { + [7] = { + .name = "MSM_TSPP_BAM_PHYS", .flags = IORESOURCE_MEM, .start = MSM_TSPP_BAM_PHYS, .end = MSM_TSPP_BAM_PHYS + MSM_TSPP_BAM_SIZE - 1, diff --git a/drivers/misc/tspp.c b/drivers/misc/tspp.c index 0715d6dc9e4..cfd9eae3820 100644 --- a/drivers/misc/tspp.c +++ b/drivers/misc/tspp.c @@ -41,6 +41,8 @@ #include #include #include +#include +#include /* * General defines @@ -647,45 +649,19 @@ static void tspp_sps_complete_tlet(unsigned long data) } /*** GPIO functions ***/ -static void tspp_gpios_free(const struct msm_gpio *table, int size) -{ - int i; - const struct msm_gpio *g; - for (i = size-1; i >= 0; i--) { - g = table + i; - gpio_free(GPIO_PIN(g->gpio_cfg)); - } -} - -static int tspp_gpios_request(const struct msm_gpio *table, int size) -{ - int rc; - int i; - const struct msm_gpio *g; - for (i = 0; i < size; i++) { - g = table + i; - rc = gpio_request(GPIO_PIN(g->gpio_cfg), g->label); - if (rc) { - pr_err("tspp: gpio_request(%d) <%s> failed: %d\n", - GPIO_PIN(g->gpio_cfg), g->label ?: "?", rc); - goto err; - } - } - return 0; -err: - tspp_gpios_free(table, i); - return rc; -} - static int tspp_gpios_disable(const struct msm_gpio *table, int size) { int rc = 0; int i; const struct msm_gpio *g; + for (i = size-1; i >= 0; i--) { int tmp; g = table + i; - tmp = gpio_tlmm_config(g->gpio_cfg, GPIO_CFG_DISABLE); + + tmp = gpio_tlmm_config(GPIO_CFG(GPIO_PIN(g->gpio_cfg), + 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), + GPIO_CFG_DISABLE); if (tmp) { pr_err("tspp_gpios_disable(0x%08x, GPIO_CFG_DISABLE) <%s> failed: %d\n", g->gpio_cfg, g->label ?: "?", rc); @@ -704,8 +680,9 @@ static int tspp_gpios_disable(const struct msm_gpio *table, int size) static int tspp_gpios_enable(const struct msm_gpio *table, int size) { int rc; - int i; + int i, j; const struct msm_gpio *g; + for (i = 0; i < size; i++) { g = table + i; rc = gpio_tlmm_config(g->gpio_cfg, GPIO_CFG_ENABLE); @@ -721,39 +698,26 @@ static int tspp_gpios_enable(const struct msm_gpio *table, int size) } return 0; err: - tspp_gpios_disable(table, i); - return rc; -} + for (j = 0; j < i; j++) + tspp_gpios_disable(table, j); -static int tspp_gpios_request_enable(const struct msm_gpio *table, int size) -{ - int rc = tspp_gpios_request(table, size); - if (rc) - return rc; - rc = tspp_gpios_enable(table, size); - if (rc) - tspp_gpios_free(table, size); return rc; } -static void tspp_gpios_disable_free(const struct msm_gpio *table, int size) -{ - tspp_gpios_disable(table, size); - tspp_gpios_free(table, size); -} - static int tspp_start_gpios(struct tspp_device *device) { struct msm_tspp_platform_data *pdata = device->pdev->dev.platform_data; - return tspp_gpios_request_enable(pdata->gpios, pdata->num_gpios); + + return tspp_gpios_enable(pdata->gpios, pdata->num_gpios); } static void tspp_stop_gpios(struct tspp_device *device) { struct msm_tspp_platform_data *pdata = device->pdev->dev.platform_data; - tspp_gpios_disable_free(pdata->gpios, pdata->num_gpios); + + tspp_gpios_disable(pdata->gpios, pdata->num_gpios); } /*** Clock functions ***/ @@ -1427,9 +1391,10 @@ int tspp_open_channel(u32 dev, u32 channel_id) event = &channel->event; /* start the clocks if needed */ - tspp_clock_start(pdev); - if (tspp_channels_in_use(pdev) == 0) + if (tspp_channels_in_use(pdev) == 0) { + tspp_clock_start(pdev); wake_lock(&pdev->wake_lock); + } /* mark it as used */ channel->used = 1; @@ -1604,9 +1569,10 @@ int tspp_close_channel(u32 dev, u32 channel_id) channel->locked = NULL; channel->used = 0; - if (tspp_channels_in_use(pdev) == 0) + if (tspp_channels_in_use(pdev) == 0) { wake_unlock(&pdev->wake_lock); - tspp_clock_stop(pdev); + tspp_clock_stop(pdev); + } return 0; } @@ -2603,6 +2569,137 @@ static void tspp_debugfs_exit(struct tspp_device *device) } } +/* copy device-tree data to platfrom data struct */ +static __devinit struct msm_tspp_platform_data * +msm_tspp_dt_to_pdata(struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + struct msm_tspp_platform_data *data; + struct msm_gpio *gpios; + int i, rc; + int gpio; + u32 gpio_func; + + /* Note: memory allocated by devm_kzalloc is freed automatically */ + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) { + pr_err("tspp: Unable to allocate platform data\n"); + return NULL; + } + rc = of_property_read_string(node, "qcom,tsif-pclk", &data->tsif_pclk); + if (rc) { + pr_err("tspp: Could not find tsif-pclk property, err = %d\n", + rc); + return NULL; + } + rc = of_property_read_string(node, "qcom,tsif-ref-clk", + &data->tsif_ref_clk); + if (rc) { + pr_err("tspp: Could not find tsif-ref-clk property, err = %d\n", + rc); + return NULL; + } + + data->num_gpios = of_gpio_count(node); + if (data->num_gpios == 0) { + pr_err("tspp: Could not find GPIO definitions\n"); + return NULL; + } + gpios = devm_kzalloc(&pdev->dev, + (data->num_gpios * sizeof(struct msm_gpio)), + GFP_KERNEL); + if (!gpios) { + pr_err("tspp: Unable to allocate memory for GPIOs table\n"); + return NULL; + } + /* Assuming GPIO FUNC property is the same for all GPIOs */ + if (of_property_read_u32(node, "qcom,gpios-func", &gpio_func)) { + pr_err("tspp: Could not find gpios-func property\n"); + return NULL; + } + for (i = 0; i < data->num_gpios; i++) { + gpio = of_get_gpio(node, i); + gpios[i].gpio_cfg = GPIO_CFG(gpio, gpio_func, + GPIO_CFG_INPUT, + GPIO_CFG_PULL_DOWN, + GPIO_CFG_2MA); + rc = of_property_read_string_index(node, "qcom,gpio-names", + i, &gpios[i].label); + if (rc) + pr_warn("tspp: Could not find gpio-names property\n"); + } + + data->gpios = gpios; + + return data; +} + +static int msm_tspp_map_irqs(struct platform_device *pdev, + struct tspp_device *device) +{ + int rc; + int i; + + /* get IRQ numbers from platform information */ + + /* map TSPP IRQ */ + rc = platform_get_irq_byname(pdev, "TSIF_TSPP_IRQ"); + if (rc > 0) { + device->tspp_irq = rc; + rc = request_irq(device->tspp_irq, tspp_isr, IRQF_SHARED, + dev_name(&pdev->dev), device); + if (rc) { + dev_err(&pdev->dev, + "failed to request TSPP IRQ %d : %d", + device->tspp_irq, rc); + device->tspp_irq = 0; + return -EINVAL; + } + } else { + dev_err(&pdev->dev, "failed to get TSPP IRQ"); + return -EINVAL; + } + + /* map TSIF IRQs */ + rc = platform_get_irq_byname(pdev, "TSIF0_IRQ"); + if (rc > 0) { + device->tsif[0].tsif_irq = rc; + } else { + dev_err(&pdev->dev, "failed to get TSIF0 IRQ"); + return -EINVAL; + } + + rc = platform_get_irq_byname(pdev, "TSIF1_IRQ"); + if (rc > 0) { + device->tsif[1].tsif_irq = rc; + } else { + dev_err(&pdev->dev, "failed to get TSIF1 IRQ"); + return -EINVAL; + } + + for (i = 0; i < TSPP_TSIF_INSTANCES; i++) { + rc = request_irq(device->tsif[i].tsif_irq, + tsif_isr, IRQF_SHARED, + dev_name(&pdev->dev), &device->tsif[i]); + if (rc) { + dev_warn(&pdev->dev, "failed to request TSIF%d IRQ: %d", + i, rc); + device->tsif[i].tsif_irq = 0; + } + } + + /* map BAM IRQ */ + rc = platform_get_irq_byname(pdev, "TSIF_BAM_IRQ"); + if (rc > 0) { + device->bam_irq = rc; + } else { + dev_err(&pdev->dev, "failed to get TSPP BAM IRQ"); + return -EINVAL; + } + + return 0; +} + static int __devinit msm_tspp_probe(struct platform_device *pdev) { int rc = -ENODEV; @@ -2616,8 +2713,20 @@ static int __devinit msm_tspp_probe(struct platform_device *pdev) struct resource *mem_bam; struct tspp_channel *channel; - /* must have platform data */ - data = pdev->dev.platform_data; + if (pdev->dev.of_node) { + /* get information from device tree */ + data = msm_tspp_dt_to_pdata(pdev); + /* get device ID */ + rc = of_property_read_u32(pdev->dev.of_node, + "cell-index", &pdev->id); + if (rc) + pdev->id = -1; + + pdev->dev.platform_data = data; + } else { + /* must have platform data */ + data = pdev->dev.platform_data; + } if (!data) { pr_err("tspp: Platform data not available"); rc = -EINVAL; @@ -2666,7 +2775,8 @@ static int __devinit msm_tspp_probe(struct platform_device *pdev) } /* map I/O memory */ - mem_tsif0 = platform_get_resource(pdev, IORESOURCE_MEM, 0); + mem_tsif0 = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "MSM_TSIF0_PHYS"); if (!mem_tsif0) { pr_err("tspp: Missing tsif0 MEM resource"); rc = -ENXIO; @@ -2679,7 +2789,8 @@ static int __devinit msm_tspp_probe(struct platform_device *pdev) goto err_map_tsif0; } - mem_tsif1 = platform_get_resource(pdev, IORESOURCE_MEM, 1); + mem_tsif1 = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "MSM_TSIF1_PHYS"); if (!mem_tsif1) { dev_err(&pdev->dev, "Missing tsif1 MEM resource"); rc = -ENXIO; @@ -2692,7 +2803,8 @@ static int __devinit msm_tspp_probe(struct platform_device *pdev) goto err_map_tsif1; } - mem_tspp = platform_get_resource(pdev, IORESOURCE_MEM, 2); + mem_tspp = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "MSM_TSPP_PHYS"); if (!mem_tspp) { dev_err(&pdev->dev, "Missing MEM resource"); rc = -ENXIO; @@ -2704,7 +2816,8 @@ static int __devinit msm_tspp_probe(struct platform_device *pdev) goto err_map_dev; } - mem_bam = platform_get_resource(pdev, IORESOURCE_MEM, 3); + mem_bam = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "MSM_TSPP_BAM_PHYS"); if (!mem_bam) { pr_err("tspp: Missing bam MEM resource"); rc = -ENXIO; @@ -2719,39 +2832,8 @@ static int __devinit msm_tspp_probe(struct platform_device *pdev) goto err_map_bam; } - /* map TSPP IRQ */ - rc = platform_get_irq(pdev, 0); - if (rc > 0) { - device->tspp_irq = rc; - rc = request_irq(device->tspp_irq, tspp_isr, IRQF_SHARED, - dev_name(&pdev->dev), device); - if (rc) { - dev_err(&pdev->dev, "failed to request IRQ %d : %d", - device->tspp_irq, rc); - goto err_irq; - } - } else { - dev_err(&pdev->dev, "failed to get tspp IRQ"); + if (msm_tspp_map_irqs(pdev, device)) goto err_irq; - } - - /* map TSIF IRQs */ - device->tsif[0].tsif_irq = TSIF1_IRQ; - device->tsif[1].tsif_irq = TSIF2_IRQ; - - for (i = 0; i < TSPP_TSIF_INSTANCES; i++) { - rc = request_irq(device->tsif[i].tsif_irq, - tsif_isr, IRQF_SHARED, - dev_name(&pdev->dev), &device->tsif[i]); - if (rc) { - dev_warn(&pdev->dev, "failed to request TSIF%d IRQ: %d", - i, rc); - device->tsif[i].tsif_irq = 0; - } - } - - /* BAM IRQ */ - device->bam_irq = TSIF_BAM_IRQ; /* GPIOs */ rc = tspp_start_gpios(device); @@ -2786,17 +2868,17 @@ static int __devinit msm_tspp_probe(struct platform_device *pdev) device->bam_props.irq = device->bam_irq; device->bam_props.manage = SPS_BAM_MGR_LOCAL; + if (tspp_clock_start(device) != 0) { + dev_err(&pdev->dev, "Can't start clocks"); + goto err_clock; + } + if (sps_register_bam_device(&device->bam_props, &device->bam_handle) != 0) { pr_err("tspp: failed to register bam"); goto err_bam; } - if (tspp_clock_start(device) != 0) { - dev_err(&pdev->dev, "Can't start clocks"); - goto err_clock; - } - spin_lock_init(&device->spinlock); tasklet_init(&device->tlet, tspp_sps_complete_tlet, (unsigned long)device); @@ -2805,7 +2887,11 @@ static int __devinit msm_tspp_probe(struct platform_device *pdev) tspp_global_reset(device); version = readl_relaxed(device->base + TSPP_VERSION); - if (version != 1) + /* + * TSPP version can be bits [7:0] or alternatively, + * TSPP major version is bits [31:28]. + */ + if ((version != 0x1) && (((version >> 28) & 0xF) != 0x1)) pr_warn("tspp: unrecognized hw version=%i", version); /* initialize the channels */ @@ -2825,21 +2911,30 @@ static int __devinit msm_tspp_probe(struct platform_device *pdev) return 0; err_channel: - /* uninitialize channels */ + /* un-initialize channels */ for (j = 0; j < i; j++) { channel = &(device->channels[i]); device_destroy(tspp_class, channel->cdev.dev); cdev_del(&channel->cdev); } -err_clock: + sps_deregister_bam_device(device->bam_handle); +err_clock: err_bam: tspp_debugfs_exit(device); for (i = 0; i < TSPP_TSIF_INSTANCES; i++) tsif_debugfs_exit(&device->tsif[i]); + + tspp_stop_gpios(device); err_gpio: err_irq: - tspp_stop_gpios(device); + for (i = 0; i < TSPP_TSIF_INSTANCES; i++) { + if (device->tsif[i].tsif_irq) + free_irq(device->tsif[i].tsif_irq, &device->tsif[i]); + } + if (device->tspp_irq) + free_irq(device->tspp_irq, device); + iounmap(device->bam_props.virt_addr); err_map_bam: err_res_bam: @@ -2879,7 +2974,10 @@ static int __devexit msm_tspp_remove(struct platform_device *pdev) cdev_del(&channel->cdev); } + /* de-registering BAM device requires clocks */ + tspp_clock_start(device); sps_deregister_bam_device(device->bam_handle); + tspp_clock_stop(device); for (i = 0; i < TSPP_TSIF_INSTANCES; i++) { tsif_debugfs_exit(&device->tsif[i]); @@ -2928,12 +3026,18 @@ static const struct dev_pm_ops tspp_dev_pm_ops = { .runtime_resume = tspp_runtime_resume, }; +static struct of_device_id msm_match_table[] = { + {.compatible = "qcom,msm_tspp"}, + {} +}; + static struct platform_driver msm_tspp_driver = { .probe = msm_tspp_probe, .remove = __exit_p(msm_tspp_remove), .driver = { .name = "msm_tspp", .pm = &tspp_dev_pm_ops, + .of_match_table = msm_match_table, }, };