From 9086ef0960ffd33e1a7687b588289d77d4e2f408 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Fri, 1 Jan 2010 15:11:43 -0800 Subject: arm: msm: allow ARCH_MSM to have v7 cpus ARCH_MSM supports armv7 cpus, so we're pushed the CPU_V6/CPU_V7 selection down into the arch/arm/mach-msm/Kconfig. Also update the description to be a bit more accurate. Signed-off-by: Daniel Walker --- arch/arm/Kconfig | 10 +++++----- arch/arm/mach-msm/Kconfig | 2 ++ 2 files changed, 7 insertions(+), 5 deletions(-) (limited to 'arch') diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 233a222752c0..c752b7d63c70 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -573,14 +573,14 @@ config ARCH_PXA config ARCH_MSM bool "Qualcomm MSM" - select CPU_V6 select GENERIC_TIME select GENERIC_CLOCKEVENTS help - Support for Qualcomm MSM7K based systems. This runs on the ARM11 - apps processor of the MSM7K and depends on a shared memory - interface to the ARM9 modem processor which runs the baseband stack - and controls some vital subsystems (clock and power control, etc). + Support for Qualcomm MSM/QSD based systems. This runs on the + apps processor of the MSM/QSD and depends on a shared memory + interface to the modem processor which runs the baseband + stack and controls some vital subsystems + (clock and power control, etc). config ARCH_RPC bool "RiscPC" diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index f780086befd7..b9fd5c528e5b 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -29,12 +29,14 @@ endchoice config MACH_HALIBUT depends on ARCH_MSM + select CPU_V6 default y bool "Halibut Board (QCT SURF7201A)" help Support for the Qualcomm SURF7201A eval board. config MACH_TROUT + select CPU_V6 default y bool "HTC Dream (aka trout)" help -- cgit v1.2.3 From 70878806fbd51036d4cd9a333f08b4cfdf24e435 Mon Sep 17 00:00:00 2001 From: Arve Hjønnevåg Date: Fri, 1 Jan 2010 14:09:26 -0800 Subject: arm msm: gpio support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Provide an implementation of the generic gpio API for the MSM family. An extended API provides single-step configuration and access to edge detect status. Signed-off-by: Brian Swetland Signed-off-by: Arve Hjønnevåg --- arch/arm/Kconfig | 1 + arch/arm/mach-msm/Makefile | 1 + arch/arm/mach-msm/generic_gpio.c | 274 +++++++++++++++++ arch/arm/mach-msm/gpio.c | 530 +++++++++++++++++++++++++++++++++ arch/arm/mach-msm/gpio_chip.h | 38 +++ arch/arm/mach-msm/gpio_hw.h | 100 +++++++ arch/arm/mach-msm/include/mach/board.h | 1 - arch/arm/mach-msm/include/mach/gpio.h | 47 +++ 8 files changed, 991 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-msm/generic_gpio.c create mode 100644 arch/arm/mach-msm/gpio.c create mode 100644 arch/arm/mach-msm/gpio_chip.h create mode 100644 arch/arm/mach-msm/gpio_hw.h create mode 100644 arch/arm/mach-msm/include/mach/gpio.h (limited to 'arch') diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index c752b7d63c70..ce4880b8969d 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -573,6 +573,7 @@ config ARCH_PXA config ARCH_MSM bool "Qualcomm MSM" + select GENERIC_GPIO select GENERIC_TIME select GENERIC_CLOCKEVENTS help diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 91e6f5c95dc1..fd06eb853a2c 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -3,6 +3,7 @@ obj-y += devices.o obj-y += proc_comm.o obj-y += vreg.o obj-y += clock.o clock-7x01a.o +obj-y += gpio.o generic_gpio.o obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o diff --git a/arch/arm/mach-msm/generic_gpio.c b/arch/arm/mach-msm/generic_gpio.c new file mode 100644 index 000000000000..86093130f457 --- /dev/null +++ b/arch/arm/mach-msm/generic_gpio.c @@ -0,0 +1,274 @@ +/* arch/arm/mach-msm/generic_gpio.c + * + * Copyright (C) 2007 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 "gpio_chip.h" + +#define GPIO_NUM_TO_CHIP_INDEX(gpio) ((gpio)>>5) + +struct gpio_state { + unsigned long flags; + int refcount; +}; + +static DEFINE_SPINLOCK(gpio_chips_lock); +static LIST_HEAD(gpio_chip_list); +static struct gpio_chip **gpio_chip_array; +static unsigned long gpio_chip_array_size; + +int register_gpio_chip(struct gpio_chip *new_gpio_chip) +{ + int err = 0; + struct gpio_chip *gpio_chip; + int i; + unsigned long irq_flags; + unsigned int chip_array_start_index, chip_array_end_index; + + new_gpio_chip->state = kzalloc((new_gpio_chip->end + 1 - new_gpio_chip->start) * sizeof(new_gpio_chip->state[0]), GFP_KERNEL); + if (new_gpio_chip->state == NULL) { + printk(KERN_ERR "register_gpio_chip: failed to allocate state\n"); + return -ENOMEM; + } + + spin_lock_irqsave(&gpio_chips_lock, irq_flags); + chip_array_start_index = GPIO_NUM_TO_CHIP_INDEX(new_gpio_chip->start); + chip_array_end_index = GPIO_NUM_TO_CHIP_INDEX(new_gpio_chip->end); + if (chip_array_end_index >= gpio_chip_array_size) { + struct gpio_chip **new_gpio_chip_array; + unsigned long new_gpio_chip_array_size = chip_array_end_index + 1; + + new_gpio_chip_array = kmalloc(new_gpio_chip_array_size * sizeof(new_gpio_chip_array[0]), GFP_KERNEL); + if (new_gpio_chip_array == NULL) { + printk(KERN_ERR "register_gpio_chip: failed to allocate array\n"); + err = -ENOMEM; + goto failed; + } + for (i = 0; i < gpio_chip_array_size; i++) + new_gpio_chip_array[i] = gpio_chip_array[i]; + for (i = gpio_chip_array_size; i < new_gpio_chip_array_size; i++) + new_gpio_chip_array[i] = NULL; + gpio_chip_array = new_gpio_chip_array; + gpio_chip_array_size = new_gpio_chip_array_size; + } + list_for_each_entry(gpio_chip, &gpio_chip_list, list) { + if (gpio_chip->start > new_gpio_chip->end) { + list_add_tail(&new_gpio_chip->list, &gpio_chip->list); + goto added; + } + if (gpio_chip->end >= new_gpio_chip->start) { + printk(KERN_ERR "register_gpio_source %u-%u overlaps with %u-%u\n", + new_gpio_chip->start, new_gpio_chip->end, + gpio_chip->start, gpio_chip->end); + err = -EBUSY; + goto failed; + } + } + list_add_tail(&new_gpio_chip->list, &gpio_chip_list); +added: + for (i = chip_array_start_index; i <= chip_array_end_index; i++) { + if (gpio_chip_array[i] == NULL || gpio_chip_array[i]->start > new_gpio_chip->start) + gpio_chip_array[i] = new_gpio_chip; + } +failed: + spin_unlock_irqrestore(&gpio_chips_lock, irq_flags); + if (err) + kfree(new_gpio_chip->state); + return err; +} + +static struct gpio_chip *get_gpio_chip_locked(unsigned int gpio) +{ + unsigned long i; + struct gpio_chip *chip; + + i = GPIO_NUM_TO_CHIP_INDEX(gpio); + if (i >= gpio_chip_array_size) + return NULL; + chip = gpio_chip_array[i]; + if (chip == NULL) + return NULL; + list_for_each_entry_from(chip, &gpio_chip_list, list) { + if (gpio < chip->start) + return NULL; + if (gpio <= chip->end) + return chip; + } + return NULL; +} + +static int request_gpio(unsigned int gpio, unsigned long flags) +{ + int err = 0; + struct gpio_chip *chip; + unsigned long irq_flags; + unsigned long chip_index; + + spin_lock_irqsave(&gpio_chips_lock, irq_flags); + chip = get_gpio_chip_locked(gpio); + if (chip == NULL) { + err = -EINVAL; + goto err; + } + chip_index = gpio - chip->start; + if (chip->state[chip_index].refcount == 0) { + chip->configure(chip, gpio, flags); + chip->state[chip_index].flags = flags; + chip->state[chip_index].refcount++; + } else if ((flags & IRQF_SHARED) && (chip->state[chip_index].flags & IRQF_SHARED)) + chip->state[chip_index].refcount++; + else + err = -EBUSY; +err: + spin_unlock_irqrestore(&gpio_chips_lock, irq_flags); + return err; +} + +int gpio_request(unsigned gpio, const char *label) +{ + return request_gpio(gpio, 0); +} +EXPORT_SYMBOL(gpio_request); + +void gpio_free(unsigned gpio) +{ + struct gpio_chip *chip; + unsigned long irq_flags; + unsigned long chip_index; + + spin_lock_irqsave(&gpio_chips_lock, irq_flags); + chip = get_gpio_chip_locked(gpio); + if (chip) { + chip_index = gpio - chip->start; + chip->state[chip_index].refcount--; + } + spin_unlock_irqrestore(&gpio_chips_lock, irq_flags); +} +EXPORT_SYMBOL(gpio_free); + +static int gpio_get_irq_num(unsigned int gpio, unsigned int *irqp, unsigned long *irqnumflagsp) +{ + int ret = -ENOTSUPP; + struct gpio_chip *chip; + unsigned long irq_flags; + + spin_lock_irqsave(&gpio_chips_lock, irq_flags); + chip = get_gpio_chip_locked(gpio); + if (chip && chip->get_irq_num) + ret = chip->get_irq_num(chip, gpio, irqp, irqnumflagsp); + spin_unlock_irqrestore(&gpio_chips_lock, irq_flags); + return ret; +} + +int gpio_to_irq(unsigned gpio) +{ + int ret, irq; + ret = gpio_get_irq_num(gpio, &irq, NULL); + if (ret) + return ret; + return irq; +} +EXPORT_SYMBOL(gpio_to_irq); + +int gpio_configure(unsigned int gpio, unsigned long flags) +{ + int ret = -ENOTSUPP; + struct gpio_chip *chip; + unsigned long irq_flags; + + spin_lock_irqsave(&gpio_chips_lock, irq_flags); + chip = get_gpio_chip_locked(gpio); + if (chip) + ret = chip->configure(chip, gpio, flags); + spin_unlock_irqrestore(&gpio_chips_lock, irq_flags); + return ret; +} +EXPORT_SYMBOL(gpio_configure); + +int gpio_direction_input(unsigned gpio) +{ + return gpio_configure(gpio, GPIOF_INPUT); +} +EXPORT_SYMBOL(gpio_direction_input); + +int gpio_direction_output(unsigned gpio, int value) +{ + gpio_set_value(gpio, value); + return gpio_configure(gpio, GPIOF_DRIVE_OUTPUT); +} +EXPORT_SYMBOL(gpio_direction_output); + +int gpio_get_value(unsigned gpio) +{ + int ret = -ENOTSUPP; + struct gpio_chip *chip; + unsigned long irq_flags; + + spin_lock_irqsave(&gpio_chips_lock, irq_flags); + chip = get_gpio_chip_locked(gpio); + if (chip && chip->read) + ret = chip->read(chip, gpio); + spin_unlock_irqrestore(&gpio_chips_lock, irq_flags); + return ret; +} +EXPORT_SYMBOL(gpio_get_value); + +void gpio_set_value(unsigned gpio, int on) +{ + int ret = -ENOTSUPP; + struct gpio_chip *chip; + unsigned long irq_flags; + + spin_lock_irqsave(&gpio_chips_lock, irq_flags); + chip = get_gpio_chip_locked(gpio); + if (chip && chip->write) + ret = chip->write(chip, gpio, on); + spin_unlock_irqrestore(&gpio_chips_lock, irq_flags); +} +EXPORT_SYMBOL(gpio_set_value); + +int gpio_read_detect_status(unsigned int gpio) +{ + int ret = -ENOTSUPP; + struct gpio_chip *chip; + unsigned long irq_flags; + + spin_lock_irqsave(&gpio_chips_lock, irq_flags); + chip = get_gpio_chip_locked(gpio); + if (chip && chip->read_detect_status) + ret = chip->read_detect_status(chip, gpio); + spin_unlock_irqrestore(&gpio_chips_lock, irq_flags); + return ret; +} +EXPORT_SYMBOL(gpio_read_detect_status); + +int gpio_clear_detect_status(unsigned int gpio) +{ + int ret = -ENOTSUPP; + struct gpio_chip *chip; + unsigned long irq_flags; + + spin_lock_irqsave(&gpio_chips_lock, irq_flags); + chip = get_gpio_chip_locked(gpio); + if (chip && chip->clear_detect_status) + ret = chip->clear_detect_status(chip, gpio); + spin_unlock_irqrestore(&gpio_chips_lock, irq_flags); + return ret; +} +EXPORT_SYMBOL(gpio_clear_detect_status); diff --git a/arch/arm/mach-msm/gpio.c b/arch/arm/mach-msm/gpio.c new file mode 100644 index 000000000000..24b510986e70 --- /dev/null +++ b/arch/arm/mach-msm/gpio.c @@ -0,0 +1,530 @@ +/* linux/arch/arm/mach-msm/gpio.c + * + * Copyright (C) 2007 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 "gpio_chip.h" +#include "gpio_hw.h" + +#include "smd_private.h" + +enum { + GPIO_DEBUG_SLEEP = 1U << 0, +}; +static int msm_gpio_debug_mask = 0; +module_param_named(debug_mask, msm_gpio_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP); + +#define MSM_GPIO_BROKEN_INT_CLEAR 1 + +/* private gpio_configure flags */ +#define MSM_GPIOF_ENABLE_INTERRUPT 0x10000000 +#define MSM_GPIOF_DISABLE_INTERRUPT 0x20000000 +#define MSM_GPIOF_ENABLE_WAKE 0x40000000 +#define MSM_GPIOF_DISABLE_WAKE 0x80000000 + +static int msm_gpio_configure(struct gpio_chip *chip, unsigned int gpio, unsigned long flags); +static int msm_gpio_get_irq_num(struct gpio_chip *chip, unsigned int gpio, unsigned int *irqp, unsigned long *irqnumflagsp); +static int msm_gpio_read(struct gpio_chip *chip, unsigned n); +static int msm_gpio_write(struct gpio_chip *chip, unsigned n, unsigned on); +static int msm_gpio_read_detect_status(struct gpio_chip *chip, unsigned int gpio); +static int msm_gpio_clear_detect_status(struct gpio_chip *chip, unsigned int gpio); + +struct msm_gpio_regs +{ + void __iomem *out; + void __iomem *in; + void __iomem *int_status; + void __iomem *int_clear; + void __iomem *int_en; + void __iomem *int_edge; + void __iomem *int_pos; + void __iomem *oe; +}; + +struct msm_gpio_chip { + struct gpio_chip chip; + struct msm_gpio_regs regs; +#if MSM_GPIO_BROKEN_INT_CLEAR + unsigned int_status_copy; +#endif + unsigned int both_edge_detect; + unsigned int int_enable[2]; /* 0: awake, 1: sleep */ +}; + +struct msm_gpio_chip msm_gpio_chips[] = { + { + .regs = { + .out = GPIO_OUT_0, + .in = GPIO_IN_0, + .int_status = GPIO_INT_STATUS_0, + .int_clear = GPIO_INT_CLEAR_0, + .int_en = GPIO_INT_EN_0, + .int_edge = GPIO_INT_EDGE_0, + .int_pos = GPIO_INT_POS_0, + .oe = GPIO_OE_0, + }, + .chip = { + .start = 0, + .end = 15, + .configure = msm_gpio_configure, + .get_irq_num = msm_gpio_get_irq_num, + .read = msm_gpio_read, + .write = msm_gpio_write, + .read_detect_status = msm_gpio_read_detect_status, + .clear_detect_status = msm_gpio_clear_detect_status + } + }, + { + .regs = { + .out = GPIO_OUT_1, + .in = GPIO_IN_1, + .int_status = GPIO_INT_STATUS_1, + .int_clear = GPIO_INT_CLEAR_1, + .int_en = GPIO_INT_EN_1, + .int_edge = GPIO_INT_EDGE_1, + .int_pos = GPIO_INT_POS_1, + .oe = GPIO_OE_1, + }, + .chip = { + .start = 16, + .end = 42, + .configure = msm_gpio_configure, + .get_irq_num = msm_gpio_get_irq_num, + .read = msm_gpio_read, + .write = msm_gpio_write, + .read_detect_status = msm_gpio_read_detect_status, + .clear_detect_status = msm_gpio_clear_detect_status + } + }, + { + .regs = { + .out = GPIO_OUT_2, + .in = GPIO_IN_2, + .int_status = GPIO_INT_STATUS_2, + .int_clear = GPIO_INT_CLEAR_2, + .int_en = GPIO_INT_EN_2, + .int_edge = GPIO_INT_EDGE_2, + .int_pos = GPIO_INT_POS_2, + .oe = GPIO_OE_2, + }, + .chip = { + .start = 43, + .end = 67, + .configure = msm_gpio_configure, + .get_irq_num = msm_gpio_get_irq_num, + .read = msm_gpio_read, + .write = msm_gpio_write, + .read_detect_status = msm_gpio_read_detect_status, + .clear_detect_status = msm_gpio_clear_detect_status + } + }, + { + .regs = { + .out = GPIO_OUT_3, + .in = GPIO_IN_3, + .int_status = GPIO_INT_STATUS_3, + .int_clear = GPIO_INT_CLEAR_3, + .int_en = GPIO_INT_EN_3, + .int_edge = GPIO_INT_EDGE_3, + .int_pos = GPIO_INT_POS_3, + .oe = GPIO_OE_3, + }, + .chip = { + .start = 68, + .end = 94, + .configure = msm_gpio_configure, + .get_irq_num = msm_gpio_get_irq_num, + .read = msm_gpio_read, + .write = msm_gpio_write, + .read_detect_status = msm_gpio_read_detect_status, + .clear_detect_status = msm_gpio_clear_detect_status + } + }, + { + .regs = { + .out = GPIO_OUT_4, + .in = GPIO_IN_4, + .int_status = GPIO_INT_STATUS_4, + .int_clear = GPIO_INT_CLEAR_4, + .int_en = GPIO_INT_EN_4, + .int_edge = GPIO_INT_EDGE_4, + .int_pos = GPIO_INT_POS_4, + .oe = GPIO_OE_4, + }, + .chip = { + .start = 95, + .end = 106, + .configure = msm_gpio_configure, + .get_irq_num = msm_gpio_get_irq_num, + .read = msm_gpio_read, + .write = msm_gpio_write, + .read_detect_status = msm_gpio_read_detect_status, + .clear_detect_status = msm_gpio_clear_detect_status + } + }, + { + .regs = { + .out = GPIO_OUT_5, + .in = GPIO_IN_5, + .int_status = GPIO_INT_STATUS_5, + .int_clear = GPIO_INT_CLEAR_5, + .int_en = GPIO_INT_EN_5, + .int_edge = GPIO_INT_EDGE_5, + .int_pos = GPIO_INT_POS_5, + .oe = GPIO_OE_5, + }, + .chip = { + .start = 107, + .end = 121, + .configure = msm_gpio_configure, + .get_irq_num = msm_gpio_get_irq_num, + .read = msm_gpio_read, + .write = msm_gpio_write, + .read_detect_status = msm_gpio_read_detect_status, + .clear_detect_status = msm_gpio_clear_detect_status + } + } +}; + +static void msm_gpio_update_both_edge_detect(struct msm_gpio_chip *msm_chip) +{ + int loop_limit = 100; + unsigned pol, val, val2, intstat; + do { + val = readl(msm_chip->regs.in); + pol = readl(msm_chip->regs.int_pos); + pol = (pol & ~msm_chip->both_edge_detect) | (~val & msm_chip->both_edge_detect); + writel(pol, msm_chip->regs.int_pos); + intstat = readl(msm_chip->regs.int_status); + val2 = readl(msm_chip->regs.in); + if (((val ^ val2) & msm_chip->both_edge_detect & ~intstat) == 0) + return; + } while (loop_limit-- > 0); + printk(KERN_ERR "msm_gpio_update_both_edge_detect, failed to reach stable state %x != %x\n", val, val2); +} + +static int msm_gpio_write(struct gpio_chip *chip, unsigned n, unsigned on) +{ + struct msm_gpio_chip *msm_chip = container_of(chip, struct msm_gpio_chip, chip); + unsigned b = 1U << (n - chip->start); + unsigned v; + + v = readl(msm_chip->regs.out); + if (on) { + writel(v | b, msm_chip->regs.out); + } else { + writel(v & (~b), msm_chip->regs.out); + } + return 0; +} + +static int msm_gpio_read(struct gpio_chip *chip, unsigned n) +{ + struct msm_gpio_chip *msm_chip = container_of(chip, struct msm_gpio_chip, chip); + unsigned b = 1U << (n - chip->start); + + return (readl(msm_chip->regs.in) & b) ? 1 : 0; +} + +static int msm_gpio_read_detect_status(struct gpio_chip *chip, unsigned int gpio) +{ + struct msm_gpio_chip *msm_chip = container_of(chip, struct msm_gpio_chip, chip); + unsigned b = 1U << (gpio - chip->start); + unsigned v; + + v = readl(msm_chip->regs.int_status); +#if MSM_GPIO_BROKEN_INT_CLEAR + v |= msm_chip->int_status_copy; +#endif + return (v & b) ? 1 : 0; +} + +static int msm_gpio_clear_detect_status(struct gpio_chip *chip, unsigned int gpio) +{ + struct msm_gpio_chip *msm_chip = container_of(chip, struct msm_gpio_chip, chip); + unsigned b = 1U << (gpio - chip->start); + +#if MSM_GPIO_BROKEN_INT_CLEAR + /* Save interrupts that already triggered before we loose them. */ + /* Any interrupt that triggers between the read of int_status */ + /* and the write to int_clear will still be lost though. */ + msm_chip->int_status_copy |= readl(msm_chip->regs.int_status); + msm_chip->int_status_copy &= ~b; +#endif + writel(b, msm_chip->regs.int_clear); + msm_gpio_update_both_edge_detect(msm_chip); + return 0; +} + +int msm_gpio_configure(struct gpio_chip *chip, unsigned int gpio, unsigned long flags) +{ + struct msm_gpio_chip *msm_chip = container_of(chip, struct msm_gpio_chip, chip); + unsigned b = 1U << (gpio - chip->start); + unsigned v; + + if (flags & (GPIOF_OUTPUT_LOW | GPIOF_OUTPUT_HIGH)) + msm_gpio_write(chip, gpio, flags & GPIOF_OUTPUT_HIGH); + + if (flags & (GPIOF_INPUT | GPIOF_DRIVE_OUTPUT)) { + v = readl(msm_chip->regs.oe); + if (flags & GPIOF_DRIVE_OUTPUT) { + writel(v | b, msm_chip->regs.oe); + } else { + writel(v & (~b), msm_chip->regs.oe); + } + } + + if (flags & (IRQF_TRIGGER_MASK | GPIOF_IRQF_TRIGGER_NONE)) { + v = readl(msm_chip->regs.int_edge); + if (flags & (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING)) { + writel(v | b, msm_chip->regs.int_edge); + irq_desc[MSM_GPIO_TO_INT(gpio)].handle_irq = handle_edge_irq; + } else { + writel(v & (~b), msm_chip->regs.int_edge); + irq_desc[MSM_GPIO_TO_INT(gpio)].handle_irq = handle_level_irq; + } + if ((flags & (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING)) == (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING)) { + msm_chip->both_edge_detect |= b; + msm_gpio_update_both_edge_detect(msm_chip); + } else { + msm_chip->both_edge_detect &= ~b; + v = readl(msm_chip->regs.int_pos); + if (flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_HIGH)) { + writel(v | b, msm_chip->regs.int_pos); + } else { + writel(v & (~b), msm_chip->regs.int_pos); + } + } + } + + /* used by msm_gpio_irq_mask and msm_gpio_irq_unmask */ + if (flags & (MSM_GPIOF_ENABLE_INTERRUPT | MSM_GPIOF_DISABLE_INTERRUPT)) { + v = readl(msm_chip->regs.int_edge); + /* level triggered interrupts are also latched */ + if (!(v & b)) + msm_gpio_clear_detect_status(chip, gpio); + if (flags & MSM_GPIOF_ENABLE_INTERRUPT) { + msm_chip->int_enable[0] |= b; + } else { + msm_chip->int_enable[0] &= ~b; + } + writel(msm_chip->int_enable[0], msm_chip->regs.int_en); + } + + if (flags & (MSM_GPIOF_ENABLE_WAKE | MSM_GPIOF_DISABLE_WAKE)) { + if (flags & MSM_GPIOF_ENABLE_WAKE) + msm_chip->int_enable[1] |= b; + else + msm_chip->int_enable[1] &= ~b; + } + + return 0; +} + +static int msm_gpio_get_irq_num(struct gpio_chip *chip, unsigned int gpio, unsigned int *irqp, unsigned long *irqnumflagsp) +{ + *irqp = MSM_GPIO_TO_INT(gpio); + if (irqnumflagsp) + *irqnumflagsp = 0; + return 0; +} + + +static void msm_gpio_irq_ack(unsigned int irq) +{ + gpio_clear_detect_status(irq - NR_MSM_IRQS); +} + +static void msm_gpio_irq_mask(unsigned int irq) +{ + gpio_configure(irq - NR_MSM_IRQS, MSM_GPIOF_DISABLE_INTERRUPT); +} + +static void msm_gpio_irq_unmask(unsigned int irq) +{ + gpio_configure(irq - NR_MSM_IRQS, MSM_GPIOF_ENABLE_INTERRUPT); +} + +static int msm_gpio_irq_set_wake(unsigned int irq, unsigned int on) +{ + return gpio_configure(irq - NR_MSM_IRQS, on ? MSM_GPIOF_ENABLE_WAKE : MSM_GPIOF_DISABLE_WAKE); +} + + +static int msm_gpio_irq_set_type(unsigned int irq, unsigned int flow_type) +{ + return gpio_configure(irq - NR_MSM_IRQS, flow_type); +} + +static void msm_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) +{ + int i, j, m; + unsigned v; + + for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) { + struct msm_gpio_chip *msm_chip = &msm_gpio_chips[i]; + v = readl(msm_chip->regs.int_status); + v &= msm_chip->int_enable[0]; + while (v) { + m = v & -v; + j = fls(m) - 1; + /* printk("msm_gpio_irq_handler %08x %08x bit %d gpio %d irq %d\n", v, m, j, msm_chip->chip.start + j, NR_MSM_IRQS + msm_chip->chip.start + j); */ + v &= ~m; + generic_handle_irq(NR_MSM_IRQS + msm_chip->chip.start + j); + } + } + desc->chip->ack(irq); +} + +static struct irq_chip msm_gpio_irq_chip = { + .name = "msmgpio", + .ack = msm_gpio_irq_ack, + .mask = msm_gpio_irq_mask, + .unmask = msm_gpio_irq_unmask, + .set_wake = msm_gpio_irq_set_wake, + .set_type = msm_gpio_irq_set_type, +}; + +#define NUM_GPIO_INT_REGISTERS 6 +#define GPIO_SMEM_NUM_GROUPS 2 +#define GPIO_SMEM_MAX_PC_INTERRUPTS 8 +struct tramp_gpio_smem +{ + uint16_t num_fired[GPIO_SMEM_NUM_GROUPS]; + uint16_t fired[GPIO_SMEM_NUM_GROUPS][GPIO_SMEM_MAX_PC_INTERRUPTS]; + uint32_t enabled[NUM_GPIO_INT_REGISTERS]; + uint32_t detection[NUM_GPIO_INT_REGISTERS]; + uint32_t polarity[NUM_GPIO_INT_REGISTERS]; +}; + +static void msm_gpio_sleep_int(unsigned long arg) +{ + int i, j; + struct tramp_gpio_smem *smem_gpio; + + BUILD_BUG_ON(ARRAY_SIZE(msm_gpio_chips) != ARRAY_SIZE(smem_gpio->enabled)); + + smem_gpio = smem_alloc(SMEM_GPIO_INT, sizeof(*smem_gpio)); + if (smem_gpio == NULL) + return; + + for(i = 0; i < GPIO_SMEM_NUM_GROUPS; i++) { + int count = smem_gpio->num_fired[i]; + for(j = 0; j < count; j++) { + /* TODO: Check mask */ + generic_handle_irq(MSM_GPIO_TO_INT(smem_gpio->fired[i][j])); + } + } +} + +static DECLARE_TASKLET(msm_gpio_sleep_int_tasklet, msm_gpio_sleep_int, 0); + +void msm_gpio_enter_sleep(int from_idle) +{ + int i; + struct tramp_gpio_smem *smem_gpio; + + BUILD_BUG_ON(ARRAY_SIZE(msm_gpio_chips) != ARRAY_SIZE(smem_gpio->enabled)); + + smem_gpio = smem_alloc(SMEM_GPIO_INT, sizeof(*smem_gpio)); + + if (smem_gpio) { + for (i = 0; i < ARRAY_SIZE(smem_gpio->enabled); i++) { + smem_gpio->enabled[i] = 0; + smem_gpio->detection[i] = 0; + smem_gpio->polarity[i] = 0; + } + } + + for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) { + writel(msm_gpio_chips[i].int_enable[!from_idle], msm_gpio_chips[i].regs.int_en); + if (smem_gpio) { + uint32_t tmp; + int start, index, shiftl, shiftr; + start = msm_gpio_chips[i].chip.start; + index = start / 32; + shiftl = start % 32; + shiftr = 32 - shiftl; + tmp = msm_gpio_chips[i].int_enable[!from_idle]; + smem_gpio->enabled[index] |= tmp << shiftl; + smem_gpio->enabled[index+1] |= tmp >> shiftr; + smem_gpio->detection[index] |= readl(msm_gpio_chips[i].regs.int_edge) << shiftl; + smem_gpio->detection[index+1] |= readl(msm_gpio_chips[i].regs.int_edge) >> shiftr; + smem_gpio->polarity[index] |= readl(msm_gpio_chips[i].regs.int_pos) << shiftl; + smem_gpio->polarity[index+1] |= readl(msm_gpio_chips[i].regs.int_pos) >> shiftr; + } + } + + if (smem_gpio) { + if (msm_gpio_debug_mask & GPIO_DEBUG_SLEEP) + for (i = 0; i < ARRAY_SIZE(smem_gpio->enabled); i++) { + printk("msm_gpio_enter_sleep gpio %d-%d: enable" + " %08x, edge %08x, polarity %08x\n", + i * 32, i * 32 + 31, + smem_gpio->enabled[i], + smem_gpio->detection[i], + smem_gpio->polarity[i]); + } + for(i = 0; i < GPIO_SMEM_NUM_GROUPS; i++) + smem_gpio->num_fired[i] = 0; + } +} + +void msm_gpio_exit_sleep(void) +{ + int i; + struct tramp_gpio_smem *smem_gpio; + + BUILD_BUG_ON(ARRAY_SIZE(msm_gpio_chips) != ARRAY_SIZE(smem_gpio->enabled)); + + smem_gpio = smem_alloc(SMEM_GPIO_INT, sizeof(*smem_gpio)); + + for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) { + writel(msm_gpio_chips[i].int_enable[0], msm_gpio_chips[i].regs.int_en); + } + + if (smem_gpio && (smem_gpio->num_fired[0] || smem_gpio->num_fired[1])) { + if (msm_gpio_debug_mask & GPIO_DEBUG_SLEEP) + printk(KERN_INFO "gpio: fired %x %x\n", + smem_gpio->num_fired[0], smem_gpio->num_fired[1]); + tasklet_schedule(&msm_gpio_sleep_int_tasklet); + } +} + +static int __init msm_init_gpio(void) +{ + int i; + + for (i = NR_MSM_IRQS; i < NR_MSM_IRQS + NR_GPIO_IRQS; i++) { + set_irq_chip(i, &msm_gpio_irq_chip); + set_irq_handler(i, handle_edge_irq); + set_irq_flags(i, IRQF_VALID); + } + + for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) { + writel(0, msm_gpio_chips[i].regs.int_en); + register_gpio_chip(&msm_gpio_chips[i].chip); + } + + set_irq_chained_handler(INT_GPIO_GROUP1, msm_gpio_irq_handler); + set_irq_chained_handler(INT_GPIO_GROUP2, msm_gpio_irq_handler); + set_irq_wake(INT_GPIO_GROUP1, 1); + set_irq_wake(INT_GPIO_GROUP2, 2); + return 0; +} + +postcore_initcall(msm_init_gpio); diff --git a/arch/arm/mach-msm/gpio_chip.h b/arch/arm/mach-msm/gpio_chip.h new file mode 100644 index 000000000000..eab9f0946921 --- /dev/null +++ b/arch/arm/mach-msm/gpio_chip.h @@ -0,0 +1,38 @@ +/* arch/arm/mach-msm/gpio_chip.h + * + * Copyright (C) 2007 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#ifndef _LINUX_GPIO_CHIP_H +#define _LINUX_GPIO_CHIP_H + +#include + +struct gpio_chip { + struct list_head list; + struct gpio_state *state; + + unsigned int start; + unsigned int end; + + int (*configure)(struct gpio_chip *chip, unsigned int gpio, unsigned long flags); + int (*get_irq_num)(struct gpio_chip *chip, unsigned int gpio, unsigned int *irqp, unsigned long *irqnumflagsp); + int (*read)(struct gpio_chip *chip, unsigned int gpio); + int (*write)(struct gpio_chip *chip, unsigned int gpio, unsigned on); + int (*read_detect_status)(struct gpio_chip *chip, unsigned int gpio); + int (*clear_detect_status)(struct gpio_chip *chip, unsigned int gpio); +}; + +int register_gpio_chip(struct gpio_chip *gpio_chip); + +#endif diff --git a/arch/arm/mach-msm/gpio_hw.h b/arch/arm/mach-msm/gpio_hw.h new file mode 100644 index 000000000000..61f410c6e7ff --- /dev/null +++ b/arch/arm/mach-msm/gpio_hw.h @@ -0,0 +1,100 @@ +/* arch/arm/mach-msm/gpio_hw.h + * + * Copyright (C) 2007 Google, Inc. + * Author: Brian Swetland + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#ifndef __ARCH_ARM_MACH_MSM_GPIO_HW_H +#define __ARCH_ARM_MACH_MSM_GPIO_HW_H + +#include + +/* see 80-VA736-2 Rev C pp 695-751 +** +** These are actually the *shadow* gpio registers, since the +** real ones (which allow full access) are only available to the +** ARM9 side of the world. +** +** Since the _BASE need to be page-aligned when we're mapping them +** to virtual addresses, adjust for the additional offset in these +** macros. +*/ + +#define GPIO1_REG(off) (MSM_GPIO1_BASE + 0x800 + (off)) +#define GPIO2_REG(off) (MSM_GPIO2_BASE + 0xC00 + (off)) + +/* output value */ +#define GPIO_OUT_0 GPIO1_REG(0x00) /* gpio 15-0 */ +#define GPIO_OUT_1 GPIO2_REG(0x00) /* gpio 42-16 */ +#define GPIO_OUT_2 GPIO1_REG(0x04) /* gpio 67-43 */ +#define GPIO_OUT_3 GPIO1_REG(0x08) /* gpio 94-68 */ +#define GPIO_OUT_4 GPIO1_REG(0x0C) /* gpio 106-95 */ +#define GPIO_OUT_5 GPIO1_REG(0x50) /* gpio 107-121 */ + +/* same pin map as above, output enable */ +#define GPIO_OE_0 GPIO1_REG(0x10) +#define GPIO_OE_1 GPIO2_REG(0x08) +#define GPIO_OE_2 GPIO1_REG(0x14) +#define GPIO_OE_3 GPIO1_REG(0x18) +#define GPIO_OE_4 GPIO1_REG(0x1C) +#define GPIO_OE_5 GPIO1_REG(0x54) + +/* same pin map as above, input read */ +#define GPIO_IN_0 GPIO1_REG(0x34) +#define GPIO_IN_1 GPIO2_REG(0x20) +#define GPIO_IN_2 GPIO1_REG(0x38) +#define GPIO_IN_3 GPIO1_REG(0x3C) +#define GPIO_IN_4 GPIO1_REG(0x40) +#define GPIO_IN_5 GPIO1_REG(0x44) + +/* same pin map as above, 1=edge 0=level interrup */ +#define GPIO_INT_EDGE_0 GPIO1_REG(0x60) +#define GPIO_INT_EDGE_1 GPIO2_REG(0x50) +#define GPIO_INT_EDGE_2 GPIO1_REG(0x64) +#define GPIO_INT_EDGE_3 GPIO1_REG(0x68) +#define GPIO_INT_EDGE_4 GPIO1_REG(0x6C) +#define GPIO_INT_EDGE_5 GPIO1_REG(0xC0) + +/* same pin map as above, 1=positive 0=negative */ +#define GPIO_INT_POS_0 GPIO1_REG(0x70) +#define GPIO_INT_POS_1 GPIO2_REG(0x58) +#define GPIO_INT_POS_2 GPIO1_REG(0x74) +#define GPIO_INT_POS_3 GPIO1_REG(0x78) +#define GPIO_INT_POS_4 GPIO1_REG(0x7C) +#define GPIO_INT_POS_5 GPIO1_REG(0xBC) + +/* same pin map as above, interrupt enable */ +#define GPIO_INT_EN_0 GPIO1_REG(0x80) +#define GPIO_INT_EN_1 GPIO2_REG(0x60) +#define GPIO_INT_EN_2 GPIO1_REG(0x84) +#define GPIO_INT_EN_3 GPIO1_REG(0x88) +#define GPIO_INT_EN_4 GPIO1_REG(0x8C) +#define GPIO_INT_EN_5 GPIO1_REG(0xB8) + +/* same pin map as above, write 1 to clear interrupt */ +#define GPIO_INT_CLEAR_0 GPIO1_REG(0x90) +#define GPIO_INT_CLEAR_1 GPIO2_REG(0x68) +#define GPIO_INT_CLEAR_2 GPIO1_REG(0x94) +#define GPIO_INT_CLEAR_3 GPIO1_REG(0x98) +#define GPIO_INT_CLEAR_4 GPIO1_REG(0x9C) +#define GPIO_INT_CLEAR_5 GPIO1_REG(0xB4) + +/* same pin map as above, 1=interrupt pending */ +#define GPIO_INT_STATUS_0 GPIO1_REG(0xA0) +#define GPIO_INT_STATUS_1 GPIO2_REG(0x70) +#define GPIO_INT_STATUS_2 GPIO1_REG(0xA4) +#define GPIO_INT_STATUS_3 GPIO1_REG(0xA8) +#define GPIO_INT_STATUS_4 GPIO1_REG(0xAC) +#define GPIO_INT_STATUS_5 GPIO1_REG(0xB0) + +#endif diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h index 264d62e519f3..65bb79202d83 100644 --- a/arch/arm/mach-msm/include/mach/board.h +++ b/arch/arm/mach-msm/include/mach/board.h @@ -32,7 +32,6 @@ struct msm_mddi_platform_data void __init msm_add_devices(void); void __init msm_map_common_io(void); void __init msm_init_irq(void); -void __init msm_init_gpio(void); void __init msm_clock_init(void); #endif diff --git a/arch/arm/mach-msm/include/mach/gpio.h b/arch/arm/mach-msm/include/mach/gpio.h new file mode 100644 index 000000000000..590573f78c2f --- /dev/null +++ b/arch/arm/mach-msm/include/mach/gpio.h @@ -0,0 +1,47 @@ +/* linux/include/asm-arm/arch-msm/gpio.h + * + * Copyright (C) 2007 Google, Inc. + * Author: Mike Lockwood + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#ifndef __ASM_ARCH_MSM_GPIO_H +#define __ASM_ARCH_MSM_GPIO_H + +#include + +int gpio_request(unsigned gpio, const char *label); +void gpio_free(unsigned gpio); +int gpio_direction_input(unsigned gpio); +int gpio_direction_output(unsigned gpio, int value); +int gpio_get_value(unsigned gpio); +void gpio_set_value(unsigned gpio, int value); +int gpio_to_irq(unsigned gpio); + +#include + +/* extended gpio api */ + +#define GPIOF_IRQF_MASK 0x0000ffff /* use to specify edge detection without */ +#define GPIOF_IRQF_TRIGGER_NONE 0x00010000 /* IRQF_TRIGGER_NONE is 0 which also means "as already configured" */ +#define GPIOF_INPUT 0x00020000 +#define GPIOF_DRIVE_OUTPUT 0x00040000 +#define GPIOF_OUTPUT_LOW 0x00080000 +#define GPIOF_OUTPUT_HIGH 0x00100000 + +#define GPIOIRQF_SHARED 0x00000001 /* the irq line is shared with other inputs */ + +extern int gpio_configure(unsigned int gpio, unsigned long flags); +extern int gpio_read_detect_status(unsigned int gpio); +extern int gpio_clear_detect_status(unsigned int gpio); + +#endif -- cgit v1.2.3 From 129fa48d74bdc1a9d1bf10669ac60e8acab59a37 Mon Sep 17 00:00:00 2001 From: Brian Swetland Date: Mon, 29 Sep 2008 16:00:48 -0700 Subject: [ARM] msm: shared memory interface for baseband processor ipc This code provides the low level interface to the "shared memory state machine" (smsm), and the virtual serial channels (smd), used to communicate with the baseband processor. Higher level transports (rpc, ethernet, AT command channel, etc) ride on top of this. Signed-off-by: Brian Swetland --- arch/arm/mach-msm/Kconfig | 10 + arch/arm/mach-msm/Makefile | 3 +- arch/arm/mach-msm/include/mach/msm_smd.h | 107 +++ arch/arm/mach-msm/include/mach/system.h | 5 + arch/arm/mach-msm/smd.c | 1330 ++++++++++++++++++++++++++++++ arch/arm/mach-msm/smd_private.h | 171 ++++ 6 files changed, 1625 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-msm/include/mach/msm_smd.h create mode 100644 arch/arm/mach-msm/smd.c create mode 100644 arch/arm/mach-msm/smd_private.h (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index b9fd5c528e5b..7cee7913f6f7 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -42,4 +42,14 @@ config MACH_TROUT help Support for the HTC Dream, T-Mobile G1, Android ADP1 devices. +config MSM_SMD + default y + bool "MSM Shared Memory Driver (SMD)" + help + Support for the shared memory interface between the apps + processor and the baseband processor. Provides access to + the "shared heap", as well as virtual serial channels + used to communicate with various services on the baseband + processor. + endif diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index fd06eb853a2c..dbaf8fc55340 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -5,6 +5,7 @@ obj-y += vreg.o obj-y += clock.o clock-7x01a.o obj-y += gpio.o generic_gpio.o -obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o +obj-$(CONFIG_MSM_SMD) += smd.o obj-$(CONFIG_MACH_TROUT) += board-dream.o +obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o diff --git a/arch/arm/mach-msm/include/mach/msm_smd.h b/arch/arm/mach-msm/include/mach/msm_smd.h new file mode 100644 index 000000000000..bdf7731ab680 --- /dev/null +++ b/arch/arm/mach-msm/include/mach/msm_smd.h @@ -0,0 +1,107 @@ +/* linux/include/asm-arm/arch-msm/msm_smd.h + * + * Copyright (C) 2007 Google, Inc. + * Author: Brian Swetland + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#ifndef __ASM_ARCH_MSM_SMD_H +#define __ASM_ARCH_MSM_SMD_H + +typedef struct smd_channel smd_channel_t; + +/* warning: notify() may be called before open returns */ +int smd_open(const char *name, smd_channel_t **ch, void *priv, + void (*notify)(void *priv, unsigned event)); + +#define SMD_EVENT_DATA 1 +#define SMD_EVENT_OPEN 2 +#define SMD_EVENT_CLOSE 3 + +int smd_close(smd_channel_t *ch); + +/* passing a null pointer for data reads and discards */ +int smd_read(smd_channel_t *ch, void *data, int len); + +/* Write to stream channels may do a partial write and return +** the length actually written. +** Write to packet channels will never do a partial write -- +** it will return the requested length written or an error. +*/ +int smd_write(smd_channel_t *ch, const void *data, int len); + +int smd_write_avail(smd_channel_t *ch); +int smd_read_avail(smd_channel_t *ch); + +/* Returns the total size of the current packet being read. +** Returns 0 if no packets available or a stream channel. +*/ +int smd_cur_packet_size(smd_channel_t *ch); + +/* used for tty unthrottling and the like -- causes the notify() +** callback to be called from the same lock context as is used +** when it is called from channel updates +*/ +void smd_kick(smd_channel_t *ch); + + +#if 0 +/* these are interruptable waits which will block you until the specified +** number of bytes are readable or writable. +*/ +int smd_wait_until_readable(smd_channel_t *ch, int bytes); +int smd_wait_until_writable(smd_channel_t *ch, int bytes); +#endif + +typedef enum +{ + SMD_PORT_DS = 0, + SMD_PORT_DIAG, + SMD_PORT_RPC_CALL, + SMD_PORT_RPC_REPLY, + SMD_PORT_BT, + SMD_PORT_CONTROL, + SMD_PORT_MEMCPY_SPARE1, + SMD_PORT_DATA1, + SMD_PORT_DATA2, + SMD_PORT_DATA3, + SMD_PORT_DATA4, + SMD_PORT_DATA5, + SMD_PORT_DATA6, + SMD_PORT_DATA7, + SMD_PORT_DATA8, + SMD_PORT_DATA9, + SMD_PORT_DATA10, + SMD_PORT_DATA11, + SMD_PORT_DATA12, + SMD_PORT_DATA13, + SMD_PORT_DATA14, + SMD_PORT_DATA15, + SMD_PORT_DATA16, + SMD_PORT_DATA17, + SMD_PORT_DATA18, + SMD_PORT_DATA19, + SMD_PORT_DATA20, + SMD_PORT_GPS_NMEA, + SMD_PORT_BRIDGE_1, + SMD_PORT_BRIDGE_2, + SMD_PORT_BRIDGE_3, + SMD_PORT_BRIDGE_4, + SMD_PORT_BRIDGE_5, + SMD_PORT_LOOPBACK, + SMD_PORT_CS_APPS_MODEM, + SMD_PORT_CS_APPS_DSP, + SMD_PORT_CS_MODEM_DSP, + SMD_NUM_PORTS, +} smd_port_id_type; + +#endif diff --git a/arch/arm/mach-msm/include/mach/system.h b/arch/arm/mach-msm/include/mach/system.h index 574ccc493daf..d2e83f42ba16 100644 --- a/arch/arm/mach-msm/include/mach/system.h +++ b/arch/arm/mach-msm/include/mach/system.h @@ -21,3 +21,8 @@ static inline void arch_reset(char mode, const char *cmd) { for (;;) ; /* depends on IPC w/ other core */ } + +/* low level hardware reset hook -- for example, hitting the + * PSHOLD line on the PMIC to hard reset the system + */ +extern void (*msm_hw_reset_hook)(void); diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c new file mode 100644 index 000000000000..64d12323995e --- /dev/null +++ b/arch/arm/mach-msm/smd.c @@ -0,0 +1,1330 @@ +/* arch/arm/mach-msm/smd.c + * + * Copyright (C) 2007 Google, Inc. + * Author: Brian Swetland + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 +#include + +#include "smd_private.h" +#include "proc_comm.h" + +void (*msm_hw_reset_hook)(void); + +#define MODULE_NAME "msm_smd" + +enum { + MSM_SMD_DEBUG = 1U << 0, + MSM_SMSM_DEBUG = 1U << 0, +}; + +static int msm_smd_debug_mask; + +module_param_named(debug_mask, msm_smd_debug_mask, + int, S_IRUGO | S_IWUSR | S_IWGRP); + +void *smem_find(unsigned id, unsigned size); +static void smd_diag(void); + +static unsigned last_heap_free = 0xffffffff; + +#define MSM_A2M_INT(n) (MSM_CSR_BASE + 0x400 + (n) * 4) + +static inline void notify_other_smsm(void) +{ + writel(1, MSM_A2M_INT(5)); +} + +static inline void notify_other_smd(void) +{ + writel(1, MSM_A2M_INT(0)); +} + +static void smd_diag(void) +{ + char *x; + + x = smem_find(ID_DIAG_ERR_MSG, SZ_DIAG_ERR_MSG); + if (x != 0) { + x[SZ_DIAG_ERR_MSG - 1] = 0; + pr_info("smem: DIAG '%s'\n", x); + } +} + +/* call when SMSM_RESET flag is set in the A9's smsm_state */ +static void handle_modem_crash(void) +{ + pr_err("ARM9 has CRASHED\n"); + smd_diag(); + + /* hard reboot if possible */ + if (msm_hw_reset_hook) + msm_hw_reset_hook(); + + /* in this case the modem or watchdog should reboot us */ + for (;;) + ; +} + +extern int (*msm_check_for_modem_crash)(void); + +static int check_for_modem_crash(void) +{ + struct smsm_shared *smsm; + + smsm = smem_find(ID_SHARED_STATE, 2 * sizeof(struct smsm_shared)); + + /* if the modem's not ready yet, we have to hope for the best */ + if (!smsm) + return 0; + + if (smsm[1].state & SMSM_RESET) { + handle_modem_crash(); + return -1; + } else { + return 0; + } +} + +#define SMD_SS_CLOSED 0x00000000 +#define SMD_SS_OPENING 0x00000001 +#define SMD_SS_OPENED 0x00000002 +#define SMD_SS_FLUSHING 0x00000003 +#define SMD_SS_CLOSING 0x00000004 +#define SMD_SS_RESET 0x00000005 +#define SMD_SS_RESET_OPENING 0x00000006 + +#define SMD_BUF_SIZE 8192 +#define SMD_CHANNELS 64 + +#define SMD_HEADER_SIZE 20 + + +/* the spinlock is used to synchronize between the +** irq handler and code that mutates the channel +** list or fiddles with channel state +*/ +static DEFINE_SPINLOCK(smd_lock); +static DEFINE_SPINLOCK(smem_lock); + +/* the mutex is used during open() and close() +** operations to avoid races while creating or +** destroying smd_channel structures +*/ +static DEFINE_MUTEX(smd_creation_mutex); + +static int smd_initialized; + +struct smd_alloc_elm { + char name[20]; + uint32_t cid; + uint32_t ctype; + uint32_t ref_count; +}; + +struct smd_half_channel { + unsigned state; + unsigned char fDSR; + unsigned char fCTS; + unsigned char fCD; + unsigned char fRI; + unsigned char fHEAD; + unsigned char fTAIL; + unsigned char fSTATE; + unsigned char fUNUSED; + unsigned tail; + unsigned head; + unsigned char data[SMD_BUF_SIZE]; +}; + +struct smd_shared { + struct smd_half_channel ch0; + struct smd_half_channel ch1; +}; + +struct smd_channel { + volatile struct smd_half_channel *send; + volatile struct smd_half_channel *recv; + struct list_head ch_list; + + unsigned current_packet; + unsigned n; + void *priv; + void (*notify)(void *priv, unsigned flags); + + int (*read)(smd_channel_t *ch, void *data, int len); + int (*write)(smd_channel_t *ch, const void *data, int len); + int (*read_avail)(smd_channel_t *ch); + int (*write_avail)(smd_channel_t *ch); + + void (*update_state)(smd_channel_t *ch); + unsigned last_state; + + char name[32]; + struct platform_device pdev; +}; + +static LIST_HEAD(smd_ch_closed_list); +static LIST_HEAD(smd_ch_list); + +static unsigned char smd_ch_allocated[64]; +static struct work_struct probe_work; + +static void smd_alloc_channel(const char *name, uint32_t cid, uint32_t type); + +static void smd_channel_probe_worker(struct work_struct *work) +{ + struct smd_alloc_elm *shared; + unsigned n; + + shared = smem_find(ID_CH_ALLOC_TBL, sizeof(*shared) * 64); + + for (n = 0; n < 64; n++) { + if (smd_ch_allocated[n]) + continue; + if (!shared[n].ref_count) + continue; + if (!shared[n].name[0]) + continue; + smd_alloc_channel(shared[n].name, + shared[n].cid, + shared[n].ctype); + smd_ch_allocated[n] = 1; + } +} + +static char *chstate(unsigned n) +{ + switch (n) { + case SMD_SS_CLOSED: + return "CLOSED"; + case SMD_SS_OPENING: + return "OPENING"; + case SMD_SS_OPENED: + return "OPENED"; + case SMD_SS_FLUSHING: + return "FLUSHING"; + case SMD_SS_CLOSING: + return "CLOSING"; + case SMD_SS_RESET: + return "RESET"; + case SMD_SS_RESET_OPENING: + return "ROPENING"; + default: + return "UNKNOWN"; + } +} + +/* how many bytes are available for reading */ +static int smd_stream_read_avail(struct smd_channel *ch) +{ + return (ch->recv->head - ch->recv->tail) & (SMD_BUF_SIZE - 1); +} + +/* how many bytes we are free to write */ +static int smd_stream_write_avail(struct smd_channel *ch) +{ + return (SMD_BUF_SIZE - 1) - + ((ch->send->head - ch->send->tail) & (SMD_BUF_SIZE - 1)); +} + +static int smd_packet_read_avail(struct smd_channel *ch) +{ + if (ch->current_packet) { + int n = smd_stream_read_avail(ch); + if (n > ch->current_packet) + n = ch->current_packet; + return n; + } else { + return 0; + } +} + +static int smd_packet_write_avail(struct smd_channel *ch) +{ + int n = smd_stream_write_avail(ch); + return n > SMD_HEADER_SIZE ? n - SMD_HEADER_SIZE : 0; +} + +static int ch_is_open(struct smd_channel *ch) +{ + return (ch->recv->state == SMD_SS_OPENED) && + (ch->send->state == SMD_SS_OPENED); +} + +/* provide a pointer and length to readable data in the fifo */ +static unsigned ch_read_buffer(struct smd_channel *ch, void **ptr) +{ + unsigned head = ch->recv->head; + unsigned tail = ch->recv->tail; + *ptr = (void *) (ch->recv->data + tail); + + if (tail <= head) + return head - tail; + else + return SMD_BUF_SIZE - tail; +} + +/* advance the fifo read pointer after data from ch_read_buffer is consumed */ +static void ch_read_done(struct smd_channel *ch, unsigned count) +{ + BUG_ON(count > smd_stream_read_avail(ch)); + ch->recv->tail = (ch->recv->tail + count) & (SMD_BUF_SIZE - 1); + ch->recv->fTAIL = 1; +} + +/* basic read interface to ch_read_{buffer,done} used +** by smd_*_read() and update_packet_state() +** will read-and-discard if the _data pointer is null +*/ +static int ch_read(struct smd_channel *ch, void *_data, int len) +{ + void *ptr; + unsigned n; + unsigned char *data = _data; + int orig_len = len; + + while (len > 0) { + n = ch_read_buffer(ch, &ptr); + if (n == 0) + break; + + if (n > len) + n = len; + if (_data) + memcpy(data, ptr, n); + + data += n; + len -= n; + ch_read_done(ch, n); + } + + return orig_len - len; +} + +static void update_stream_state(struct smd_channel *ch) +{ + /* streams have no special state requiring updating */ +} + +static void update_packet_state(struct smd_channel *ch) +{ + unsigned hdr[5]; + int r; + + /* can't do anything if we're in the middle of a packet */ + if (ch->current_packet != 0) + return; + + /* don't bother unless we can get the full header */ + if (smd_stream_read_avail(ch) < SMD_HEADER_SIZE) + return; + + r = ch_read(ch, hdr, SMD_HEADER_SIZE); + BUG_ON(r != SMD_HEADER_SIZE); + + ch->current_packet = hdr[0]; +} + +/* provide a pointer and length to next free space in the fifo */ +static unsigned ch_write_buffer(struct smd_channel *ch, void **ptr) +{ + unsigned head = ch->send->head; + unsigned tail = ch->send->tail; + *ptr = (void *) (ch->send->data + head); + + if (head < tail) { + return tail - head - 1; + } else { + if (tail == 0) + return SMD_BUF_SIZE - head - 1; + else + return SMD_BUF_SIZE - head; + } +} + +/* advace the fifo write pointer after freespace + * from ch_write_buffer is filled + */ +static void ch_write_done(struct smd_channel *ch, unsigned count) +{ + BUG_ON(count > smd_stream_write_avail(ch)); + ch->send->head = (ch->send->head + count) & (SMD_BUF_SIZE - 1); + ch->send->fHEAD = 1; +} + +static void hc_set_state(volatile struct smd_half_channel *hc, unsigned n) +{ + if (n == SMD_SS_OPENED) { + hc->fDSR = 1; + hc->fCTS = 1; + hc->fCD = 1; + } else { + hc->fDSR = 0; + hc->fCTS = 0; + hc->fCD = 0; + } + hc->state = n; + hc->fSTATE = 1; + notify_other_smd(); +} + +static void do_smd_probe(void) +{ + struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE; + if (shared->heap_info.free_offset != last_heap_free) { + last_heap_free = shared->heap_info.free_offset; + schedule_work(&probe_work); + } +} + +static void smd_state_change(struct smd_channel *ch, + unsigned last, unsigned next) +{ + ch->last_state = next; + + pr_info("SMD: ch %d %s -> %s\n", ch->n, + chstate(last), chstate(next)); + + switch (next) { + case SMD_SS_OPENING: + ch->recv->tail = 0; + case SMD_SS_OPENED: + if (ch->send->state != SMD_SS_OPENED) + hc_set_state(ch->send, SMD_SS_OPENED); + ch->notify(ch->priv, SMD_EVENT_OPEN); + break; + case SMD_SS_FLUSHING: + case SMD_SS_RESET: + /* we should force them to close? */ + default: + ch->notify(ch->priv, SMD_EVENT_CLOSE); + } +} + +static irqreturn_t smd_irq_handler(int irq, void *data) +{ + unsigned long flags; + struct smd_channel *ch; + int do_notify = 0; + unsigned ch_flags; + unsigned tmp; + + spin_lock_irqsave(&smd_lock, flags); + list_for_each_entry(ch, &smd_ch_list, ch_list) { + ch_flags = 0; + if (ch_is_open(ch)) { + if (ch->recv->fHEAD) { + ch->recv->fHEAD = 0; + ch_flags |= 1; + do_notify |= 1; + } + if (ch->recv->fTAIL) { + ch->recv->fTAIL = 0; + ch_flags |= 2; + do_notify |= 1; + } + if (ch->recv->fSTATE) { + ch->recv->fSTATE = 0; + ch_flags |= 4; + do_notify |= 1; + } + } + tmp = ch->recv->state; + if (tmp != ch->last_state) + smd_state_change(ch, ch->last_state, tmp); + if (ch_flags) { + ch->update_state(ch); + ch->notify(ch->priv, SMD_EVENT_DATA); + } + } + if (do_notify) + notify_other_smd(); + spin_unlock_irqrestore(&smd_lock, flags); + do_smd_probe(); + return IRQ_HANDLED; +} + +static void smd_fake_irq_handler(unsigned long arg) +{ + smd_irq_handler(0, NULL); +} + +static DECLARE_TASKLET(smd_fake_irq_tasklet, smd_fake_irq_handler, 0); + +void smd_sleep_exit(void) +{ + unsigned long flags; + struct smd_channel *ch; + unsigned tmp; + int need_int = 0; + + spin_lock_irqsave(&smd_lock, flags); + list_for_each_entry(ch, &smd_ch_list, ch_list) { + if (ch_is_open(ch)) { + if (ch->recv->fHEAD) { + if (msm_smd_debug_mask & MSM_SMD_DEBUG) + pr_info("smd_sleep_exit ch %d fHEAD " + "%x %x %x\n", + ch->n, ch->recv->fHEAD, + ch->recv->head, ch->recv->tail); + need_int = 1; + break; + } + if (ch->recv->fTAIL) { + if (msm_smd_debug_mask & MSM_SMD_DEBUG) + pr_info("smd_sleep_exit ch %d fTAIL " + "%x %x %x\n", + ch->n, ch->recv->fTAIL, + ch->send->head, ch->send->tail); + need_int = 1; + break; + } + if (ch->recv->fSTATE) { + if (msm_smd_debug_mask & MSM_SMD_DEBUG) + pr_info("smd_sleep_exit ch %d fSTATE %x" + "\n", ch->n, ch->recv->fSTATE); + need_int = 1; + break; + } + tmp = ch->recv->state; + if (tmp != ch->last_state) { + if (msm_smd_debug_mask & MSM_SMD_DEBUG) + pr_info("smd_sleep_exit ch %d " + "state %x != %x\n", + ch->n, tmp, ch->last_state); + need_int = 1; + break; + } + } + } + spin_unlock_irqrestore(&smd_lock, flags); + do_smd_probe(); + if (need_int) { + if (msm_smd_debug_mask & MSM_SMD_DEBUG) + pr_info("smd_sleep_exit need interrupt\n"); + tasklet_schedule(&smd_fake_irq_tasklet); + } +} + + +void smd_kick(smd_channel_t *ch) +{ + unsigned long flags; + unsigned tmp; + + spin_lock_irqsave(&smd_lock, flags); + ch->update_state(ch); + tmp = ch->recv->state; + if (tmp != ch->last_state) { + ch->last_state = tmp; + if (tmp == SMD_SS_OPENED) + ch->notify(ch->priv, SMD_EVENT_OPEN); + else + ch->notify(ch->priv, SMD_EVENT_CLOSE); + } + ch->notify(ch->priv, SMD_EVENT_DATA); + notify_other_smd(); + spin_unlock_irqrestore(&smd_lock, flags); +} + +static int smd_is_packet(int chn) +{ + if ((chn > 4) || (chn == 1)) + return 1; + else + return 0; +} + +static int smd_stream_write(smd_channel_t *ch, const void *_data, int len) +{ + void *ptr; + const unsigned char *buf = _data; + unsigned xfer; + int orig_len = len; + + if (len < 0) + return -EINVAL; + + while ((xfer = ch_write_buffer(ch, &ptr)) != 0) { + if (!ch_is_open(ch)) + break; + if (xfer > len) + xfer = len; + memcpy(ptr, buf, xfer); + ch_write_done(ch, xfer); + len -= xfer; + buf += xfer; + if (len == 0) + break; + } + + notify_other_smd(); + + return orig_len - len; +} + +static int smd_packet_write(smd_channel_t *ch, const void *_data, int len) +{ + unsigned hdr[5]; + + if (len < 0) + return -EINVAL; + + if (smd_stream_write_avail(ch) < (len + SMD_HEADER_SIZE)) + return -ENOMEM; + + hdr[0] = len; + hdr[1] = hdr[2] = hdr[3] = hdr[4] = 0; + + smd_stream_write(ch, hdr, sizeof(hdr)); + smd_stream_write(ch, _data, len); + + return len; +} + +static int smd_stream_read(smd_channel_t *ch, void *data, int len) +{ + int r; + + if (len < 0) + return -EINVAL; + + r = ch_read(ch, data, len); + if (r > 0) + notify_other_smd(); + + return r; +} + +static int smd_packet_read(smd_channel_t *ch, void *data, int len) +{ + unsigned long flags; + int r; + + if (len < 0) + return -EINVAL; + + if (len > ch->current_packet) + len = ch->current_packet; + + r = ch_read(ch, data, len); + if (r > 0) + notify_other_smd(); + + spin_lock_irqsave(&smd_lock, flags); + ch->current_packet -= r; + update_packet_state(ch); + spin_unlock_irqrestore(&smd_lock, flags); + + return r; +} + +static void smd_alloc_channel(const char *name, uint32_t cid, uint32_t type) +{ + struct smd_channel *ch; + struct smd_shared *shared; + + shared = smem_alloc(ID_SMD_CHANNELS + cid, sizeof(*shared)); + if (!shared) { + pr_err("smd_alloc_channel() cid %d does not exist\n", cid); + return; + } + + ch = kzalloc(sizeof(struct smd_channel), GFP_KERNEL); + if (ch == 0) { + pr_err("smd_alloc_channel() out of memory\n"); + return; + } + + ch->send = &shared->ch0; + ch->recv = &shared->ch1; + ch->n = cid; + + if (smd_is_packet(cid)) { + ch->read = smd_packet_read; + ch->write = smd_packet_write; + ch->read_avail = smd_packet_read_avail; + ch->write_avail = smd_packet_write_avail; + ch->update_state = update_packet_state; + } else { + ch->read = smd_stream_read; + ch->write = smd_stream_write; + ch->read_avail = smd_stream_read_avail; + ch->write_avail = smd_stream_write_avail; + ch->update_state = update_stream_state; + } + + memcpy(ch->name, "SMD_", 4); + memcpy(ch->name + 4, name, 20); + ch->name[23] = 0; + ch->pdev.name = ch->name; + ch->pdev.id = -1; + + pr_info("smd_alloc_channel() '%s' cid=%d, shared=%p\n", + ch->name, ch->n, shared); + + mutex_lock(&smd_creation_mutex); + list_add(&ch->ch_list, &smd_ch_closed_list); + mutex_unlock(&smd_creation_mutex); + + platform_device_register(&ch->pdev); +} + +static void do_nothing_notify(void *priv, unsigned flags) +{ +} + +struct smd_channel *smd_get_channel(const char *name) +{ + struct smd_channel *ch; + + mutex_lock(&smd_creation_mutex); + list_for_each_entry(ch, &smd_ch_closed_list, ch_list) { + if (!strcmp(name, ch->name)) { + list_del(&ch->ch_list); + mutex_unlock(&smd_creation_mutex); + return ch; + } + } + mutex_unlock(&smd_creation_mutex); + + return NULL; +} + +int smd_open(const char *name, smd_channel_t **_ch, + void *priv, void (*notify)(void *, unsigned)) +{ + struct smd_channel *ch; + unsigned long flags; + + if (smd_initialized == 0) { + pr_info("smd_open() before smd_init()\n"); + return -ENODEV; + } + + ch = smd_get_channel(name); + if (!ch) + return -ENODEV; + + if (notify == 0) + notify = do_nothing_notify; + + ch->notify = notify; + ch->current_packet = 0; + ch->last_state = SMD_SS_CLOSED; + ch->priv = priv; + + *_ch = ch; + + spin_lock_irqsave(&smd_lock, flags); + list_add(&ch->ch_list, &smd_ch_list); + + /* If the remote side is CLOSING, we need to get it to + * move to OPENING (which we'll do by moving from CLOSED to + * OPENING) and then get it to move from OPENING to + * OPENED (by doing the same state change ourselves). + * + * Otherwise, it should be OPENING and we can move directly + * to OPENED so that it will follow. + */ + if (ch->recv->state == SMD_SS_CLOSING) { + ch->send->head = 0; + hc_set_state(ch->send, SMD_SS_OPENING); + } else { + hc_set_state(ch->send, SMD_SS_OPENED); + } + spin_unlock_irqrestore(&smd_lock, flags); + smd_kick(ch); + + return 0; +} + +int smd_close(smd_channel_t *ch) +{ + unsigned long flags; + + pr_info("smd_close(%p)\n", ch); + + if (ch == 0) + return -1; + + spin_lock_irqsave(&smd_lock, flags); + ch->notify = do_nothing_notify; + list_del(&ch->ch_list); + hc_set_state(ch->send, SMD_SS_CLOSED); + spin_unlock_irqrestore(&smd_lock, flags); + + mutex_lock(&smd_creation_mutex); + list_add(&ch->ch_list, &smd_ch_closed_list); + mutex_unlock(&smd_creation_mutex); + + return 0; +} + +int smd_read(smd_channel_t *ch, void *data, int len) +{ + return ch->read(ch, data, len); +} + +int smd_write(smd_channel_t *ch, const void *data, int len) +{ + return ch->write(ch, data, len); +} + +int smd_read_avail(smd_channel_t *ch) +{ + return ch->read_avail(ch); +} + +int smd_write_avail(smd_channel_t *ch) +{ + return ch->write_avail(ch); +} + +int smd_wait_until_readable(smd_channel_t *ch, int bytes) +{ + return -1; +} + +int smd_wait_until_writable(smd_channel_t *ch, int bytes) +{ + return -1; +} + +int smd_cur_packet_size(smd_channel_t *ch) +{ + return ch->current_packet; +} + + +/* ------------------------------------------------------------------------- */ + +void *smem_alloc(unsigned id, unsigned size) +{ + return smem_find(id, size); +} + +static void *_smem_find(unsigned id, unsigned *size) +{ + struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE; + struct smem_heap_entry *toc = shared->heap_toc; + + if (id >= SMEM_NUM_ITEMS) + return 0; + + if (toc[id].allocated) { + *size = toc[id].size; + return (void *) (MSM_SHARED_RAM_BASE + toc[id].offset); + } + + return 0; +} + +void *smem_find(unsigned id, unsigned size_in) +{ + unsigned size; + void *ptr; + + ptr = _smem_find(id, &size); + if (!ptr) + return 0; + + size_in = ALIGN(size_in, 8); + if (size_in != size) { + pr_err("smem_find(%d, %d): wrong size %d\n", + id, size_in, size); + return 0; + } + + return ptr; +} + +static irqreturn_t smsm_irq_handler(int irq, void *data) +{ + unsigned long flags; + struct smsm_shared *smsm; + + spin_lock_irqsave(&smem_lock, flags); + smsm = smem_alloc(ID_SHARED_STATE, + 2 * sizeof(struct smsm_shared)); + + if (smsm == 0) { + pr_info("\n"); + } else { + unsigned apps = smsm[0].state; + unsigned modm = smsm[1].state; + + if (msm_smd_debug_mask & MSM_SMSM_DEBUG) + pr_info("\n", apps, modm); + if (modm & SMSM_RESET) { + handle_modem_crash(); + } else { + apps |= SMSM_INIT; + if (modm & SMSM_SMDINIT) + apps |= SMSM_SMDINIT; + if (modm & SMSM_RPCINIT) + apps |= SMSM_RPCINIT; + } + + if (smsm[0].state != apps) { + if (msm_smd_debug_mask & MSM_SMSM_DEBUG) + pr_info("\n", apps); + smsm[0].state = apps; + do_smd_probe(); + notify_other_smsm(); + } + } + spin_unlock_irqrestore(&smem_lock, flags); + return IRQ_HANDLED; +} + +int smsm_change_state(uint32_t clear_mask, uint32_t set_mask) +{ + unsigned long flags; + struct smsm_shared *smsm; + + spin_lock_irqsave(&smem_lock, flags); + + smsm = smem_alloc(ID_SHARED_STATE, + 2 * sizeof(struct smsm_shared)); + + if (smsm) { + if (smsm[1].state & SMSM_RESET) + handle_modem_crash(); + smsm[0].state = (smsm[0].state & ~clear_mask) | set_mask; + if (msm_smd_debug_mask & MSM_SMSM_DEBUG) + pr_info("smsm_change_state %x\n", + smsm[0].state); + notify_other_smsm(); + } + + spin_unlock_irqrestore(&smem_lock, flags); + + if (smsm == NULL) { + pr_err("smsm_change_state \n"); + return -EIO; + } + return 0; +} + +uint32_t smsm_get_state(void) +{ + unsigned long flags; + struct smsm_shared *smsm; + uint32_t rv; + + spin_lock_irqsave(&smem_lock, flags); + + smsm = smem_alloc(ID_SHARED_STATE, + 2 * sizeof(struct smsm_shared)); + + if (smsm) + rv = smsm[1].state; + else + rv = 0; + + if (rv & SMSM_RESET) + handle_modem_crash(); + + spin_unlock_irqrestore(&smem_lock, flags); + + if (smsm == NULL) + pr_err("smsm_get_state \n"); + return rv; +} + +int smsm_set_sleep_duration(uint32_t delay) +{ + uint32_t *ptr; + + ptr = smem_alloc(SMEM_SMSM_SLEEP_DELAY, sizeof(*ptr)); + if (ptr == NULL) { + pr_err("smsm_set_sleep_duration \n"); + return -EIO; + } + if (msm_smd_debug_mask & MSM_SMSM_DEBUG) + pr_info("smsm_set_sleep_duration %d -> %d\n", + *ptr, delay); + *ptr = delay; + return 0; +} + +int smsm_set_interrupt_info(struct smsm_interrupt_info *info) +{ + struct smsm_interrupt_info *ptr; + + ptr = smem_alloc(SMEM_SMSM_INT_INFO, sizeof(*ptr)); + if (ptr == NULL) { + pr_err("smsm_set_sleep_duration \n"); + return -EIO; + } + if (msm_smd_debug_mask & MSM_SMSM_DEBUG) + pr_info("smsm_set_interrupt_info %x %x -> %x %x\n", + ptr->aArm_en_mask, ptr->aArm_interrupts_pending, + info->aArm_en_mask, info->aArm_interrupts_pending); + *ptr = *info; + return 0; +} + +#define MAX_NUM_SLEEP_CLIENTS 64 +#define MAX_SLEEP_NAME_LEN 8 + +#define NUM_GPIO_INT_REGISTERS 6 +#define GPIO_SMEM_NUM_GROUPS 2 +#define GPIO_SMEM_MAX_PC_INTERRUPTS 8 + +struct tramp_gpio_save { + unsigned int enable; + unsigned int detect; + unsigned int polarity; +}; + +struct tramp_gpio_smem { + uint16_t num_fired[GPIO_SMEM_NUM_GROUPS]; + uint16_t fired[GPIO_SMEM_NUM_GROUPS][GPIO_SMEM_MAX_PC_INTERRUPTS]; + uint32_t enabled[NUM_GPIO_INT_REGISTERS]; + uint32_t detection[NUM_GPIO_INT_REGISTERS]; + uint32_t polarity[NUM_GPIO_INT_REGISTERS]; +}; + + +void smsm_print_sleep_info(void) +{ + unsigned long flags; + uint32_t *ptr; + struct tramp_gpio_smem *gpio; + struct smsm_interrupt_info *int_info; + + + spin_lock_irqsave(&smem_lock, flags); + + ptr = smem_alloc(SMEM_SMSM_SLEEP_DELAY, sizeof(*ptr)); + if (ptr) + pr_info("SMEM_SMSM_SLEEP_DELAY: %x\n", *ptr); + + ptr = smem_alloc(SMEM_SMSM_LIMIT_SLEEP, sizeof(*ptr)); + if (ptr) + pr_info("SMEM_SMSM_LIMIT_SLEEP: %x\n", *ptr); + + ptr = smem_alloc(SMEM_SLEEP_POWER_COLLAPSE_DISABLED, sizeof(*ptr)); + if (ptr) + pr_info("SMEM_SLEEP_POWER_COLLAPSE_DISABLED: %x\n", *ptr); + + int_info = smem_alloc(SMEM_SMSM_INT_INFO, sizeof(*int_info)); + if (int_info) + pr_info("SMEM_SMSM_INT_INFO %x %x %x\n", + int_info->aArm_en_mask, + int_info->aArm_interrupts_pending, + int_info->aArm_wakeup_reason); + + gpio = smem_alloc(SMEM_GPIO_INT, sizeof(*gpio)); + if (gpio) { + int i; + for (i = 0; i < NUM_GPIO_INT_REGISTERS; i++) + pr_info("SMEM_GPIO_INT: %d: e %x d %x p %x\n", + i, gpio->enabled[i], gpio->detection[i], + gpio->polarity[i]); + + for (i = 0; i < GPIO_SMEM_NUM_GROUPS; i++) + pr_info("SMEM_GPIO_INT: %d: f %d: %d %d...\n", + i, gpio->num_fired[i], gpio->fired[i][0], + gpio->fired[i][1]); + } + + spin_unlock_irqrestore(&smem_lock, flags); +} + +int smd_core_init(void) +{ + int r; + pr_info("smd_core_init()\n"); + + r = request_irq(INT_A9_M2A_0, smd_irq_handler, + IRQF_TRIGGER_RISING, "smd_dev", 0); + if (r < 0) + return r; + r = enable_irq_wake(INT_A9_M2A_0); + if (r < 0) + pr_err("smd_core_init: enable_irq_wake failed for A9_M2A_0\n"); + + r = request_irq(INT_A9_M2A_5, smsm_irq_handler, + IRQF_TRIGGER_RISING, "smsm_dev", 0); + if (r < 0) { + free_irq(INT_A9_M2A_0, 0); + return r; + } + r = enable_irq_wake(INT_A9_M2A_5); + if (r < 0) + pr_err("smd_core_init: enable_irq_wake failed for A9_M2A_5\n"); + + /* we may have missed a signal while booting -- fake + * an interrupt to make sure we process any existing + * state + */ + smsm_irq_handler(0, 0); + + pr_info("smd_core_init() done\n"); + + return 0; +} + +#if defined(CONFIG_DEBUG_FS) + +static int dump_ch(char *buf, int max, int n, + struct smd_half_channel *s, + struct smd_half_channel *r) +{ + return scnprintf( + buf, max, + "ch%02d:" + " %8s(%04d/%04d) %c%c%c%c%c%c%c <->" + " %8s(%04d/%04d) %c%c%c%c%c%c%c\n", n, + chstate(s->state), s->tail, s->head, + s->fDSR ? 'D' : 'd', + s->fCTS ? 'C' : 'c', + s->fCD ? 'C' : 'c', + s->fRI ? 'I' : 'i', + s->fHEAD ? 'W' : 'w', + s->fTAIL ? 'R' : 'r', + s->fSTATE ? 'S' : 's', + chstate(r->state), r->tail, r->head, + r->fDSR ? 'D' : 'd', + r->fCTS ? 'R' : 'r', + r->fCD ? 'C' : 'c', + r->fRI ? 'I' : 'i', + r->fHEAD ? 'W' : 'w', + r->fTAIL ? 'R' : 'r', + r->fSTATE ? 'S' : 's' + ); +} + +static int debug_read_stat(char *buf, int max) +{ + struct smsm_shared *smsm; + char *msg; + int i = 0; + + smsm = smem_find(ID_SHARED_STATE, + 2 * sizeof(struct smsm_shared)); + + msg = smem_find(ID_DIAG_ERR_MSG, SZ_DIAG_ERR_MSG); + + if (smsm) { + if (smsm[1].state & SMSM_RESET) + i += scnprintf(buf + i, max - i, + "smsm: ARM9 HAS CRASHED\n"); + i += scnprintf(buf + i, max - i, "smsm: a9: %08x a11: %08x\n", + smsm[0].state, smsm[1].state); + } else { + i += scnprintf(buf + i, max - i, "smsm: cannot find\n"); + } + if (msg) { + msg[SZ_DIAG_ERR_MSG - 1] = 0; + i += scnprintf(buf + i, max - i, "diag: '%s'\n", msg); + } + return i; +} + +static int debug_read_mem(char *buf, int max) +{ + unsigned n; + struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE; + struct smem_heap_entry *toc = shared->heap_toc; + int i = 0; + + i += scnprintf(buf + i, max - i, + "heap: init=%d free=%d remain=%d\n", + shared->heap_info.initialized, + shared->heap_info.free_offset, + shared->heap_info.heap_remaining); + + for (n = 0; n < SMEM_NUM_ITEMS; n++) { + if (toc[n].allocated == 0) + continue; + i += scnprintf(buf + i, max - i, + "%04d: offsed %08x size %08x\n", + n, toc[n].offset, toc[n].size); + } + return i; +} + +static int debug_read_ch(char *buf, int max) +{ + struct smd_shared *shared; + int n, i = 0; + + for (n = 0; n < SMD_CHANNELS; n++) { + shared = smem_find(ID_SMD_CHANNELS + n, + sizeof(struct smd_shared)); + if (shared == 0) + continue; + i += dump_ch(buf + i, max - i, n, &shared->ch0, &shared->ch1); + } + + return i; +} + +static int debug_read_version(char *buf, int max) +{ + struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE; + unsigned version = shared->version[VERSION_MODEM]; + return sprintf(buf, "%d.%d\n", version >> 16, version & 0xffff); +} + +static int debug_read_build_id(char *buf, int max) +{ + unsigned size; + void *data; + + data = _smem_find(SMEM_HW_SW_BUILD_ID, &size); + if (!data) + return 0; + + if (size >= max) + size = max; + memcpy(buf, data, size); + + return size; +} + +static int debug_read_alloc_tbl(char *buf, int max) +{ + struct smd_alloc_elm *shared; + int n, i = 0; + + shared = smem_find(ID_CH_ALLOC_TBL, sizeof(*shared) * 64); + + for (n = 0; n < 64; n++) { + if (shared[n].ref_count == 0) + continue; + i += scnprintf(buf + i, max - i, + "%03d: %20s cid=%02d ctype=%d ref_count=%d\n", + n, shared[n].name, shared[n].cid, + shared[n].ctype, shared[n].ref_count); + } + + return i; +} + +static int debug_boom(char *buf, int max) +{ + unsigned ms = 5000; + msm_proc_comm(PCOM_RESET_MODEM, &ms, 0); + return 0; +} + +#define DEBUG_BUFMAX 4096 +static char debug_buffer[DEBUG_BUFMAX]; + +static ssize_t debug_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + int (*fill)(char *buf, int max) = file->private_data; + int bsize = fill(debug_buffer, DEBUG_BUFMAX); + return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize); +} + +static int debug_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static const struct file_operations debug_ops = { + .read = debug_read, + .open = debug_open, +}; + +static void debug_create(const char *name, mode_t mode, + struct dentry *dent, + int (*fill)(char *buf, int max)) +{ + debugfs_create_file(name, mode, dent, fill, &debug_ops); +} + +static void smd_debugfs_init(void) +{ + struct dentry *dent; + + dent = debugfs_create_dir("smd", 0); + if (IS_ERR(dent)) + return; + + debug_create("ch", 0444, dent, debug_read_ch); + debug_create("stat", 0444, dent, debug_read_stat); + debug_create("mem", 0444, dent, debug_read_mem); + debug_create("version", 0444, dent, debug_read_version); + debug_create("tbl", 0444, dent, debug_read_alloc_tbl); + debug_create("build", 0444, dent, debug_read_build_id); + debug_create("boom", 0444, dent, debug_boom); +} +#else +static void smd_debugfs_init(void) {} +#endif + +static int __init msm_smd_probe(struct platform_device *pdev) +{ + pr_info("smd_init()\n"); + + INIT_WORK(&probe_work, smd_channel_probe_worker); + + if (smd_core_init()) { + pr_err("smd_core_init() failed\n"); + return -1; + } + + do_smd_probe(); + + msm_check_for_modem_crash = check_for_modem_crash; + + smd_debugfs_init(); + smd_initialized = 1; + + return 0; +} + +static struct platform_driver msm_smd_driver = { + .probe = msm_smd_probe, + .driver = { + .name = MODULE_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init msm_smd_init(void) +{ + return platform_driver_register(&msm_smd_driver); +} + +module_init(msm_smd_init); + +MODULE_DESCRIPTION("MSM Shared Memory Core"); +MODULE_AUTHOR("Brian Swetland "); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-msm/smd_private.h b/arch/arm/mach-msm/smd_private.h new file mode 100644 index 000000000000..c0eb3de1be54 --- /dev/null +++ b/arch/arm/mach-msm/smd_private.h @@ -0,0 +1,171 @@ +/* arch/arm/mach-msm/smd_private.h + * + * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2007 QUALCOMM Incorporated + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ +#ifndef _ARCH_ARM_MACH_MSM_MSM_SMD_PRIVATE_H_ +#define _ARCH_ARM_MACH_MSM_MSM_SMD_PRIVATE_H_ + +struct smem_heap_info +{ + unsigned initialized; + unsigned free_offset; + unsigned heap_remaining; + unsigned reserved; +}; + +struct smem_heap_entry +{ + unsigned allocated; + unsigned offset; + unsigned size; + unsigned reserved; +}; + +struct smem_proc_comm +{ + unsigned command; + unsigned status; + unsigned data1; + unsigned data2; +}; + +#define PC_APPS 0 +#define PC_MODEM 1 + +#define VERSION_QDSP6 4 +#define VERSION_APPS_SBL 6 +#define VERSION_MODEM_SBL 7 +#define VERSION_APPS 8 +#define VERSION_MODEM 9 + +struct smem_shared +{ + struct smem_proc_comm proc_comm[4]; + unsigned version[32]; + struct smem_heap_info heap_info; + struct smem_heap_entry heap_toc[128]; +}; + +struct smsm_shared +{ + unsigned host; + unsigned state; +}; + +struct smsm_interrupt_info +{ + uint32_t aArm_en_mask; + uint32_t aArm_interrupts_pending; + uint32_t aArm_wakeup_reason; +}; + +#define SZ_DIAG_ERR_MSG 0xC8 +#define ID_DIAG_ERR_MSG SMEM_DIAG_ERR_MESSAGE +#define ID_SMD_CHANNELS SMEM_SMD_BASE_ID +#define ID_SHARED_STATE SMEM_SMSM_SHARED_STATE +#define ID_CH_ALLOC_TBL SMEM_CHANNEL_ALLOC_TBL + +#define SMSM_INIT 0x000001 +#define SMSM_SMDINIT 0x000008 +#define SMSM_RPCINIT 0x000020 +#define SMSM_RESET 0x000040 +#define SMSM_RSA 0x0080 +#define SMSM_RUN 0x000100 +#define SMSM_PWRC 0x0200 +#define SMSM_TIMEWAIT 0x0400 +#define SMSM_TIMEINIT 0x0800 +#define SMSM_PWRC_EARLY_EXIT 0x1000 +#define SMSM_WFPI 0x2000 +#define SMSM_SLEEP 0x4000 +#define SMSM_SLEEPEXIT 0x8000 +#define SMSM_OEMSBL_RELEASE 0x10000 +#define SMSM_PWRC_SUSPEND 0x200000 + +#define SMSM_WKUP_REASON_RPC 0x00000001 +#define SMSM_WKUP_REASON_INT 0x00000002 +#define SMSM_WKUP_REASON_GPIO 0x00000004 +#define SMSM_WKUP_REASON_TIMER 0x00000008 +#define SMSM_WKUP_REASON_ALARM 0x00000010 +#define SMSM_WKUP_REASON_RESET 0x00000020 + +void *smem_alloc(unsigned id, unsigned size); +int smsm_change_state(uint32_t clear_mask, uint32_t set_mask); +uint32_t smsm_get_state(void); +int smsm_set_sleep_duration(uint32_t delay); +int smsm_set_interrupt_info(struct smsm_interrupt_info *info); +void smsm_print_sleep_info(void); + +#define SMEM_NUM_SMD_CHANNELS 64 + +typedef enum +{ + /* fixed items */ + SMEM_PROC_COMM = 0, + SMEM_HEAP_INFO, + SMEM_ALLOCATION_TABLE, + SMEM_VERSION_INFO, + SMEM_HW_RESET_DETECT, + SMEM_AARM_WARM_BOOT, + SMEM_DIAG_ERR_MESSAGE, + SMEM_SPINLOCK_ARRAY, + SMEM_MEMORY_BARRIER_LOCATION, + + /* dynamic items */ + SMEM_AARM_PARTITION_TABLE, + SMEM_AARM_BAD_BLOCK_TABLE, + SMEM_RESERVE_BAD_BLOCKS, + SMEM_WM_UUID, + SMEM_CHANNEL_ALLOC_TBL, + SMEM_SMD_BASE_ID, + SMEM_SMEM_LOG_IDX = SMEM_SMD_BASE_ID + SMEM_NUM_SMD_CHANNELS, + SMEM_SMEM_LOG_EVENTS, + SMEM_SMEM_STATIC_LOG_IDX, + SMEM_SMEM_STATIC_LOG_EVENTS, + SMEM_SMEM_SLOW_CLOCK_SYNC, + SMEM_SMEM_SLOW_CLOCK_VALUE, + SMEM_BIO_LED_BUF, + SMEM_SMSM_SHARED_STATE, + SMEM_SMSM_INT_INFO, + SMEM_SMSM_SLEEP_DELAY, + SMEM_SMSM_LIMIT_SLEEP, + SMEM_SLEEP_POWER_COLLAPSE_DISABLED, + SMEM_KEYPAD_KEYS_PRESSED, + SMEM_KEYPAD_STATE_UPDATED, + SMEM_KEYPAD_STATE_IDX, + SMEM_GPIO_INT, + SMEM_MDDI_LCD_IDX, + SMEM_MDDI_HOST_DRIVER_STATE, + SMEM_MDDI_LCD_DISP_STATE, + SMEM_LCD_CUR_PANEL, + SMEM_MARM_BOOT_SEGMENT_INFO, + SMEM_AARM_BOOT_SEGMENT_INFO, + SMEM_SLEEP_STATIC, + SMEM_SCORPION_FREQUENCY, + SMEM_SMD_PROFILES, + SMEM_TSSC_BUSY, + SMEM_HS_SUSPEND_FILTER_INFO, + SMEM_BATT_INFO, + SMEM_APPS_BOOT_MODE, + SMEM_VERSION_FIRST, + SMEM_VERSION_LAST = SMEM_VERSION_FIRST + 24, + SMEM_OSS_RRCASN1_BUF1, + SMEM_OSS_RRCASN1_BUF2, + SMEM_ID_VENDOR0, + SMEM_ID_VENDOR1, + SMEM_ID_VENDOR2, + SMEM_HW_SW_BUILD_ID, + SMEM_NUM_ITEMS, +} smem_mem_type; + +#endif -- cgit v1.2.3 From 739a1cc0af180a48051d0b4d0f1865988ddf4749 Mon Sep 17 00:00:00 2001 From: Brian Swetland Date: Sat, 1 Dec 2007 19:10:02 -0800 Subject: [ARM] msm: shared memory tty interface Provides a simple tty interface to the shared memory "virtual serial" streams. Signed-off-by: Brian Swetland --- arch/arm/mach-msm/Makefile | 2 +- arch/arm/mach-msm/smd_tty.c | 208 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 209 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-msm/smd_tty.c (limited to 'arch') diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index dbaf8fc55340..b3fc8c4718ef 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -5,7 +5,7 @@ obj-y += vreg.o obj-y += clock.o clock-7x01a.o obj-y += gpio.o generic_gpio.o -obj-$(CONFIG_MSM_SMD) += smd.o +obj-$(CONFIG_MSM_SMD) += smd.o smd_tty.o obj-$(CONFIG_MACH_TROUT) += board-dream.o obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o diff --git a/arch/arm/mach-msm/smd_tty.c b/arch/arm/mach-msm/smd_tty.c new file mode 100644 index 000000000000..f40944958d44 --- /dev/null +++ b/arch/arm/mach-msm/smd_tty.c @@ -0,0 +1,208 @@ +/* arch/arm/mach-msm/smd_tty.c + * + * Copyright (C) 2007 Google, Inc. + * Author: Brian Swetland + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 + +#define MAX_SMD_TTYS 32 + +static DEFINE_MUTEX(smd_tty_lock); + +struct smd_tty_info { + smd_channel_t *ch; + struct tty_struct *tty; + int open_count; +}; + +static struct smd_tty_info smd_tty[MAX_SMD_TTYS]; + + +static void smd_tty_notify(void *priv, unsigned event) +{ + unsigned char *ptr; + int avail; + struct smd_tty_info *info = priv; + struct tty_struct *tty = info->tty; + + if (!tty) + return; + + if (event != SMD_EVENT_DATA) + return; + + for (;;) { + if (test_bit(TTY_THROTTLED, &tty->flags)) break; + avail = smd_read_avail(info->ch); + if (avail == 0) break; + + avail = tty_prepare_flip_string(tty, &ptr, avail); + + if (smd_read(info->ch, ptr, avail) != avail) { + /* shouldn't be possible since we're in interrupt + ** context here and nobody else could 'steal' our + ** characters. + */ + printk(KERN_ERR "OOPS - smd_tty_buffer mismatch?!"); + } + + tty_flip_buffer_push(tty); + } + + /* XXX only when writable and necessary */ + tty_wakeup(tty); +} + +static int smd_tty_open(struct tty_struct *tty, struct file *f) +{ + int res = 0; + int n = tty->index; + struct smd_tty_info *info; + const char *name; + + if (n == 0) { + name = "SMD_DS"; + } else if (n == 27) { + name = "SMD_GPSNMEA"; + } else { + return -ENODEV; + } + + info = smd_tty + n; + + mutex_lock(&smd_tty_lock); + tty->driver_data = info; + + if (info->open_count++ == 0) { + info->tty = tty; + if (info->ch) { + smd_kick(info->ch); + } else { + res = smd_open(name, &info->ch, info, smd_tty_notify); + } + } + mutex_unlock(&smd_tty_lock); + + return res; +} + +static void smd_tty_close(struct tty_struct *tty, struct file *f) +{ + struct smd_tty_info *info = tty->driver_data; + + if (info == 0) + return; + + mutex_lock(&smd_tty_lock); + if (--info->open_count == 0) { + info->tty = 0; + tty->driver_data = 0; + if (info->ch) { + smd_close(info->ch); + info->ch = 0; + } + } + mutex_unlock(&smd_tty_lock); +} + +static int smd_tty_write(struct tty_struct *tty, const unsigned char *buf, int len) +{ + struct smd_tty_info *info = tty->driver_data; + int avail; + + /* if we're writing to a packet channel we will + ** never be able to write more data than there + ** is currently space for + */ + avail = smd_write_avail(info->ch); + if (len > avail) + len = avail; + + return smd_write(info->ch, buf, len); +} + +static int smd_tty_write_room(struct tty_struct *tty) +{ + struct smd_tty_info *info = tty->driver_data; + return smd_write_avail(info->ch); +} + +static int smd_tty_chars_in_buffer(struct tty_struct *tty) +{ + struct smd_tty_info *info = tty->driver_data; + return smd_read_avail(info->ch); +} + +static void smd_tty_unthrottle(struct tty_struct *tty) +{ + struct smd_tty_info *info = tty->driver_data; + smd_kick(info->ch); +} + +static struct tty_operations smd_tty_ops = { + .open = smd_tty_open, + .close = smd_tty_close, + .write = smd_tty_write, + .write_room = smd_tty_write_room, + .chars_in_buffer = smd_tty_chars_in_buffer, + .unthrottle = smd_tty_unthrottle, +}; + +static struct tty_driver *smd_tty_driver; + +static int __init smd_tty_init(void) +{ + int ret; + + smd_tty_driver = alloc_tty_driver(MAX_SMD_TTYS); + if (smd_tty_driver == 0) + return -ENOMEM; + + smd_tty_driver->owner = THIS_MODULE; + smd_tty_driver->driver_name = "smd_tty_driver"; + smd_tty_driver->name = "smd"; + smd_tty_driver->major = 0; + smd_tty_driver->minor_start = 0; + smd_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; + smd_tty_driver->subtype = SERIAL_TYPE_NORMAL; + smd_tty_driver->init_termios = tty_std_termios; + smd_tty_driver->init_termios.c_iflag = 0; + smd_tty_driver->init_termios.c_oflag = 0; + smd_tty_driver->init_termios.c_cflag = B38400 | CS8 | CREAD; + smd_tty_driver->init_termios.c_lflag = 0; + smd_tty_driver->flags = TTY_DRIVER_RESET_TERMIOS | + TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; + tty_set_operations(smd_tty_driver, &smd_tty_ops); + + ret = tty_register_driver(smd_tty_driver); + if (ret) return ret; + + /* this should be dynamic */ + tty_register_device(smd_tty_driver, 0, 0); + tty_register_device(smd_tty_driver, 27, 0); + + return 0; +} + +module_init(smd_tty_init); -- cgit v1.2.3 From 3aba32da4ebfb218acbecb34913e8e84f43767d8 Mon Sep 17 00:00:00 2001 From: Brian Swetland Date: Sat, 1 Dec 2007 19:11:31 -0800 Subject: [ARM] msm: shared memory qmi interface The QMI control stream is used to configure the virtual ethernet network interface to the baseband processor / cellular network. Publish qmi0, qmi1, and qmi2 (which control the rmnet0, rmnet1, and rmnet2 interfaces). Signed-off-by: Brian Swetland --- arch/arm/mach-msm/Makefile | 2 +- arch/arm/mach-msm/smd_qmi.c | 843 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 844 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-msm/smd_qmi.c (limited to 'arch') diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index b3fc8c4718ef..238329d63b2a 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -5,7 +5,7 @@ obj-y += vreg.o obj-y += clock.o clock-7x01a.o obj-y += gpio.o generic_gpio.o -obj-$(CONFIG_MSM_SMD) += smd.o smd_tty.o +obj-$(CONFIG_MSM_SMD) += smd.o smd_tty.o smd_qmi.o obj-$(CONFIG_MACH_TROUT) += board-dream.o obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o diff --git a/arch/arm/mach-msm/smd_qmi.c b/arch/arm/mach-msm/smd_qmi.c new file mode 100644 index 000000000000..066d535809c1 --- /dev/null +++ b/arch/arm/mach-msm/smd_qmi.c @@ -0,0 +1,843 @@ +/* arch/arm/mach-msm/smd_qmi.c + * + * QMI Control Driver -- Manages network data connections. + * + * Copyright (C) 2007 Google, Inc. + * Author: Brian Swetland + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 + +#define QMI_CTL 0x00 +#define QMI_WDS 0x01 +#define QMI_DMS 0x02 +#define QMI_NAS 0x03 + +#define QMI_RESULT_SUCCESS 0x0000 +#define QMI_RESULT_FAILURE 0x0001 + +struct qmi_msg { + unsigned char service; + unsigned char client_id; + unsigned short txn_id; + unsigned short type; + unsigned short size; + unsigned char *tlv; +}; + +#define qmi_ctl_client_id 0 + +#define STATE_OFFLINE 0 +#define STATE_QUERYING 1 +#define STATE_ONLINE 2 + +struct qmi_ctxt { + struct miscdevice misc; + + struct mutex lock; + + unsigned char ctl_txn_id; + unsigned char wds_client_id; + unsigned short wds_txn_id; + + unsigned wds_busy; + unsigned wds_handle; + unsigned state_dirty; + unsigned state; + + unsigned char addr[4]; + unsigned char mask[4]; + unsigned char gateway[4]; + unsigned char dns1[4]; + unsigned char dns2[4]; + + smd_channel_t *ch; + const char *ch_name; + + struct work_struct open_work; + struct work_struct read_work; +}; + +static struct qmi_ctxt *qmi_minor_to_ctxt(unsigned n); + +static void qmi_read_work(struct work_struct *ws); +static void qmi_open_work(struct work_struct *work); + +void qmi_ctxt_init(struct qmi_ctxt *ctxt, unsigned n) +{ + mutex_init(&ctxt->lock); + INIT_WORK(&ctxt->read_work, qmi_read_work); + INIT_WORK(&ctxt->open_work, qmi_open_work); + ctxt->ctl_txn_id = 1; + ctxt->wds_txn_id = 1; + ctxt->wds_busy = 1; + ctxt->state = STATE_OFFLINE; + +} + +static struct workqueue_struct *qmi_wq; + +static int verbose = 0; + +/* anyone waiting for a state change waits here */ +static DECLARE_WAIT_QUEUE_HEAD(qmi_wait_queue); + + +static void qmi_dump_msg(struct qmi_msg *msg, const char *prefix) +{ + unsigned sz, n; + unsigned char *x; + + if (!verbose) + return; + + printk(KERN_INFO + "qmi: %s: svc=%02x cid=%02x tid=%04x type=%04x size=%04x\n", + prefix, msg->service, msg->client_id, + msg->txn_id, msg->type, msg->size); + + x = msg->tlv; + sz = msg->size; + + while (sz >= 3) { + sz -= 3; + + n = x[1] | (x[2] << 8); + if (n > sz) + break; + + printk(KERN_INFO "qmi: %s: tlv: %02x %04x { ", + prefix, x[0], n); + x += 3; + sz -= n; + while (n-- > 0) + printk("%02x ", *x++); + printk("}\n"); + } +} + +int qmi_add_tlv(struct qmi_msg *msg, + unsigned type, unsigned size, const void *data) +{ + unsigned char *x = msg->tlv + msg->size; + + x[0] = type; + x[1] = size; + x[2] = size >> 8; + + memcpy(x + 3, data, size); + + msg->size += (size + 3); + + return 0; +} + +/* Extract a tagged item from a qmi message buffer, +** taking care not to overrun the buffer. +*/ +static int qmi_get_tlv(struct qmi_msg *msg, + unsigned type, unsigned size, void *data) +{ + unsigned char *x = msg->tlv; + unsigned len = msg->size; + unsigned n; + + while (len >= 3) { + len -= 3; + + /* size of this item */ + n = x[1] | (x[2] << 8); + if (n > len) + break; + + if (x[0] == type) { + if (n != size) + return -1; + memcpy(data, x + 3, size); + return 0; + } + + x += (n + 3); + len -= n; + } + + return -1; +} + +static unsigned qmi_get_status(struct qmi_msg *msg, unsigned *error) +{ + unsigned short status[2]; + if (qmi_get_tlv(msg, 0x02, sizeof(status), status)) { + *error = 0; + return QMI_RESULT_FAILURE; + } else { + *error = status[1]; + return status[0]; + } +} + +/* 0x01 */ +#define QMUX_HEADER 13 + +/* should be >= HEADER + FOOTER */ +#define QMUX_OVERHEAD 16 + +static int qmi_send(struct qmi_ctxt *ctxt, struct qmi_msg *msg) +{ + unsigned char *data; + unsigned hlen; + unsigned len; + int r; + + qmi_dump_msg(msg, "send"); + + if (msg->service == QMI_CTL) { + hlen = QMUX_HEADER - 1; + } else { + hlen = QMUX_HEADER; + } + + /* QMUX length is total header + total payload - IFC selector */ + len = hlen + msg->size - 1; + if (len > 0xffff) + return -1; + + data = msg->tlv - hlen; + + /* prepend encap and qmux header */ + *data++ = 0x01; /* ifc selector */ + + /* qmux header */ + *data++ = len; + *data++ = len >> 8; + *data++ = 0x00; /* flags: client */ + *data++ = msg->service; + *data++ = msg->client_id; + + /* qmi header */ + *data++ = 0x00; /* flags: send */ + *data++ = msg->txn_id; + if (msg->service != QMI_CTL) + *data++ = msg->txn_id >> 8; + + *data++ = msg->type; + *data++ = msg->type >> 8; + *data++ = msg->size; + *data++ = msg->size >> 8; + + /* len + 1 takes the interface selector into account */ + r = smd_write(ctxt->ch, msg->tlv - hlen, len + 1); + + if (r != len) { + return -1; + } else { + return 0; + } +} + +static void qmi_process_ctl_msg(struct qmi_ctxt *ctxt, struct qmi_msg *msg) +{ + unsigned err; + if (msg->type == 0x0022) { + unsigned char n[2]; + if (qmi_get_status(msg, &err)) + return; + if (qmi_get_tlv(msg, 0x01, sizeof(n), n)) + return; + if (n[0] == QMI_WDS) { + printk(KERN_INFO + "qmi: ctl: wds use client_id 0x%02x\n", n[1]); + ctxt->wds_client_id = n[1]; + ctxt->wds_busy = 0; + } + } +} + +static int qmi_network_get_profile(struct qmi_ctxt *ctxt); + +static void swapaddr(unsigned char *src, unsigned char *dst) +{ + dst[0] = src[3]; + dst[1] = src[2]; + dst[2] = src[1]; + dst[3] = src[0]; +} + +static unsigned char zero[4]; +static void qmi_read_runtime_profile(struct qmi_ctxt *ctxt, struct qmi_msg *msg) +{ + unsigned char tmp[4]; + unsigned r; + + r = qmi_get_tlv(msg, 0x1e, 4, tmp); + swapaddr(r ? zero : tmp, ctxt->addr); + r = qmi_get_tlv(msg, 0x21, 4, tmp); + swapaddr(r ? zero : tmp, ctxt->mask); + r = qmi_get_tlv(msg, 0x20, 4, tmp); + swapaddr(r ? zero : tmp, ctxt->gateway); + r = qmi_get_tlv(msg, 0x15, 4, tmp); + swapaddr(r ? zero : tmp, ctxt->dns1); + r = qmi_get_tlv(msg, 0x16, 4, tmp); + swapaddr(r ? zero : tmp, ctxt->dns2); +} + +static void qmi_process_unicast_wds_msg(struct qmi_ctxt *ctxt, + struct qmi_msg *msg) +{ + unsigned err; + switch (msg->type) { + case 0x0021: + if (qmi_get_status(msg, &err)) { + printk(KERN_ERR + "qmi: wds: network stop failed (%04x)\n", err); + } else { + printk(KERN_INFO + "qmi: wds: network stopped\n"); + ctxt->state = STATE_OFFLINE; + ctxt->state_dirty = 1; + } + break; + case 0x0020: + if (qmi_get_status(msg, &err)) { + printk(KERN_ERR + "qmi: wds: network start failed (%04x)\n", err); + } else if (qmi_get_tlv(msg, 0x01, sizeof(ctxt->wds_handle), &ctxt->wds_handle)) { + printk(KERN_INFO + "qmi: wds no handle?\n"); + } else { + printk(KERN_INFO + "qmi: wds: got handle 0x%08x\n", + ctxt->wds_handle); + } + break; + case 0x002D: + printk("qmi: got network profile\n"); + if (ctxt->state == STATE_QUERYING) { + qmi_read_runtime_profile(ctxt, msg); + ctxt->state = STATE_ONLINE; + ctxt->state_dirty = 1; + } + break; + default: + printk(KERN_ERR "qmi: unknown msg type 0x%04x\n", msg->type); + } + ctxt->wds_busy = 0; +} + +static void qmi_process_broadcast_wds_msg(struct qmi_ctxt *ctxt, + struct qmi_msg *msg) +{ + if (msg->type == 0x0022) { + unsigned char n[2]; + if (qmi_get_tlv(msg, 0x01, sizeof(n), n)) + return; + switch (n[0]) { + case 1: + printk(KERN_INFO "qmi: wds: DISCONNECTED\n"); + ctxt->state = STATE_OFFLINE; + ctxt->state_dirty = 1; + break; + case 2: + printk(KERN_INFO "qmi: wds: CONNECTED\n"); + ctxt->state = STATE_QUERYING; + ctxt->state_dirty = 1; + qmi_network_get_profile(ctxt); + break; + case 3: + printk(KERN_INFO "qmi: wds: SUSPENDED\n"); + ctxt->state = STATE_OFFLINE; + ctxt->state_dirty = 1; + } + } else { + printk(KERN_ERR "qmi: unknown bcast msg type 0x%04x\n", msg->type); + } +} + +static void qmi_process_wds_msg(struct qmi_ctxt *ctxt, + struct qmi_msg *msg) +{ + printk("wds: %04x @ %02x\n", msg->type, msg->client_id); + if (msg->client_id == ctxt->wds_client_id) { + qmi_process_unicast_wds_msg(ctxt, msg); + } else if (msg->client_id == 0xff) { + qmi_process_broadcast_wds_msg(ctxt, msg); + } else { + printk(KERN_ERR + "qmi_process_wds_msg client id 0x%02x unknown\n", + msg->client_id); + } +} + +static void qmi_process_qmux(struct qmi_ctxt *ctxt, + unsigned char *buf, unsigned sz) +{ + struct qmi_msg msg; + + /* require a full header */ + if (sz < 5) + return; + + /* require a size that matches the buffer size */ + if (sz != (buf[0] | (buf[1] << 8))) + return; + + /* only messages from a service (bit7=1) are allowed */ + if (buf[2] != 0x80) + return; + + msg.service = buf[3]; + msg.client_id = buf[4]; + + /* annoyingly, CTL messages have a shorter TID */ + if (buf[3] == 0) { + if (sz < 7) + return; + msg.txn_id = buf[6]; + buf += 7; + sz -= 7; + } else { + if (sz < 8) + return; + msg.txn_id = buf[6] | (buf[7] << 8); + buf += 8; + sz -= 8; + } + + /* no type and size!? */ + if (sz < 4) + return; + sz -= 4; + + msg.type = buf[0] | (buf[1] << 8); + msg.size = buf[2] | (buf[3] << 8); + msg.tlv = buf + 4; + + if (sz != msg.size) + return; + + qmi_dump_msg(&msg, "recv"); + + mutex_lock(&ctxt->lock); + switch (msg.service) { + case QMI_CTL: + qmi_process_ctl_msg(ctxt, &msg); + break; + case QMI_WDS: + qmi_process_wds_msg(ctxt, &msg); + break; + default: + printk(KERN_ERR "qmi: msg from unknown svc 0x%02x\n", + msg.service); + break; + } + mutex_unlock(&ctxt->lock); + + wake_up(&qmi_wait_queue); +} + +#define QMI_MAX_PACKET (256 + QMUX_OVERHEAD) + +static void qmi_read_work(struct work_struct *ws) +{ + struct qmi_ctxt *ctxt = container_of(ws, struct qmi_ctxt, read_work); + struct smd_channel *ch = ctxt->ch; + unsigned char buf[QMI_MAX_PACKET]; + int sz; + + for (;;) { + sz = smd_cur_packet_size(ch); + if (sz == 0) + break; + if (sz < smd_read_avail(ch)) + break; + if (sz > QMI_MAX_PACKET) { + smd_read(ch, 0, sz); + continue; + } + if (smd_read(ch, buf, sz) != sz) { + printk(KERN_ERR "qmi: not enough data?!\n"); + continue; + } + + /* interface selector must be 1 */ + if (buf[0] != 0x01) + continue; + + qmi_process_qmux(ctxt, buf + 1, sz - 1); + } +} + +static int qmi_request_wds_cid(struct qmi_ctxt *ctxt); + +static void qmi_open_work(struct work_struct *ws) +{ + struct qmi_ctxt *ctxt = container_of(ws, struct qmi_ctxt, open_work); + mutex_lock(&ctxt->lock); + qmi_request_wds_cid(ctxt); + mutex_unlock(&ctxt->lock); +} + +static void qmi_notify(void *priv, unsigned event) +{ + struct qmi_ctxt *ctxt = priv; + + switch (event) { + case SMD_EVENT_DATA: { + int sz; + sz = smd_cur_packet_size(ctxt->ch); + if ((sz > 0) && (sz <= smd_read_avail(ctxt->ch))) + queue_work(qmi_wq, &ctxt->read_work); + break; + } + case SMD_EVENT_OPEN: + printk(KERN_INFO "qmi: smd opened\n"); + queue_work(qmi_wq, &ctxt->open_work); + break; + case SMD_EVENT_CLOSE: + printk(KERN_INFO "qmi: smd closed\n"); + break; + } +} + +static int qmi_request_wds_cid(struct qmi_ctxt *ctxt) +{ + unsigned char data[64 + QMUX_OVERHEAD]; + struct qmi_msg msg; + unsigned char n; + + msg.service = QMI_CTL; + msg.client_id = qmi_ctl_client_id; + msg.txn_id = ctxt->ctl_txn_id; + msg.type = 0x0022; + msg.size = 0; + msg.tlv = data + QMUX_HEADER; + + ctxt->ctl_txn_id += 2; + + n = QMI_WDS; + qmi_add_tlv(&msg, 0x01, 0x01, &n); + + return qmi_send(ctxt, &msg); +} + +static int qmi_network_get_profile(struct qmi_ctxt *ctxt) +{ + unsigned char data[96 + QMUX_OVERHEAD]; + struct qmi_msg msg; + + msg.service = QMI_WDS; + msg.client_id = ctxt->wds_client_id; + msg.txn_id = ctxt->wds_txn_id; + msg.type = 0x002D; + msg.size = 0; + msg.tlv = data + QMUX_HEADER; + + ctxt->wds_txn_id += 2; + + return qmi_send(ctxt, &msg); +} + +static int qmi_network_up(struct qmi_ctxt *ctxt, char *apn) +{ + unsigned char data[96 + QMUX_OVERHEAD]; + struct qmi_msg msg; + char *user; + char *pass; + + for (user = apn; *user; user++) { + if (*user == ' ') { + *user++ = 0; + break; + } + } + for (pass = user; *pass; pass++) { + if (*pass == ' ') { + *pass++ = 0; + break; + } + } + + msg.service = QMI_WDS; + msg.client_id = ctxt->wds_client_id; + msg.txn_id = ctxt->wds_txn_id; + msg.type = 0x0020; + msg.size = 0; + msg.tlv = data + QMUX_HEADER; + + ctxt->wds_txn_id += 2; + + qmi_add_tlv(&msg, 0x14, strlen(apn), apn); + if (*user) { + unsigned char x; + x = 3; + qmi_add_tlv(&msg, 0x16, 1, &x); + qmi_add_tlv(&msg, 0x17, strlen(user), user); + if (*pass) + qmi_add_tlv(&msg, 0x18, strlen(pass), pass); + } + return qmi_send(ctxt, &msg); +} + +static int qmi_network_down(struct qmi_ctxt *ctxt) +{ + unsigned char data[16 + QMUX_OVERHEAD]; + struct qmi_msg msg; + + msg.service = QMI_WDS; + msg.client_id = ctxt->wds_client_id; + msg.txn_id = ctxt->wds_txn_id; + msg.type = 0x0021; + msg.size = 0; + msg.tlv = data + QMUX_HEADER; + + ctxt->wds_txn_id += 2; + + qmi_add_tlv(&msg, 0x01, sizeof(ctxt->wds_handle), &ctxt->wds_handle); + + return qmi_send(ctxt, &msg); +} + +static int qmi_print_state(struct qmi_ctxt *ctxt, char *buf, int max) +{ + int i; + char *statename; + + if (ctxt->state == STATE_ONLINE) { + statename = "up"; + } else if (ctxt->state == STATE_OFFLINE) { + statename = "down"; + } else { + statename = "busy"; + } + + i = scnprintf(buf, max, "STATE=%s\n", statename); + i += scnprintf(buf + i, max - i, "CID=%d\n",ctxt->wds_client_id); + + if (ctxt->state != STATE_ONLINE){ + return i; + } + + i += scnprintf(buf + i, max - i, "ADDR=%d.%d.%d.%d\n", + ctxt->addr[0], ctxt->addr[1], ctxt->addr[2], ctxt->addr[3]); + i += scnprintf(buf + i, max - i, "MASK=%d.%d.%d.%d\n", + ctxt->mask[0], ctxt->mask[1], ctxt->mask[2], ctxt->mask[3]); + i += scnprintf(buf + i, max - i, "GATEWAY=%d.%d.%d.%d\n", + ctxt->gateway[0], ctxt->gateway[1], ctxt->gateway[2], + ctxt->gateway[3]); + i += scnprintf(buf + i, max - i, "DNS1=%d.%d.%d.%d\n", + ctxt->dns1[0], ctxt->dns1[1], ctxt->dns1[2], ctxt->dns1[3]); + i += scnprintf(buf + i, max - i, "DNS2=%d.%d.%d.%d\n", + ctxt->dns2[0], ctxt->dns2[1], ctxt->dns2[2], ctxt->dns2[3]); + + return i; +} + +static ssize_t qmi_read(struct file *fp, char __user *buf, + size_t count, loff_t *pos) +{ + struct qmi_ctxt *ctxt = fp->private_data; + char msg[256]; + int len; + int r; + + mutex_lock(&ctxt->lock); + for (;;) { + if (ctxt->state_dirty) { + ctxt->state_dirty = 0; + len = qmi_print_state(ctxt, msg, 256); + break; + } + mutex_unlock(&ctxt->lock); + r = wait_event_interruptible(qmi_wait_queue, ctxt->state_dirty); + if (r < 0) + return r; + mutex_lock(&ctxt->lock); + } + mutex_unlock(&ctxt->lock); + + if (len > count) + len = count; + + if (copy_to_user(buf, msg, len)) + return -EFAULT; + + return len; +} + + +static ssize_t qmi_write(struct file *fp, const char __user *buf, + size_t count, loff_t *pos) +{ + struct qmi_ctxt *ctxt = fp->private_data; + unsigned char cmd[64]; + int len; + int r; + + if (count < 1) + return 0; + + len = count > 63 ? 63 : count; + + if (copy_from_user(cmd, buf, len)) + return -EFAULT; + + cmd[len] = 0; + + /* lazy */ + if (cmd[len-1] == '\n') { + cmd[len-1] = 0; + len--; + } + + if (!strncmp(cmd, "verbose", 7)) { + verbose = 1; + } else if (!strncmp(cmd, "terse", 5)) { + verbose = 0; + } else if (!strncmp(cmd, "poll", 4)) { + ctxt->state_dirty = 1; + wake_up(&qmi_wait_queue); + } else if (!strncmp(cmd, "down", 4)) { +retry_down: + mutex_lock(&ctxt->lock); + if (ctxt->wds_busy) { + mutex_unlock(&ctxt->lock); + r = wait_event_interruptible(qmi_wait_queue, !ctxt->wds_busy); + if (r < 0) + return r; + goto retry_down; + } + ctxt->wds_busy = 1; + qmi_network_down(ctxt); + mutex_unlock(&ctxt->lock); + } else if (!strncmp(cmd, "up:", 3)) { +retry_up: + mutex_lock(&ctxt->lock); + if (ctxt->wds_busy) { + mutex_unlock(&ctxt->lock); + r = wait_event_interruptible(qmi_wait_queue, !ctxt->wds_busy); + if (r < 0) + return r; + goto retry_up; + } + ctxt->wds_busy = 1; + qmi_network_up(ctxt, cmd+3); + mutex_unlock(&ctxt->lock); + } else { + return -EINVAL; + } + + return count; +} + +static int qmi_open(struct inode *ip, struct file *fp) +{ + struct qmi_ctxt *ctxt = qmi_minor_to_ctxt(MINOR(ip->i_rdev)); + int r = 0; + + if (!ctxt) { + printk(KERN_ERR "unknown qmi misc %d\n", MINOR(ip->i_rdev)); + return -ENODEV; + } + + fp->private_data = ctxt; + + mutex_lock(&ctxt->lock); + if (ctxt->ch == 0) + r = smd_open(ctxt->ch_name, &ctxt->ch, ctxt, qmi_notify); + if (r == 0) + wake_up(&qmi_wait_queue); + mutex_unlock(&ctxt->lock); + + return r; +} + +static int qmi_release(struct inode *ip, struct file *fp) +{ + return 0; +} + +static struct file_operations qmi_fops = { + .owner = THIS_MODULE, + .read = qmi_read, + .write = qmi_write, + .open = qmi_open, + .release = qmi_release, +}; + +static struct qmi_ctxt qmi_device0 = { + .ch_name = "SMD_DATA5_CNTL", + .misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = "qmi0", + .fops = &qmi_fops, + } +}; +static struct qmi_ctxt qmi_device1 = { + .ch_name = "SMD_DATA6_CNTL", + .misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = "qmi1", + .fops = &qmi_fops, + } +}; +static struct qmi_ctxt qmi_device2 = { + .ch_name = "SMD_DATA7_CNTL", + .misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = "qmi2", + .fops = &qmi_fops, + } +}; + +static struct qmi_ctxt *qmi_minor_to_ctxt(unsigned n) +{ + if (n == qmi_device0.misc.minor) + return &qmi_device0; + if (n == qmi_device1.misc.minor) + return &qmi_device1; + if (n == qmi_device2.misc.minor) + return &qmi_device2; + return 0; +} + +static int __init qmi_init(void) +{ + int ret; + + qmi_wq = create_singlethread_workqueue("qmi"); + if (qmi_wq == 0) + return -ENOMEM; + + qmi_ctxt_init(&qmi_device0, 0); + qmi_ctxt_init(&qmi_device1, 1); + qmi_ctxt_init(&qmi_device2, 2); + + ret = misc_register(&qmi_device0.misc); + if (ret == 0) + ret = misc_register(&qmi_device1.misc); + if (ret == 0) + ret = misc_register(&qmi_device2.misc); + return ret; +} + +module_init(qmi_init); -- cgit v1.2.3 From f91e58fe14fd4353585071511eeb63492af7f162 Mon Sep 17 00:00:00 2001 From: San Mehat Date: Fri, 1 Jan 2010 10:37:58 -0800 Subject: [ARM] msm: shared memory rpc router The RPC router provides access to RPC services running on the baseband core from kernel and userspace. Signed-off-by: Brian Swetland Signed-off-by: San Mehat Signed-off-by: Iliyan Malchev --- arch/arm/mach-msm/Kconfig | 9 + arch/arm/mach-msm/Makefile | 4 + arch/arm/mach-msm/include/mach/msm_rpcrouter.h | 151 +++ arch/arm/mach-msm/smd_rpcrouter.c | 1165 ++++++++++++++++++++++++ arch/arm/mach-msm/smd_rpcrouter.h | 190 ++++ arch/arm/mach-msm/smd_rpcrouter_device.c | 339 +++++++ arch/arm/mach-msm/smd_rpcrouter_servers.c | 213 +++++ 7 files changed, 2071 insertions(+) create mode 100644 arch/arm/mach-msm/include/mach/msm_rpcrouter.h create mode 100644 arch/arm/mach-msm/smd_rpcrouter.c create mode 100644 arch/arm/mach-msm/smd_rpcrouter.h create mode 100644 arch/arm/mach-msm/smd_rpcrouter_device.c create mode 100644 arch/arm/mach-msm/smd_rpcrouter_servers.c (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index 7cee7913f6f7..2e08f3a36f2b 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -52,4 +52,13 @@ config MSM_SMD used to communicate with various services on the baseband processor. +config MSM_ONCRPCROUTER + depends on MSM_SMD + default y + bool "MSM ONCRPC router support" + help + Support for the MSM ONCRPC router for communication between + the ARM9 and ARM11 + + endif diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 238329d63b2a..ee6da92c3063 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -6,6 +6,10 @@ obj-y += clock.o clock-7x01a.o obj-y += gpio.o generic_gpio.o obj-$(CONFIG_MSM_SMD) += smd.o smd_tty.o smd_qmi.o +obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter.o +obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_device.o +obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_servers.o + obj-$(CONFIG_MACH_TROUT) += board-dream.o obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o diff --git a/arch/arm/mach-msm/include/mach/msm_rpcrouter.h b/arch/arm/mach-msm/include/mach/msm_rpcrouter.h new file mode 100644 index 000000000000..facef7cefd2d --- /dev/null +++ b/arch/arm/mach-msm/include/mach/msm_rpcrouter.h @@ -0,0 +1,151 @@ +/** include/asm-arm/arch-msm/msm_rpcrouter.h + * + * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2007 QUALCOMM Incorporated + * Author: San Mehat + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#ifndef __ASM__ARCH_MSM_RPCROUTER_H +#define __ASM__ARCH_MSM_RPCROUTER_H + +#include +#include +#include +#include + +struct rpcrouter_ioctl_server_args { + uint32_t prog; + uint32_t vers; +}; + +struct msm_rpc_endpoint; + +struct rpcsvr_platform_device +{ + struct platform_device base; + uint32_t prog; + uint32_t vers; +}; + +#define RPC_DATA_IN 0 +/* + * Structures for sending / receiving direct RPC requests + * XXX: Any cred/verif lengths > 0 not supported + */ + +struct rpc_request_hdr +{ + uint32_t xid; + uint32_t type; /* 0 */ + uint32_t rpc_vers; /* 2 */ + uint32_t prog; + uint32_t vers; + uint32_t procedure; + uint32_t cred_flavor; + uint32_t cred_length; + uint32_t verf_flavor; + uint32_t verf_length; +}; + +typedef struct +{ + uint32_t low; + uint32_t high; +} rpc_reply_progmismatch_data; + +typedef struct +{ +} rpc_denied_reply_hdr; + +typedef struct +{ + uint32_t verf_flavor; + uint32_t verf_length; + uint32_t accept_stat; +#define RPC_ACCEPTSTAT_SUCCESS 0 +#define RPC_ACCEPTSTAT_PROG_UNAVAIL 1 +#define RPC_ACCEPTSTAT_PROG_MISMATCH 2 +#define RPC_ACCEPTSTAT_PROC_UNAVAIL 3 +#define RPC_ACCEPTSTAT_GARBAGE_ARGS 4 +#define RPC_ACCEPTSTAT_SYSTEM_ERR 5 +#define RPC_ACCEPTSTAT_PROG_LOCKED 6 + /* + * Following data is dependant on accept_stat + * If ACCEPTSTAT == PROG_MISMATCH then there is a + * 'rpc_reply_progmismatch_data' structure following the header. + * Otherwise the data is procedure specific + */ +} rpc_accepted_reply_hdr; + +struct rpc_reply_hdr +{ + uint32_t xid; + uint32_t type; + uint32_t reply_stat; +#define RPCMSG_REPLYSTAT_ACCEPTED 0 +#define RPCMSG_REPLYSTAT_DENIED 1 + union { + rpc_accepted_reply_hdr acc_hdr; + rpc_denied_reply_hdr dny_hdr; + } data; +}; + +/* flags for msm_rpc_connect() */ +#define MSM_RPC_UNINTERRUPTIBLE 0x0001 + +/* use IS_ERR() to check for failure */ +struct msm_rpc_endpoint *msm_rpc_open(void); +struct msm_rpc_endpoint *msm_rpc_connect(uint32_t prog, uint32_t vers, unsigned flags); + +int msm_rpc_close(struct msm_rpc_endpoint *ept); +int msm_rpc_write(struct msm_rpc_endpoint *ept, + void *data, int len); +int msm_rpc_read(struct msm_rpc_endpoint *ept, + void **data, unsigned len, long timeout); +void msm_rpc_setup_req(struct rpc_request_hdr *hdr, + uint32_t prog, uint32_t vers, uint32_t proc); +int msm_rpc_register_server(struct msm_rpc_endpoint *ept, + uint32_t prog, uint32_t vers); +int msm_rpc_unregister_server(struct msm_rpc_endpoint *ept, + uint32_t prog, uint32_t vers); + +/* simple blocking rpc call + * + * request is mandatory and must have a rpc_request_hdr + * at the start. The header will be filled out for you. + * + * reply provides a buffer for replies of reply_max_size + */ +int msm_rpc_call_reply(struct msm_rpc_endpoint *ept, uint32_t proc, + void *request, int request_size, + void *reply, int reply_max_size, + long timeout); +int msm_rpc_call(struct msm_rpc_endpoint *ept, uint32_t proc, + void *request, int request_size, + long timeout); + +struct msm_rpc_server +{ + struct list_head list; + uint32_t flags; + + uint32_t prog; + uint32_t vers; + + int (*rpc_call)(struct msm_rpc_server *server, + struct rpc_request_hdr *req, unsigned len); +}; + +int msm_rpc_create_server(struct msm_rpc_server *server); + +#endif diff --git a/arch/arm/mach-msm/smd_rpcrouter.c b/arch/arm/mach-msm/smd_rpcrouter.c new file mode 100644 index 000000000000..f30325c008b5 --- /dev/null +++ b/arch/arm/mach-msm/smd_rpcrouter.c @@ -0,0 +1,1165 @@ +/* arch/arm/mach-msm/smd_rpcrouter.c + * + * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2007 QUALCOMM Incorporated + * Author: San Mehat + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +/* TODO: fragmentation for large writes */ +/* TODO: handle cases where smd_write() will tempfail due to full fifo */ +/* TODO: thread priority? schedule a work to bump it? */ +/* TODO: maybe make server_list_lock a mutex */ +/* TODO: pool fragments to avoid kmalloc/kfree churn */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "smd_rpcrouter.h" + +#define TRACE_R2R_MSG 0 +#define TRACE_R2R_RAW 0 +#define TRACE_RPC_MSG 0 + +#define MSM_RPCROUTER_DEBUG 0 +#define MSM_RPCROUTER_DEBUG_PKT 0 +#define MSM_RPCROUTER_R2R_DEBUG 0 +#define DUMP_ALL_RECEIVED_HEADERS 0 + +#define DIAG(x...) printk("[RR] ERROR " x) + +#if MSM_RPCROUTER_DEBUG +#define D(x...) printk(x) +#else +#define D(x...) do {} while (0) +#endif + +#if TRACE_R2R_MSG +#define RR(x...) printk("[RR] "x) +#else +#define RR(x...) do {} while (0) +#endif + +#if TRACE_RPC_MSG +#define IO(x...) printk("[RPC] "x) +#else +#define IO(x...) do {} while (0) +#endif + +static LIST_HEAD(local_endpoints); +static LIST_HEAD(remote_endpoints); + +static LIST_HEAD(server_list); + +static smd_channel_t *smd_channel; +static int initialized; +static wait_queue_head_t newserver_wait; +static wait_queue_head_t smd_wait; + +static DEFINE_SPINLOCK(local_endpoints_lock); +static DEFINE_SPINLOCK(remote_endpoints_lock); +static DEFINE_SPINLOCK(server_list_lock); +static DEFINE_SPINLOCK(smd_lock); + +static struct workqueue_struct *rpcrouter_workqueue; + +static atomic_t next_xid = ATOMIC_INIT(1); +static uint8_t next_pacmarkid; + +static void do_read_data(struct work_struct *work); +static void do_create_pdevs(struct work_struct *work); +static void do_create_rpcrouter_pdev(struct work_struct *work); + +static DECLARE_WORK(work_read_data, do_read_data); +static DECLARE_WORK(work_create_pdevs, do_create_pdevs); +static DECLARE_WORK(work_create_rpcrouter_pdev, do_create_rpcrouter_pdev); + +#define RR_STATE_IDLE 0 +#define RR_STATE_HEADER 1 +#define RR_STATE_BODY 2 +#define RR_STATE_ERROR 3 + +struct rr_context { + struct rr_packet *pkt; + uint8_t *ptr; + uint32_t state; /* current assembly state */ + uint32_t count; /* bytes needed in this state */ +}; + +struct rr_context the_rr_context; + +static struct platform_device rpcrouter_pdev = { + .name = "oncrpc_router", + .id = -1, +}; + + +static int rpcrouter_send_control_msg(union rr_control_msg *msg) +{ + struct rr_header hdr; + unsigned long flags; + int need; + + if (!(msg->cmd == RPCROUTER_CTRL_CMD_HELLO) && !initialized) { + printk(KERN_ERR "rpcrouter_send_control_msg(): Warning, " + "router not initialized\n"); + return -EINVAL; + } + + hdr.version = RPCROUTER_VERSION; + hdr.type = msg->cmd; + hdr.src_pid = RPCROUTER_PID_LOCAL; + hdr.src_cid = RPCROUTER_ROUTER_ADDRESS; + hdr.confirm_rx = 0; + hdr.size = sizeof(*msg); + hdr.dst_pid = 0; + hdr.dst_cid = RPCROUTER_ROUTER_ADDRESS; + + /* TODO: what if channel is full? */ + + need = sizeof(hdr) + hdr.size; + spin_lock_irqsave(&smd_lock, flags); + while (smd_write_avail(smd_channel) < need) { + spin_unlock_irqrestore(&smd_lock, flags); + msleep(250); + spin_lock_irqsave(&smd_lock, flags); + } + smd_write(smd_channel, &hdr, sizeof(hdr)); + smd_write(smd_channel, msg, hdr.size); + spin_unlock_irqrestore(&smd_lock, flags); + return 0; +} + +static struct rr_server *rpcrouter_create_server(uint32_t pid, + uint32_t cid, + uint32_t prog, + uint32_t ver) +{ + struct rr_server *server; + unsigned long flags; + int rc; + + server = kmalloc(sizeof(struct rr_server), GFP_KERNEL); + if (!server) + return ERR_PTR(-ENOMEM); + + memset(server, 0, sizeof(struct rr_server)); + server->pid = pid; + server->cid = cid; + server->prog = prog; + server->vers = ver; + + spin_lock_irqsave(&server_list_lock, flags); + list_add_tail(&server->list, &server_list); + spin_unlock_irqrestore(&server_list_lock, flags); + + if (pid == RPCROUTER_PID_REMOTE) { + rc = msm_rpcrouter_create_server_cdev(server); + if (rc < 0) + goto out_fail; + } + return server; +out_fail: + spin_lock_irqsave(&server_list_lock, flags); + list_del(&server->list); + spin_unlock_irqrestore(&server_list_lock, flags); + kfree(server); + return ERR_PTR(rc); +} + +static void rpcrouter_destroy_server(struct rr_server *server) +{ + unsigned long flags; + + spin_lock_irqsave(&server_list_lock, flags); + list_del(&server->list); + spin_unlock_irqrestore(&server_list_lock, flags); + device_destroy(msm_rpcrouter_class, server->device_number); + kfree(server); +} + +static struct rr_server *rpcrouter_lookup_server(uint32_t prog, + uint32_t ver) +{ + struct rr_server *server; + unsigned long flags; + + spin_lock_irqsave(&server_list_lock, flags); + list_for_each_entry(server, &server_list, list) { + if (server->prog == prog + && server->vers == ver) { + spin_unlock_irqrestore(&server_list_lock, flags); + return server; + } + } + spin_unlock_irqrestore(&server_list_lock, flags); + return NULL; +} + +static struct rr_server *rpcrouter_lookup_server_by_dev(dev_t dev) +{ + struct rr_server *server; + unsigned long flags; + + spin_lock_irqsave(&server_list_lock, flags); + list_for_each_entry(server, &server_list, list) { + if (server->device_number == dev) { + spin_unlock_irqrestore(&server_list_lock, flags); + return server; + } + } + spin_unlock_irqrestore(&server_list_lock, flags); + return NULL; +} + + +struct msm_rpc_endpoint *msm_rpcrouter_create_local_endpoint(dev_t dev) +{ + struct msm_rpc_endpoint *ept; + unsigned long flags; + + ept = kmalloc(sizeof(struct msm_rpc_endpoint), GFP_KERNEL); + if (!ept) + return NULL; + memset(ept, 0, sizeof(struct msm_rpc_endpoint)); + + /* mark no reply outstanding */ + ept->reply_pid = 0xffffffff; + + ept->cid = (uint32_t) ept; + ept->pid = RPCROUTER_PID_LOCAL; + ept->dev = dev; + + if ((dev != msm_rpcrouter_devno) && (dev != MKDEV(0, 0))) { + struct rr_server *srv; + /* + * This is a userspace client which opened + * a program/ver devicenode. Bind the client + * to that destination + */ + srv = rpcrouter_lookup_server_by_dev(dev); + /* TODO: bug? really? */ + BUG_ON(!srv); + + ept->dst_pid = srv->pid; + ept->dst_cid = srv->cid; + ept->dst_prog = cpu_to_be32(srv->prog); + ept->dst_vers = cpu_to_be32(srv->vers); + } else { + /* mark not connected */ + ept->dst_pid = 0xffffffff; + } + + init_waitqueue_head(&ept->wait_q); + INIT_LIST_HEAD(&ept->read_q); + spin_lock_init(&ept->read_q_lock); + INIT_LIST_HEAD(&ept->incomplete); + + spin_lock_irqsave(&local_endpoints_lock, flags); + list_add_tail(&ept->list, &local_endpoints); + spin_unlock_irqrestore(&local_endpoints_lock, flags); + return ept; +} + +int msm_rpcrouter_destroy_local_endpoint(struct msm_rpc_endpoint *ept) +{ + int rc; + union rr_control_msg msg; + + msg.cmd = RPCROUTER_CTRL_CMD_REMOVE_CLIENT; + msg.cli.pid = ept->pid; + msg.cli.cid = ept->cid; + + RR("x REMOVE_CLIENT id=%d:%08x\n", ept->pid, ept->cid); + rc = rpcrouter_send_control_msg(&msg); + if (rc < 0) + return rc; + + list_del(&ept->list); + kfree(ept); + return 0; +} + +static int rpcrouter_create_remote_endpoint(uint32_t cid) +{ + struct rr_remote_endpoint *new_c; + unsigned long flags; + + new_c = kmalloc(sizeof(struct rr_remote_endpoint), GFP_KERNEL); + if (!new_c) + return -ENOMEM; + memset(new_c, 0, sizeof(struct rr_remote_endpoint)); + + new_c->cid = cid; + new_c->pid = RPCROUTER_PID_REMOTE; + init_waitqueue_head(&new_c->quota_wait); + spin_lock_init(&new_c->quota_lock); + + spin_lock_irqsave(&remote_endpoints_lock, flags); + list_add_tail(&new_c->list, &remote_endpoints); + spin_unlock_irqrestore(&remote_endpoints_lock, flags); + return 0; +} + +static struct msm_rpc_endpoint *rpcrouter_lookup_local_endpoint(uint32_t cid) +{ + struct msm_rpc_endpoint *ept; + unsigned long flags; + + spin_lock_irqsave(&local_endpoints_lock, flags); + list_for_each_entry(ept, &local_endpoints, list) { + if (ept->cid == cid) { + spin_unlock_irqrestore(&local_endpoints_lock, flags); + return ept; + } + } + spin_unlock_irqrestore(&local_endpoints_lock, flags); + return NULL; +} + +static struct rr_remote_endpoint *rpcrouter_lookup_remote_endpoint(uint32_t cid) +{ + struct rr_remote_endpoint *ept; + unsigned long flags; + + spin_lock_irqsave(&remote_endpoints_lock, flags); + list_for_each_entry(ept, &remote_endpoints, list) { + if (ept->cid == cid) { + spin_unlock_irqrestore(&remote_endpoints_lock, flags); + return ept; + } + } + spin_unlock_irqrestore(&remote_endpoints_lock, flags); + return NULL; +} + +static int process_control_msg(union rr_control_msg *msg, int len) +{ + union rr_control_msg ctl; + struct rr_server *server; + struct rr_remote_endpoint *r_ept; + int rc = 0; + unsigned long flags; + + if (len != sizeof(*msg)) { + printk(KERN_ERR "rpcrouter: r2r msg size %d != %d\n", + len, sizeof(*msg)); + return -EINVAL; + } + + switch (msg->cmd) { + case RPCROUTER_CTRL_CMD_HELLO: + RR("o HELLO\n"); + + RR("x HELLO\n"); + memset(&ctl, 0, sizeof(ctl)); + ctl.cmd = RPCROUTER_CTRL_CMD_HELLO; + rpcrouter_send_control_msg(&ctl); + + initialized = 1; + + /* Send list of servers one at a time */ + ctl.cmd = RPCROUTER_CTRL_CMD_NEW_SERVER; + + /* TODO: long time to hold a spinlock... */ + spin_lock_irqsave(&server_list_lock, flags); + list_for_each_entry(server, &server_list, list) { + ctl.srv.pid = server->pid; + ctl.srv.cid = server->cid; + ctl.srv.prog = server->prog; + ctl.srv.vers = server->vers; + + RR("x NEW_SERVER id=%d:%08x prog=%08x:%d\n", + server->pid, server->cid, + server->prog, server->vers); + + rpcrouter_send_control_msg(&ctl); + } + spin_unlock_irqrestore(&server_list_lock, flags); + + queue_work(rpcrouter_workqueue, &work_create_rpcrouter_pdev); + break; + + case RPCROUTER_CTRL_CMD_RESUME_TX: + RR("o RESUME_TX id=%d:%08x\n", msg->cli.pid, msg->cli.cid); + + r_ept = rpcrouter_lookup_remote_endpoint(msg->cli.cid); + if (!r_ept) { + printk(KERN_ERR + "rpcrouter: Unable to resume client\n"); + break; + } + spin_lock_irqsave(&r_ept->quota_lock, flags); + r_ept->tx_quota_cntr = 0; + spin_unlock_irqrestore(&r_ept->quota_lock, flags); + wake_up(&r_ept->quota_wait); + break; + + case RPCROUTER_CTRL_CMD_NEW_SERVER: + RR("o NEW_SERVER id=%d:%08x prog=%08x:%d\n", + msg->srv.pid, msg->srv.cid, msg->srv.prog, msg->srv.vers); + + server = rpcrouter_lookup_server(msg->srv.prog, msg->srv.vers); + + if (!server) { + server = rpcrouter_create_server( + msg->srv.pid, msg->srv.cid, + msg->srv.prog, msg->srv.vers); + if (!server) + return -ENOMEM; + /* + * XXX: Verify that its okay to add the + * client to our remote client list + * if we get a NEW_SERVER notification + */ + if (!rpcrouter_lookup_remote_endpoint(msg->srv.cid)) { + rc = rpcrouter_create_remote_endpoint( + msg->srv.cid); + if (rc < 0) + printk(KERN_ERR + "rpcrouter:Client create" + "error (%d)\n", rc); + } + schedule_work(&work_create_pdevs); + wake_up(&newserver_wait); + } else { + if ((server->pid == msg->srv.pid) && + (server->cid == msg->srv.cid)) { + printk(KERN_ERR "rpcrouter: Duplicate svr\n"); + } else { + server->pid = msg->srv.pid; + server->cid = msg->srv.cid; + } + } + break; + + case RPCROUTER_CTRL_CMD_REMOVE_SERVER: + RR("o REMOVE_SERVER prog=%08x:%d\n", + msg->srv.prog, msg->srv.vers); + server = rpcrouter_lookup_server(msg->srv.prog, msg->srv.vers); + if (server) + rpcrouter_destroy_server(server); + break; + + case RPCROUTER_CTRL_CMD_REMOVE_CLIENT: + RR("o REMOVE_CLIENT id=%d:%08x\n", msg->cli.pid, msg->cli.cid); + if (msg->cli.pid != RPCROUTER_PID_REMOTE) { + printk(KERN_ERR + "rpcrouter: Denying remote removal of " + "local client\n"); + break; + } + r_ept = rpcrouter_lookup_remote_endpoint(msg->cli.cid); + if (r_ept) { + spin_lock_irqsave(&remote_endpoints_lock, flags); + list_del(&r_ept->list); + spin_unlock_irqrestore(&remote_endpoints_lock, flags); + kfree(r_ept); + } + + /* Notify local clients of this event */ + printk(KERN_ERR "rpcrouter: LOCAL NOTIFICATION NOT IMP\n"); + rc = -ENOSYS; + + break; + default: + RR("o UNKNOWN(%08x)\n", msg->cmd); + rc = -ENOSYS; + } + + return rc; +} + +static void do_create_rpcrouter_pdev(struct work_struct *work) +{ + platform_device_register(&rpcrouter_pdev); +} + +static void do_create_pdevs(struct work_struct *work) +{ + unsigned long flags; + struct rr_server *server; + + /* TODO: race if destroyed while being registered */ + spin_lock_irqsave(&server_list_lock, flags); + list_for_each_entry(server, &server_list, list) { + if (server->pid == RPCROUTER_PID_REMOTE) { + if (server->pdev_name[0] == 0) { + spin_unlock_irqrestore(&server_list_lock, + flags); + msm_rpcrouter_create_server_pdev(server); + schedule_work(&work_create_pdevs); + return; + } + } + } + spin_unlock_irqrestore(&server_list_lock, flags); +} + +static void rpcrouter_smdnotify(void *_dev, unsigned event) +{ + if (event != SMD_EVENT_DATA) + return; + + wake_up(&smd_wait); +} + +static void *rr_malloc(unsigned sz) +{ + void *ptr = kmalloc(sz, GFP_KERNEL); + if (ptr) + return ptr; + + printk(KERN_ERR "rpcrouter: kmalloc of %d failed, retrying...\n", sz); + do { + ptr = kmalloc(sz, GFP_KERNEL); + } while (!ptr); + + return ptr; +} + +/* TODO: deal with channel teardown / restore */ +static int rr_read(void *data, int len) +{ + int rc; + unsigned long flags; +// printk("rr_read() %d\n", len); + for(;;) { + spin_lock_irqsave(&smd_lock, flags); + if (smd_read_avail(smd_channel) >= len) { + rc = smd_read(smd_channel, data, len); + spin_unlock_irqrestore(&smd_lock, flags); + if (rc == len) + return 0; + else + return -EIO; + } + spin_unlock_irqrestore(&smd_lock, flags); + +// printk("rr_read: waiting (%d)\n", len); + wait_event(smd_wait, smd_read_avail(smd_channel) >= len); + } + return 0; +} + +static uint32_t r2r_buf[RPCROUTER_MSGSIZE_MAX]; + +static void do_read_data(struct work_struct *work) +{ + struct rr_header hdr; + struct rr_packet *pkt; + struct rr_fragment *frag; + struct msm_rpc_endpoint *ept; + uint32_t pm, mid; + unsigned long flags; + + if (rr_read(&hdr, sizeof(hdr))) + goto fail_io; + +#if TRACE_R2R_RAW + RR("- ver=%d type=%d src=%d:%08x crx=%d siz=%d dst=%d:%08x\n", + hdr.version, hdr.type, hdr.src_pid, hdr.src_cid, + hdr.confirm_rx, hdr.size, hdr.dst_pid, hdr.dst_cid); +#endif + + if (hdr.version != RPCROUTER_VERSION) { + DIAG("version %d != %d\n", hdr.version, RPCROUTER_VERSION); + goto fail_data; + } + if (hdr.size > RPCROUTER_MSGSIZE_MAX) { + DIAG("msg size %d > max %d\n", hdr.size, RPCROUTER_MSGSIZE_MAX); + goto fail_data; + } + + if (hdr.dst_cid == RPCROUTER_ROUTER_ADDRESS) { + if (rr_read(r2r_buf, hdr.size)) + goto fail_io; + process_control_msg((void*) r2r_buf, hdr.size); + goto done; + } + + if (hdr.size < sizeof(pm)) { + DIAG("runt packet (no pacmark)\n"); + goto fail_data; + } + if (rr_read(&pm, sizeof(pm))) + goto fail_io; + + hdr.size -= sizeof(pm); + + frag = rr_malloc(hdr.size + sizeof(*frag)); + frag->next = NULL; + frag->length = hdr.size; + if (rr_read(frag->data, hdr.size)) + goto fail_io; + + ept = rpcrouter_lookup_local_endpoint(hdr.dst_cid); + if (!ept) { + DIAG("no local ept for cid %08x\n", hdr.dst_cid); + kfree(frag); + goto done; + } + + /* See if there is already a partial packet that matches our mid + * and if so, append this fragment to that packet. + */ + mid = PACMARK_MID(pm); + list_for_each_entry(pkt, &ept->incomplete, list) { + if (pkt->mid == mid) { + pkt->last->next = frag; + pkt->last = frag; + pkt->length += frag->length; + if (PACMARK_LAST(pm)) { + list_del(&pkt->list); + goto packet_complete; + } + goto done; + } + } + + /* This mid is new -- create a packet for it, and put it on + * the incomplete list if this fragment is not a last fragment, + * otherwise put it on the read queue. + */ + pkt = rr_malloc(sizeof(struct rr_packet)); + pkt->first = frag; + pkt->last = frag; + memcpy(&pkt->hdr, &hdr, sizeof(hdr)); + pkt->mid = mid; + pkt->length = frag->length; + if (!PACMARK_LAST(pm)) { + list_add_tail(&pkt->list, &ept->incomplete); + goto done; + } + +packet_complete: + spin_lock_irqsave(&ept->read_q_lock, flags); + list_add_tail(&pkt->list, &ept->read_q); + wake_up(&ept->wait_q); + spin_unlock_irqrestore(&ept->read_q_lock, flags); +done: + if (hdr.confirm_rx) { + union rr_control_msg msg; + + msg.cmd = RPCROUTER_CTRL_CMD_RESUME_TX; + msg.cli.pid = hdr.dst_pid; + msg.cli.cid = hdr.dst_cid; + + RR("x RESUME_TX id=%d:%08x\n", msg.cli.pid, msg.cli.cid); + rpcrouter_send_control_msg(&msg); + } + + queue_work(rpcrouter_workqueue, &work_read_data); + return; + +fail_io: +fail_data: + printk(KERN_ERR "rpc_router has died\n"); +} + +void msm_rpc_setup_req(struct rpc_request_hdr *hdr, uint32_t prog, + uint32_t vers, uint32_t proc) +{ + memset(hdr, 0, sizeof(struct rpc_request_hdr)); + hdr->xid = cpu_to_be32(atomic_add_return(1, &next_xid)); + hdr->rpc_vers = cpu_to_be32(2); + hdr->prog = cpu_to_be32(prog); + hdr->vers = cpu_to_be32(vers); + hdr->procedure = cpu_to_be32(proc); +} + +struct msm_rpc_endpoint *msm_rpc_open(void) +{ + struct msm_rpc_endpoint *ept; + + ept = msm_rpcrouter_create_local_endpoint(MKDEV(0, 0)); + if (ept == NULL) + return ERR_PTR(-ENOMEM); + + return ept; +} + +int msm_rpc_close(struct msm_rpc_endpoint *ept) +{ + return msm_rpcrouter_destroy_local_endpoint(ept); +} + +int msm_rpc_write(struct msm_rpc_endpoint *ept, void *buffer, int count) +{ + struct rr_header hdr; + uint32_t pacmark; + struct rpc_request_hdr *rq = buffer; + struct rr_remote_endpoint *r_ept; + unsigned long flags; + int needed; + DEFINE_WAIT(__wait); + + /* TODO: fragmentation for large outbound packets */ + if (count > (RPCROUTER_MSGSIZE_MAX - sizeof(uint32_t)) || !count) + return -EINVAL; + + /* snoop the RPC packet and enforce permissions */ + + /* has to have at least the xid and type fields */ + if (count < (sizeof(uint32_t) * 2)) { + printk(KERN_ERR "rr_write: rejecting runt packet\n"); + return -EINVAL; + } + + if (rq->type == 0) { + /* RPC CALL */ + if (count < (sizeof(uint32_t) * 6)) { + printk(KERN_ERR + "rr_write: rejecting runt call packet\n"); + return -EINVAL; + } + if (ept->dst_pid == 0xffffffff) { + printk(KERN_ERR "rr_write: not connected\n"); + return -ENOTCONN; + } + if ((ept->dst_prog != rq->prog) || + (ept->dst_vers != rq->vers)) { + printk(KERN_ERR + "rr_write: cannot write to %08x:%d " + "(bound to %08x:%d)\n", + be32_to_cpu(rq->prog), be32_to_cpu(rq->vers), + be32_to_cpu(ept->dst_prog), + be32_to_cpu(ept->dst_vers)); + return -EINVAL; + } + hdr.dst_pid = ept->dst_pid; + hdr.dst_cid = ept->dst_cid; + IO("CALL to %08x:%d @ %d:%08x (%d bytes)\n", + be32_to_cpu(rq->prog), be32_to_cpu(rq->vers), + ept->dst_pid, ept->dst_cid, count); + } else { + /* RPC REPLY */ + /* TODO: locking */ + if (ept->reply_pid == 0xffffffff) { + printk(KERN_ERR + "rr_write: rejecting unexpected reply\n"); + return -EINVAL; + } + if (ept->reply_xid != rq->xid) { + printk(KERN_ERR + "rr_write: rejecting packet w/ bad xid\n"); + return -EINVAL; + } + + hdr.dst_pid = ept->reply_pid; + hdr.dst_cid = ept->reply_cid; + + /* consume this reply */ + ept->reply_pid = 0xffffffff; + + IO("REPLY to xid=%d @ %d:%08x (%d bytes)\n", + be32_to_cpu(rq->xid), hdr.dst_pid, hdr.dst_cid, count); + } + + r_ept = rpcrouter_lookup_remote_endpoint(hdr.dst_cid); + + if (!r_ept) { + printk(KERN_ERR + "msm_rpc_write(): No route to ept " + "[PID %x CID %x]\n", hdr.dst_pid, hdr.dst_cid); + return -EHOSTUNREACH; + } + + /* Create routing header */ + hdr.type = RPCROUTER_CTRL_CMD_DATA; + hdr.version = RPCROUTER_VERSION; + hdr.src_pid = ept->pid; + hdr.src_cid = ept->cid; + hdr.confirm_rx = 0; + hdr.size = count + sizeof(uint32_t); + + for (;;) { + prepare_to_wait(&r_ept->quota_wait, &__wait, + TASK_INTERRUPTIBLE); + spin_lock_irqsave(&r_ept->quota_lock, flags); + if (r_ept->tx_quota_cntr < RPCROUTER_DEFAULT_RX_QUOTA) + break; + if (signal_pending(current) && + (!(ept->flags & MSM_RPC_UNINTERRUPTIBLE))) + break; + spin_unlock_irqrestore(&r_ept->quota_lock, flags); + schedule(); + } + finish_wait(&r_ept->quota_wait, &__wait); + + if (signal_pending(current) && + (!(ept->flags & MSM_RPC_UNINTERRUPTIBLE))) { + spin_unlock_irqrestore(&r_ept->quota_lock, flags); + return -ERESTARTSYS; + } + r_ept->tx_quota_cntr++; + if (r_ept->tx_quota_cntr == RPCROUTER_DEFAULT_RX_QUOTA) + hdr.confirm_rx = 1; + + /* bump pacmark while interrupts disabled to avoid race + * probably should be atomic op instead + */ + pacmark = PACMARK(count, ++next_pacmarkid, 1); + + spin_unlock_irqrestore(&r_ept->quota_lock, flags); + + spin_lock_irqsave(&smd_lock, flags); + + needed = sizeof(hdr) + hdr.size; + while (smd_write_avail(smd_channel) < needed) { + spin_unlock_irqrestore(&smd_lock, flags); + msleep(250); + spin_lock_irqsave(&smd_lock, flags); + } + + /* TODO: deal with full fifo */ + smd_write(smd_channel, &hdr, sizeof(hdr)); + smd_write(smd_channel, &pacmark, sizeof(pacmark)); + smd_write(smd_channel, buffer, count); + + spin_unlock_irqrestore(&smd_lock, flags); + + return count; +} + +/* + * NOTE: It is the responsibility of the caller to kfree buffer + */ +int msm_rpc_read(struct msm_rpc_endpoint *ept, void **buffer, + unsigned user_len, long timeout) +{ + struct rr_fragment *frag, *next; + char *buf; + int rc; + + rc = __msm_rpc_read(ept, &frag, user_len, timeout); + if (rc <= 0) + return rc; + + /* single-fragment messages conveniently can be + * returned as-is (the buffer is at the front) + */ + if (frag->next == 0) { + *buffer = (void*) frag; + return rc; + } + + /* multi-fragment messages, we have to do it the + * hard way, which is rather disgusting right now + */ + buf = rr_malloc(rc); + *buffer = buf; + + while (frag != NULL) { + memcpy(buf, frag->data, frag->length); + next = frag->next; + buf += frag->length; + kfree(frag); + frag = next; + } + + return rc; +} + +int msm_rpc_call(struct msm_rpc_endpoint *ept, uint32_t proc, + void *_request, int request_size, + long timeout) +{ + return msm_rpc_call_reply(ept, proc, + _request, request_size, + NULL, 0, timeout); +} + +int msm_rpc_call_reply(struct msm_rpc_endpoint *ept, uint32_t proc, + void *_request, int request_size, + void *_reply, int reply_size, + long timeout) +{ + struct rpc_request_hdr *req = _request; + struct rpc_reply_hdr *reply; + int rc; + + if (request_size < sizeof(*req)) + return -ETOOSMALL; + + if (ept->dst_pid == 0xffffffff) + return -ENOTCONN; + + memset(req, 0, sizeof(*req)); + req->xid = cpu_to_be32(atomic_add_return(1, &next_xid)); + req->rpc_vers = cpu_to_be32(2); + req->prog = ept->dst_prog; + req->vers = ept->dst_vers; + req->procedure = cpu_to_be32(proc); + + rc = msm_rpc_write(ept, req, request_size); + if (rc < 0) + return rc; + + for (;;) { + rc = msm_rpc_read(ept, (void*) &reply, -1, timeout); + if (rc < 0) + return rc; + if (rc < (3 * sizeof(uint32_t))) { + rc = -EIO; + break; + } + /* we should not get CALL packets -- ignore them */ + if (reply->type == 0) { + kfree(reply); + continue; + } + /* If an earlier call timed out, we could get the (no + * longer wanted) reply for it. Ignore replies that + * we don't expect + */ + if (reply->xid != req->xid) { + kfree(reply); + continue; + } + if (reply->reply_stat != 0) { + rc = -EPERM; + break; + } + if (reply->data.acc_hdr.accept_stat != 0) { + rc = -EINVAL; + break; + } + if (_reply == NULL) { + rc = 0; + break; + } + if (rc > reply_size) { + rc = -ENOMEM; + } else { + memcpy(_reply, reply, rc); + } + break; + } + kfree(reply); + return rc; +} + + +static inline int ept_packet_available(struct msm_rpc_endpoint *ept) +{ + unsigned long flags; + int ret; + spin_lock_irqsave(&ept->read_q_lock, flags); + ret = !list_empty(&ept->read_q); + spin_unlock_irqrestore(&ept->read_q_lock, flags); + return ret; +} + +int __msm_rpc_read(struct msm_rpc_endpoint *ept, + struct rr_fragment **frag_ret, + unsigned len, long timeout) +{ + struct rr_packet *pkt; + struct rpc_request_hdr *rq; + DEFINE_WAIT(__wait); + unsigned long flags; + int rc; + + IO("READ on ept %p\n", ept); + + if (ept->flags & MSM_RPC_UNINTERRUPTIBLE) { + if (timeout < 0) { + wait_event(ept->wait_q, ept_packet_available(ept)); + } else { + rc = wait_event_timeout( + ept->wait_q, ept_packet_available(ept), + timeout); + if (rc == 0) + return -ETIMEDOUT; + } + } else { + if (timeout < 0) { + rc = wait_event_interruptible( + ept->wait_q, ept_packet_available(ept)); + if (rc < 0) + return rc; + } else { + rc = wait_event_interruptible_timeout( + ept->wait_q, ept_packet_available(ept), + timeout); + if (rc == 0) + return -ETIMEDOUT; + } + } + + spin_lock_irqsave(&ept->read_q_lock, flags); + if (list_empty(&ept->read_q)) { + spin_unlock_irqrestore(&ept->read_q_lock, flags); + return -EAGAIN; + } + pkt = list_first_entry(&ept->read_q, struct rr_packet, list); + if (pkt->length > len) { + spin_unlock_irqrestore(&ept->read_q_lock, flags); + return -ETOOSMALL; + } + list_del(&pkt->list); + spin_unlock_irqrestore(&ept->read_q_lock, flags); + + rc = pkt->length; + + *frag_ret = pkt->first; + rq = (void*) pkt->first->data; + if ((rc >= (sizeof(uint32_t) * 3)) && (rq->type == 0)) { + /* RPC CALL */ + if (ept->reply_pid != 0xffffffff) { + printk(KERN_WARNING + "rr_read: lost previous reply xid...\n"); + } + /* TODO: locking? */ + ept->reply_pid = pkt->hdr.src_pid; + ept->reply_cid = pkt->hdr.src_cid; + ept->reply_xid = rq->xid; + } + + kfree(pkt); + + IO("READ on ept %p (%d bytes)\n", ept, rc); + return rc; +} + +struct msm_rpc_endpoint *msm_rpc_connect(uint32_t prog, uint32_t vers, unsigned flags) +{ + struct msm_rpc_endpoint *ept; + struct rr_server *server; + + server = rpcrouter_lookup_server(prog, vers); + if (!server) + return ERR_PTR(-EHOSTUNREACH); + + ept = msm_rpc_open(); + if (IS_ERR(ept)) + return ept; + + ept->flags = flags; + ept->dst_pid = server->pid; + ept->dst_cid = server->cid; + ept->dst_prog = cpu_to_be32(prog); + ept->dst_vers = cpu_to_be32(vers); + + return ept; +} + +/* TODO: permission check? */ +int msm_rpc_register_server(struct msm_rpc_endpoint *ept, + uint32_t prog, uint32_t vers) +{ + int rc; + union rr_control_msg msg; + struct rr_server *server; + + server = rpcrouter_create_server(ept->pid, ept->cid, + prog, vers); + if (!server) + return -ENODEV; + + msg.srv.cmd = RPCROUTER_CTRL_CMD_NEW_SERVER; + msg.srv.pid = ept->pid; + msg.srv.cid = ept->cid; + msg.srv.prog = prog; + msg.srv.vers = vers; + + RR("x NEW_SERVER id=%d:%08x prog=%08x:%d\n", + ept->pid, ept->cid, prog, vers); + + rc = rpcrouter_send_control_msg(&msg); + if (rc < 0) + return rc; + + return 0; +} + +/* TODO: permission check -- disallow unreg of somebody else's server */ +int msm_rpc_unregister_server(struct msm_rpc_endpoint *ept, + uint32_t prog, uint32_t vers) +{ + struct rr_server *server; + server = rpcrouter_lookup_server(prog, vers); + + if (!server) + return -ENOENT; + rpcrouter_destroy_server(server); + return 0; +} + +static int msm_rpcrouter_probe(struct platform_device *pdev) +{ + int rc; + + /* Initialize what we need to start processing */ + INIT_LIST_HEAD(&local_endpoints); + INIT_LIST_HEAD(&remote_endpoints); + + init_waitqueue_head(&newserver_wait); + init_waitqueue_head(&smd_wait); + + rpcrouter_workqueue = create_singlethread_workqueue("rpcrouter"); + if (!rpcrouter_workqueue) + return -ENOMEM; + + rc = msm_rpcrouter_init_devices(); + if (rc < 0) + goto fail_destroy_workqueue; + + /* Open up SMD channel 2 */ + initialized = 0; + rc = smd_open("SMD_RPCCALL", &smd_channel, NULL, rpcrouter_smdnotify); + if (rc < 0) + goto fail_remove_devices; + + queue_work(rpcrouter_workqueue, &work_read_data); + return 0; + +fail_remove_devices: + msm_rpcrouter_exit_devices(); +fail_destroy_workqueue: + destroy_workqueue(rpcrouter_workqueue); + return rc; +} + +static struct platform_driver msm_smd_channel2_driver = { + .probe = msm_rpcrouter_probe, + .driver = { + .name = "SMD_RPCCALL", + .owner = THIS_MODULE, + }, +}; + +static int __init rpcrouter_init(void) +{ + return platform_driver_register(&msm_smd_channel2_driver); +} + +module_init(rpcrouter_init); +MODULE_DESCRIPTION("MSM RPC Router"); +MODULE_AUTHOR("San Mehat "); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-msm/smd_rpcrouter.h b/arch/arm/mach-msm/smd_rpcrouter.h new file mode 100644 index 000000000000..9438ca3780c9 --- /dev/null +++ b/arch/arm/mach-msm/smd_rpcrouter.h @@ -0,0 +1,190 @@ +/** arch/arm/mach-msm/smd_rpcrouter.h + * + * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2007 QUALCOMM Incorporated + * Author: San Mehat + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#ifndef _ARCH_ARM_MACH_MSM_SMD_RPCROUTER_H +#define _ARCH_ARM_MACH_MSM_SMD_RPCROUTER_H + +#include +#include +#include +#include + +#include +#include + +#include + +/* definitions for the R2R wire protcol */ + +#define RPCROUTER_VERSION 1 +#define RPCROUTER_PROCESSORS_MAX 4 +#define RPCROUTER_MSGSIZE_MAX 512 + +#define RPCROUTER_CLIENT_BCAST_ID 0xffffffff +#define RPCROUTER_ROUTER_ADDRESS 0xfffffffe + +#define RPCROUTER_PID_LOCAL 1 +#define RPCROUTER_PID_REMOTE 0 + +#define RPCROUTER_CTRL_CMD_DATA 1 +#define RPCROUTER_CTRL_CMD_HELLO 2 +#define RPCROUTER_CTRL_CMD_BYE 3 +#define RPCROUTER_CTRL_CMD_NEW_SERVER 4 +#define RPCROUTER_CTRL_CMD_REMOVE_SERVER 5 +#define RPCROUTER_CTRL_CMD_REMOVE_CLIENT 6 +#define RPCROUTER_CTRL_CMD_RESUME_TX 7 +#define RPCROUTER_CTRL_CMD_EXIT 8 + +#define RPCROUTER_DEFAULT_RX_QUOTA 5 + +union rr_control_msg { + uint32_t cmd; + struct { + uint32_t cmd; + uint32_t prog; + uint32_t vers; + uint32_t pid; + uint32_t cid; + } srv; + struct { + uint32_t cmd; + uint32_t pid; + uint32_t cid; + } cli; +}; + +struct rr_header { + uint32_t version; + uint32_t type; + uint32_t src_pid; + uint32_t src_cid; + uint32_t confirm_rx; + uint32_t size; + uint32_t dst_pid; + uint32_t dst_cid; +}; + +/* internals */ + +#define RPCROUTER_MAX_REMOTE_SERVERS 100 + +struct rr_fragment { + unsigned char data[RPCROUTER_MSGSIZE_MAX]; + uint32_t length; + struct rr_fragment *next; +}; + +struct rr_packet { + struct list_head list; + struct rr_fragment *first; + struct rr_fragment *last; + struct rr_header hdr; + uint32_t mid; + uint32_t length; +}; + +#define PACMARK_LAST(n) ((n) & 0x80000000) +#define PACMARK_MID(n) (((n) >> 16) & 0xFF) +#define PACMARK_LEN(n) ((n) & 0xFFFF) + +static inline uint32_t PACMARK(uint32_t len, uint32_t mid, uint32_t last) +{ + return (len & 0xFFFF) | ((mid & 0xFF) << 16) | ((!!last) << 31); +} + +struct rr_server { + struct list_head list; + + uint32_t pid; + uint32_t cid; + uint32_t prog; + uint32_t vers; + + dev_t device_number; + struct cdev cdev; + struct device *device; + struct rpcsvr_platform_device p_device; + char pdev_name[32]; +}; + +struct rr_remote_endpoint { + uint32_t pid; + uint32_t cid; + + int tx_quota_cntr; + spinlock_t quota_lock; + wait_queue_head_t quota_wait; + + struct list_head list; +}; + +struct msm_rpc_endpoint { + struct list_head list; + + /* incomplete packets waiting for assembly */ + struct list_head incomplete; + + /* complete packets waiting to be read */ + struct list_head read_q; + spinlock_t read_q_lock; + wait_queue_head_t wait_q; + unsigned flags; + + /* endpoint address */ + uint32_t pid; + uint32_t cid; + + /* bound remote address + * if not connected (dst_pid == 0xffffffff) RPC_CALL writes fail + * RPC_CALLs must be to the prog/vers below or they will fail + */ + uint32_t dst_pid; + uint32_t dst_cid; + uint32_t dst_prog; /* be32 */ + uint32_t dst_vers; /* be32 */ + + /* reply remote address + * if reply_pid == 0xffffffff, none available + * RPC_REPLY writes may only go to the pid/cid/xid of the + * last RPC_CALL we received. + */ + uint32_t reply_pid; + uint32_t reply_cid; + uint32_t reply_xid; /* be32 */ + + /* device node if this endpoint is accessed via userspace */ + dev_t dev; +}; + +/* shared between smd_rpcrouter*.c */ + +int __msm_rpc_read(struct msm_rpc_endpoint *ept, + struct rr_fragment **frag, + unsigned len, long timeout); + +struct msm_rpc_endpoint *msm_rpcrouter_create_local_endpoint(dev_t dev); +int msm_rpcrouter_destroy_local_endpoint(struct msm_rpc_endpoint *ept); + +int msm_rpcrouter_create_server_cdev(struct rr_server *server); +int msm_rpcrouter_create_server_pdev(struct rr_server *server); + +int msm_rpcrouter_init_devices(void); +void msm_rpcrouter_exit_devices(void); + +extern dev_t msm_rpcrouter_devno; +extern struct class *msm_rpcrouter_class; +#endif diff --git a/arch/arm/mach-msm/smd_rpcrouter_device.c b/arch/arm/mach-msm/smd_rpcrouter_device.c new file mode 100644 index 000000000000..4722e644d2d2 --- /dev/null +++ b/arch/arm/mach-msm/smd_rpcrouter_device.c @@ -0,0 +1,339 @@ +/* arch/arm/mach-msm/smd_rpcrouter_device.c + * + * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2007 QUALCOMM Incorporated + * Author: San Mehat + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 +#include + +#include "smd_rpcrouter.h" + +/* Next minor # available for a remote server */ +static int next_minor = 1; + +struct class *msm_rpcrouter_class; +dev_t msm_rpcrouter_devno; + +static struct cdev rpcrouter_cdev; +static struct device *rpcrouter_device; + +static int rpcrouter_open(struct inode *inode, struct file *filp) +{ + int rc; + struct msm_rpc_endpoint *ept; + + rc = nonseekable_open(inode, filp); + if (rc < 0) + return rc; + + ept = msm_rpcrouter_create_local_endpoint(inode->i_rdev); + if (!ept) + return -ENOMEM; + + filp->private_data = ept; + return 0; +} + +static int rpcrouter_release(struct inode *inode, struct file *filp) +{ + struct msm_rpc_endpoint *ept; + ept = (struct msm_rpc_endpoint *) filp->private_data; + + return msm_rpcrouter_destroy_local_endpoint(ept); +} + +static ssize_t rpcrouter_read(struct file *filp, char __user *buf, + size_t count, loff_t *ppos) +{ + struct msm_rpc_endpoint *ept; + struct rr_fragment *frag, *next; + int rc; + + ept = (struct msm_rpc_endpoint *) filp->private_data; + + rc = __msm_rpc_read(ept, &frag, count, -1); + if (rc < 0) + return rc; + + count = rc; + + while (frag != NULL) { + if (copy_to_user(buf, frag->data, frag->length)) { + printk(KERN_ERR + "rpcrouter: could not copy all read data to user!\n"); + rc = -EFAULT; + } + buf += frag->length; + next = frag->next; + kfree(frag); + frag = next; + } + + return rc; +} + +static ssize_t rpcrouter_write(struct file *filp, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct msm_rpc_endpoint *ept; + int rc = 0; + void *k_buffer; + + ept = (struct msm_rpc_endpoint *) filp->private_data; + + if (count > RPCROUTER_MSGSIZE_MAX) + return -EINVAL; + + k_buffer = kmalloc(count, GFP_KERNEL); + if (!k_buffer) + return -ENOMEM; + + if (copy_from_user(k_buffer, buf, count)) { + rc = -EFAULT; + goto write_out_free; + } + + rc = msm_rpc_write(ept, k_buffer, count); + if (rc < 0) + goto write_out_free; + + rc = count; +write_out_free: + kfree(k_buffer); + return rc; +} + +static unsigned int rpcrouter_poll(struct file *filp, + struct poll_table_struct *wait) +{ + struct msm_rpc_endpoint *ept; + unsigned mask = 0; + ept = (struct msm_rpc_endpoint *) filp->private_data; + + /* If there's data already in the read queue, return POLLIN. + * Else, wait for the requested amount of time, and check again. + */ + if (!list_empty(&ept->read_q)) + mask |= POLLIN; + + if (!mask) { + poll_wait(filp, &ept->wait_q, wait); + if (!list_empty(&ept->read_q)) + mask |= POLLIN; + } + + return mask; +} + +static long rpcrouter_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + struct msm_rpc_endpoint *ept; + struct rpcrouter_ioctl_server_args server_args; + int rc; + uint32_t n; + + ept = (struct msm_rpc_endpoint *) filp->private_data; + switch (cmd) { + + case RPC_ROUTER_IOCTL_GET_VERSION: + n = RPC_ROUTER_VERSION_V1; + rc = put_user(n, (unsigned int *) arg); + break; + + case RPC_ROUTER_IOCTL_GET_MTU: + /* the pacmark word reduces the actual payload + * possible per message + */ + n = RPCROUTER_MSGSIZE_MAX - sizeof(uint32_t); + rc = put_user(n, (unsigned int *) arg); + break; + + case RPC_ROUTER_IOCTL_REGISTER_SERVER: + rc = copy_from_user(&server_args, (void *) arg, + sizeof(server_args)); + if (rc < 0) + break; + msm_rpc_register_server(ept, + server_args.prog, + server_args.vers); + break; + + case RPC_ROUTER_IOCTL_UNREGISTER_SERVER: + rc = copy_from_user(&server_args, (void *) arg, + sizeof(server_args)); + if (rc < 0) + break; + + msm_rpc_unregister_server(ept, + server_args.prog, + server_args.vers); + break; + + default: + rc = -EINVAL; + break; + } + + return rc; +} + +static struct file_operations rpcrouter_server_fops = { + .owner = THIS_MODULE, + .open = rpcrouter_open, + .release = rpcrouter_release, + .read = rpcrouter_read, + .write = rpcrouter_write, + .poll = rpcrouter_poll, + .unlocked_ioctl = rpcrouter_ioctl, +}; + +static struct file_operations rpcrouter_router_fops = { + .owner = THIS_MODULE, + .open = rpcrouter_open, + .release = rpcrouter_release, + .read = rpcrouter_read, + .write = rpcrouter_write, + .poll = rpcrouter_poll, + .unlocked_ioctl = rpcrouter_ioctl, +}; + +int msm_rpcrouter_create_server_cdev(struct rr_server *server) +{ + int rc; + + if (next_minor == RPCROUTER_MAX_REMOTE_SERVERS) { + printk(KERN_ERR + "rpcrouter: Minor numbers exhausted - Increase " + "RPCROUTER_MAX_REMOTE_SERVERS\n"); + return -ENOBUFS; + } + server->device_number = + MKDEV(MAJOR(msm_rpcrouter_devno), next_minor++); + + server->device = + device_create(msm_rpcrouter_class, rpcrouter_device, + server->device_number, NULL, "%.8x:%.8x", + server->prog, server->vers); + if (IS_ERR(server->device)) { + printk(KERN_ERR + "rpcrouter: Unable to create device (%ld)\n", + PTR_ERR(server->device)); + return PTR_ERR(server->device);; + } + + cdev_init(&server->cdev, &rpcrouter_server_fops); + server->cdev.owner = THIS_MODULE; + + rc = cdev_add(&server->cdev, server->device_number, 1); + if (rc < 0) { + printk(KERN_ERR + "rpcrouter: Unable to add chrdev (%d)\n", rc); + device_destroy(msm_rpcrouter_class, server->device_number); + return rc; + } + return 0; +} + +int msm_rpcrouter_create_server_pdev(struct rr_server *server) +{ + sprintf(server->pdev_name, "rs%.8x:%.8x", + server->prog, server->vers); + + server->p_device.base.id = -1; + server->p_device.base.name = server->pdev_name; + + server->p_device.prog = server->prog; + server->p_device.vers = server->vers; + + platform_device_register(&server->p_device.base); + return 0; +} + +int msm_rpcrouter_init_devices(void) +{ + int rc; + int major; + + /* Create the device nodes */ + msm_rpcrouter_class = class_create(THIS_MODULE, "oncrpc"); + if (IS_ERR(msm_rpcrouter_class)) { + rc = -ENOMEM; + printk(KERN_ERR + "rpcrouter: failed to create oncrpc class\n"); + goto fail; + } + + rc = alloc_chrdev_region(&msm_rpcrouter_devno, 0, + RPCROUTER_MAX_REMOTE_SERVERS + 1, + "oncrpc"); + if (rc < 0) { + printk(KERN_ERR + "rpcrouter: Failed to alloc chardev region (%d)\n", rc); + goto fail_destroy_class; + } + + major = MAJOR(msm_rpcrouter_devno); + rpcrouter_device = device_create(msm_rpcrouter_class, NULL, + msm_rpcrouter_devno, NULL, "%.8x:%d", + 0, 0); + if (IS_ERR(rpcrouter_device)) { + rc = -ENOMEM; + goto fail_unregister_cdev_region; + } + + cdev_init(&rpcrouter_cdev, &rpcrouter_router_fops); + rpcrouter_cdev.owner = THIS_MODULE; + + rc = cdev_add(&rpcrouter_cdev, msm_rpcrouter_devno, 1); + if (rc < 0) + goto fail_destroy_device; + + return 0; + +fail_destroy_device: + device_destroy(msm_rpcrouter_class, msm_rpcrouter_devno); +fail_unregister_cdev_region: + unregister_chrdev_region(msm_rpcrouter_devno, + RPCROUTER_MAX_REMOTE_SERVERS + 1); +fail_destroy_class: + class_destroy(msm_rpcrouter_class); +fail: + return rc; +} + +void msm_rpcrouter_exit_devices(void) +{ + cdev_del(&rpcrouter_cdev); + device_destroy(msm_rpcrouter_class, msm_rpcrouter_devno); + unregister_chrdev_region(msm_rpcrouter_devno, + RPCROUTER_MAX_REMOTE_SERVERS + 1); + class_destroy(msm_rpcrouter_class); +} + diff --git a/arch/arm/mach-msm/smd_rpcrouter_servers.c b/arch/arm/mach-msm/smd_rpcrouter_servers.c new file mode 100644 index 000000000000..791f7908aa57 --- /dev/null +++ b/arch/arm/mach-msm/smd_rpcrouter_servers.c @@ -0,0 +1,213 @@ +/* arch/arm/mach-msm/rpc_servers.c + * + * Copyright (C) 2007 Google, Inc. + * Author: Iliyan Malchev + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 +#include "smd_rpcrouter.h" + +static struct msm_rpc_endpoint *endpoint; + +#define FLAG_REGISTERED 0x0001 + +static LIST_HEAD(rpc_server_list); +static DEFINE_MUTEX(rpc_server_list_lock); +static int rpc_servers_active; + +static void rpc_server_register(struct msm_rpc_server *server) +{ + int rc; + rc = msm_rpc_register_server(endpoint, server->prog, server->vers); + if (rc < 0) + printk(KERN_ERR "[rpcserver] error registering %p @ %08x:%d\n", + server, server->prog, server->vers); +} + +static struct msm_rpc_server *rpc_server_find(uint32_t prog, uint32_t vers) +{ + struct msm_rpc_server *server; + + mutex_lock(&rpc_server_list_lock); + list_for_each_entry(server, &rpc_server_list, list) { + if ((server->prog == prog) && (server->vers == vers)) { + mutex_unlock(&rpc_server_list_lock); + return server; + } + } + mutex_unlock(&rpc_server_list_lock); + return NULL; +} + +static void rpc_server_register_all(void) +{ + struct msm_rpc_server *server; + + mutex_lock(&rpc_server_list_lock); + list_for_each_entry(server, &rpc_server_list, list) { + if (!(server->flags & FLAG_REGISTERED)) { + rpc_server_register(server); + server->flags |= FLAG_REGISTERED; + } + } + mutex_unlock(&rpc_server_list_lock); +} + +int msm_rpc_create_server(struct msm_rpc_server *server) +{ + /* make sure we're in a sane state first */ + server->flags = 0; + INIT_LIST_HEAD(&server->list); + + mutex_lock(&rpc_server_list_lock); + list_add(&server->list, &rpc_server_list); + if (rpc_servers_active) { + rpc_server_register(server); + server->flags |= FLAG_REGISTERED; + } + mutex_unlock(&rpc_server_list_lock); + + return 0; +} + +static int rpc_send_accepted_void_reply(struct msm_rpc_endpoint *client, + uint32_t xid, uint32_t accept_status) +{ + int rc = 0; + uint8_t reply_buf[sizeof(struct rpc_reply_hdr)]; + struct rpc_reply_hdr *reply = (struct rpc_reply_hdr *)reply_buf; + + reply->xid = cpu_to_be32(xid); + reply->type = cpu_to_be32(1); /* reply */ + reply->reply_stat = cpu_to_be32(RPCMSG_REPLYSTAT_ACCEPTED); + + reply->data.acc_hdr.accept_stat = cpu_to_be32(accept_status); + reply->data.acc_hdr.verf_flavor = 0; + reply->data.acc_hdr.verf_length = 0; + + rc = msm_rpc_write(endpoint, reply_buf, sizeof(reply_buf)); + if (rc < 0) + printk(KERN_ERR + "%s: could not write response: %d\n", + __FUNCTION__, rc); + + return rc; +} + +static int rpc_servers_thread(void *data) +{ + void *buffer; + struct rpc_request_hdr *req; + struct msm_rpc_server *server; + int rc; + + for (;;) { + rc = msm_rpc_read(endpoint, &buffer, -1, -1); + if (rc < 0) { + printk(KERN_ERR "%s: could not read: %d\n", + __FUNCTION__, rc); + break; + } + req = (struct rpc_request_hdr *)buffer; + + req->type = be32_to_cpu(req->type); + req->xid = be32_to_cpu(req->xid); + req->rpc_vers = be32_to_cpu(req->rpc_vers); + req->prog = be32_to_cpu(req->prog); + req->vers = be32_to_cpu(req->vers); + req->procedure = be32_to_cpu(req->procedure); + + server = rpc_server_find(req->prog, req->vers); + + if (req->rpc_vers != 2) + continue; + if (req->type != 0) + continue; + if (!server) { + rpc_send_accepted_void_reply( + endpoint, req->xid, + RPC_ACCEPTSTAT_PROG_UNAVAIL); + continue; + } + + rc = server->rpc_call(server, req, rc); + + switch (rc) { + case 0: + rpc_send_accepted_void_reply( + endpoint, req->xid, + RPC_ACCEPTSTAT_SUCCESS); + break; + default: + rpc_send_accepted_void_reply( + endpoint, req->xid, + RPC_ACCEPTSTAT_PROG_UNAVAIL); + break; + } + + kfree(buffer); + } + + do_exit(0); +} + +static int rpcservers_probe(struct platform_device *pdev) +{ + endpoint = msm_rpc_open(); + if (IS_ERR(endpoint)) + return PTR_ERR(endpoint); + + /* we're online -- register any servers installed beforehand */ + rpc_servers_active = 1; + rpc_server_register_all(); + + /* start the kernel thread */ + kthread_run(rpc_servers_thread, NULL, "krpcserversd"); + + return 0; +} + +static struct platform_driver rpcservers_driver = { + .probe = rpcservers_probe, + .driver = { + .name = "oncrpc_router", + .owner = THIS_MODULE, + }, +}; + +static int __init rpc_servers_init(void) +{ + return platform_driver_register(&rpcservers_driver); +} + +module_init(rpc_servers_init); + +MODULE_DESCRIPTION("MSM RPC Servers"); +MODULE_AUTHOR("Iliyan Malchev "); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From a9faed91b6460afc140434129d6821e7dabe1320 Mon Sep 17 00:00:00 2001 From: Brian Swetland Date: Sun, 25 May 2008 22:05:07 -0700 Subject: [ARM] msm: provide AMSS version selection mechanism Some drivers have dependencies on AMSS versions that are not easily resolved at runtime. Provide a mechanism for selecting the AMSS version so they can be compiled appropriately. Signed-off-by: Brian Swetland --- arch/arm/mach-msm/Kconfig | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index 2e08f3a36f2b..778cf7829d60 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -1,5 +1,26 @@ if ARCH_MSM +config MSM_AMSS_VERSION + int + default 6210 if MSM_AMSS_VERSION_6210 + default 6220 if MSM_AMSS_VERSION_6220 + default 6225 if MSM_AMSS_VERSION_6225 + +choice + prompt "AMSS modem firmware version" + + default MSM_AMSS_VERSION_6225 + + config MSM_AMSS_VERSION_6210 + bool "6.2.10" + + config MSM_AMSS_VERSION_6220 + bool "6.2.20" + + config MSM_AMSS_VERSION_6225 + bool "6.2.20 + New ADSP" +endchoice + comment "MSM Board Type" depends on ARCH_MSM -- cgit v1.2.3 From 5b835cf535cb296eece27659c330642777166f68 Mon Sep 17 00:00:00 2001 From: Iliyan Malchev Date: Mon, 31 Dec 2007 13:11:28 -0800 Subject: [ARM] msm_rpc: support rpc servers - time_remote_mtoa server receives notification of time bases - dog_keepalive server to handle watchdog events Signed-off-by: Iliyan Malchev Signed-off-by: San Mehat Signed-off-by: Brian Swetland --- arch/arm/mach-msm/Kconfig | 6 +++ arch/arm/mach-msm/Makefile | 2 + arch/arm/mach-msm/rpc_server_dog_keepalive.c | 62 +++++++++++++++++++++++ arch/arm/mach-msm/rpc_server_time_remote.c | 75 ++++++++++++++++++++++++++++ 4 files changed, 145 insertions(+) create mode 100644 arch/arm/mach-msm/rpc_server_dog_keepalive.c create mode 100644 arch/arm/mach-msm/rpc_server_time_remote.c (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index 778cf7829d60..6e4e62fc0bdd 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -81,5 +81,11 @@ config MSM_ONCRPCROUTER Support for the MSM ONCRPC router for communication between the ARM9 and ARM11 +config MSM_RPCSERVERS + depends on MSM_ONCRPCROUTER + default y + bool "Kernel side RPC server bundle" + help + none endif diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index ee6da92c3063..5e3a64507a27 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -9,6 +9,8 @@ obj-$(CONFIG_MSM_SMD) += smd.o smd_tty.o smd_qmi.o obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter.o obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_device.o obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_servers.o +obj-$(CONFIG_MSM_RPCSERVERS) += rpc_server_dog_keepalive.o +obj-$(CONFIG_MSM_RPCSERVERS) += rpc_server_time_remote.o obj-$(CONFIG_MACH_TROUT) += board-dream.o diff --git a/arch/arm/mach-msm/rpc_server_dog_keepalive.c b/arch/arm/mach-msm/rpc_server_dog_keepalive.c new file mode 100644 index 000000000000..a04a380e1ff0 --- /dev/null +++ b/arch/arm/mach-msm/rpc_server_dog_keepalive.c @@ -0,0 +1,62 @@ +/* arch/arm/mach-msm/rpc_server_dog_keepalive.c + * + * Copyright (C) 2007 Google, Inc. + * Author: Iliyan Malchev + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 + +/* dog_keepalive server definitions */ + +#define DOG_KEEPALIVE_PROG 0x30000015 +#define RPC_DOG_KEEPALIVE_NULL 0 + +#if CONFIG_MSM_AMSS_VERSION==6210 +#define DOG_KEEPALIVE_VERS 0 +#define RPC_DOG_KEEPALIVE_BEACON 1 +#elif (CONFIG_MSM_AMSS_VERSION==6220) || (CONFIG_MSM_AMSS_VERSION==6225) +#define DOG_KEEPALIVE_VERS 0x731fa727 +#define RPC_DOG_KEEPALIVE_BEACON 2 +#else +#error "Unsupported AMSS version" +#endif + +static int handle_rpc_call(struct msm_rpc_server *server, + struct rpc_request_hdr *req, unsigned len) +{ + switch (req->procedure) { + case RPC_DOG_KEEPALIVE_NULL: + return 0; + case RPC_DOG_KEEPALIVE_BEACON: + printk(KERN_INFO "DOG KEEPALIVE PING\n"); + return 0; + default: + return -ENODEV; + } +} + +static struct msm_rpc_server rpc_server = { + .prog = DOG_KEEPALIVE_PROG, + .vers = DOG_KEEPALIVE_VERS, + .rpc_call = handle_rpc_call, +}; + +static int __init rpc_server_init(void) +{ + return msm_rpc_create_server(&rpc_server); +} + + +module_init(rpc_server_init); diff --git a/arch/arm/mach-msm/rpc_server_time_remote.c b/arch/arm/mach-msm/rpc_server_time_remote.c new file mode 100644 index 000000000000..a833f83dfedb --- /dev/null +++ b/arch/arm/mach-msm/rpc_server_time_remote.c @@ -0,0 +1,75 @@ +/* arch/arm/mach-msm/rpc_server_time_remote.c + * + * Copyright (C) 2007 Google, Inc. + * Author: Iliyan Malchev + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 + +/* time_remote_mtoa server definitions. */ + +#define TIME_REMOTE_MTOA_PROG 0x3000005d +#define RPC_TIME_REMOTE_MTOA_NULL 0 +#define RPC_TIME_TOD_SET_APPS_BASES 2 + +#if CONFIG_MSM_AMSS_VERSION==6210 +#define TIME_REMOTE_MTOA_VERS 0 +#elif (CONFIG_MSM_AMSS_VERSION==6220) || (CONFIG_MSM_AMSS_VERSION==6225) +#define TIME_REMOTE_MTOA_VERS 0x9202a8e4 +#else +#error "Unknown AMSS version" +#endif + +struct rpc_time_tod_set_apps_bases_args { + uint32_t tick; + uint64_t stamp; +}; + +static int handle_rpc_call(struct msm_rpc_server *server, + struct rpc_request_hdr *req, unsigned len) +{ + switch (req->procedure) { + case RPC_TIME_REMOTE_MTOA_NULL: + return 0; + + case RPC_TIME_TOD_SET_APPS_BASES: { + struct rpc_time_tod_set_apps_bases_args *args; + args = (struct rpc_time_tod_set_apps_bases_args *)(req + 1); + args->tick = be32_to_cpu(args->tick); + args->stamp = be64_to_cpu(args->stamp); + printk(KERN_INFO "RPC_TIME_TOD_SET_APPS_BASES:\n" + "\ttick = %d\n" + "\tstamp = %lld\n", + args->tick, args->stamp); + return 0; + } + default: + return -ENODEV; + } +} + +static struct msm_rpc_server rpc_server = { + .prog = TIME_REMOTE_MTOA_PROG, + .vers = TIME_REMOTE_MTOA_VERS, + .rpc_call = handle_rpc_call, +}; + +static int __init rpc_server_init(void) +{ + return msm_rpc_create_server(&rpc_server); +} + + +module_init(rpc_server_init); -- cgit v1.2.3 From 4e01cdeecbd90de58b9106bb8073e3580a7d35af Mon Sep 17 00:00:00 2001 From: Arve Hjønnevåg Date: Fri, 2 May 2008 15:30:32 -0700 Subject: [ARM] msm: Timer fixes. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Restart timer when entering idle if it appears to have missed. If the timer should have fired more than a millisecond ago, we assume that the interrupt was lost and reprogram the timer. Sync the GP timer with the other core. Get the time from the other core after low power idle. Return time until next alarm when entering idle. Add config option to select default timer. Fix shift value so multiplier does not overflow. Add workarounds for some hardware bugs. Add sched_clock. Increase min_delta_ns so that we don't get stuck if running at low speed. Limit number of alarm-already-expired messages. Signed-off-by: Brian Swetland Signed-off-by: Arve Hjønnevåg --- arch/arm/mach-msm/Kconfig | 15 +++ arch/arm/mach-msm/timer.c | 280 ++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 272 insertions(+), 23 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index 6e4e62fc0bdd..d6338806e058 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -63,6 +63,21 @@ config MACH_TROUT help Support for the HTC Dream, T-Mobile G1, Android ADP1 devices. +choice + prompt "Default Timer" + default MSM7X00A_USE_GP_TIMER + + config MSM7X00A_USE_GP_TIMER + bool "GP Timer" + help + Low resolution timer that allows power collapse from idle. + + config MSM7X00A_USE_DG_TIMER + bool "DG Timer" + help + High resolution timer. +endchoice + config MSM_SMD default y bool "MSM Shared Memory Driver (SMD)" diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c index 4855b8ca5101..915b26f225fa 100644 --- a/arch/arm/mach-msm/timer.c +++ b/arch/arm/mach-msm/timer.c @@ -25,6 +25,14 @@ #include #include +#include "smd_private.h" + +enum { + MSM_TIMER_DEBUG_SYNC = 1U << 0, +}; +static int msm_timer_debug_mask; +module_param_named(debug_mask, msm_timer_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP); + #define MSM_DGT_BASE (MSM_GPT_BASE + 0x10) #define MSM_DGT_SHIFT (5) @@ -41,6 +49,14 @@ #define GPT_HZ 32768 #define DGT_HZ 19200000 /* 19.2 MHz or 600 KHz after shift */ +static int msm_timer_ready; + +enum { + MSM_CLOCK_FLAGS_UNSTABLE_COUNT = 1U << 0, + MSM_CLOCK_FLAGS_ODD_MATCH_WRITE = 1U << 1, + MSM_CLOCK_FLAGS_DELAYED_WRITE_POST = 1U << 2, +}; + struct msm_clock { struct clock_event_device clockevent; struct clocksource clocksource; @@ -48,7 +64,20 @@ struct msm_clock { void __iomem *regbase; uint32_t freq; uint32_t shift; + uint32_t flags; + uint32_t write_delay; + uint32_t last_set; + uint32_t offset; + uint32_t alarm_vtime; + uint32_t smem_offset; + uint32_t smem_in_sync; }; +enum { + MSM_CLOCK_GPT, + MSM_CLOCK_DGT, +}; +static struct msm_clock msm_clocks[]; +static struct msm_clock *msm_active_clock; static irqreturn_t msm_timer_interrupt(int irq, void *dev_id) { @@ -57,31 +86,76 @@ static irqreturn_t msm_timer_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } +static uint32_t msm_read_timer_count(struct msm_clock *clock) +{ + uint32_t t1, t2; + int loop_count = 0; + + t1 = readl(clock->regbase + TIMER_COUNT_VAL); + if (!(clock->flags & MSM_CLOCK_FLAGS_UNSTABLE_COUNT)) + return t1; + while (1) { + t2 = readl(clock->regbase + TIMER_COUNT_VAL); + if (t1 == t2) + return t1; + if (loop_count++ > 10) { + printk(KERN_ERR "msm_read_timer_count timer %s did not" + "stabilize %u != %u\n", clock->clockevent.name, + t2, t1); + return t2; + } + t1 = t2; + } +} + static cycle_t msm_gpt_read(struct clocksource *cs) { - return readl(MSM_GPT_BASE + TIMER_COUNT_VAL); + struct msm_clock *clock = &msm_clocks[MSM_CLOCK_GPT]; + return msm_read_timer_count(clock) + clock->offset; } static cycle_t msm_dgt_read(struct clocksource *cs) { - return readl(MSM_DGT_BASE + TIMER_COUNT_VAL) >> MSM_DGT_SHIFT; + struct msm_clock *clock = &msm_clocks[MSM_CLOCK_DGT]; + return (msm_read_timer_count(clock) + clock->offset) >> MSM_DGT_SHIFT; } static int msm_timer_set_next_event(unsigned long cycles, struct clock_event_device *evt) { - struct msm_clock *clock = container_of(evt, struct msm_clock, clockevent); - uint32_t now = readl(clock->regbase + TIMER_COUNT_VAL); - uint32_t alarm = now + (cycles << clock->shift); + int i; + struct msm_clock *clock; + uint32_t now; + uint32_t alarm; int late; + clock = container_of(evt, struct msm_clock, clockevent); + now = msm_read_timer_count(clock); + alarm = now + (cycles << clock->shift); + if (clock->flags & MSM_CLOCK_FLAGS_ODD_MATCH_WRITE) + while (now == clock->last_set) + now = msm_read_timer_count(clock); writel(alarm, clock->regbase + TIMER_MATCH_VAL); - now = readl(clock->regbase + TIMER_COUNT_VAL); + if (clock->flags & MSM_CLOCK_FLAGS_DELAYED_WRITE_POST) { + /* read the counter four extra times to make sure write posts + before reading the time */ + for (i = 0; i < 4; i++) + readl(clock->regbase + TIMER_COUNT_VAL); + } + now = msm_read_timer_count(clock); + clock->last_set = now; + clock->alarm_vtime = alarm + clock->offset; late = now - alarm; - if (late >= (-2 << clock->shift) && late < DGT_HZ*5) { - printk(KERN_NOTICE "msm_timer_set_next_event(%lu) clock %s, " - "alarm already expired, now %x, alarm %x, late %d\n", - cycles, clock->clockevent.name, now, alarm, late); + if (late >= (int)(-clock->write_delay << clock->shift) && late < DGT_HZ*5) { + static int print_limit = 10; + if (print_limit > 0) { + print_limit--; + printk(KERN_NOTICE "msm_timer_set_next_event(%lu) " + "clock %s, alarm already expired, now %x, " + "alarm %x, late %d%s\n", + cycles, clock->clockevent.name, now, alarm, late, + print_limit ? "" : " stop printing"); + } return -ETIME; } return 0; @@ -90,23 +164,173 @@ static int msm_timer_set_next_event(unsigned long cycles, static void msm_timer_set_mode(enum clock_event_mode mode, struct clock_event_device *evt) { - struct msm_clock *clock = container_of(evt, struct msm_clock, clockevent); + struct msm_clock *clock; + clock = container_of(evt, struct msm_clock, clockevent); switch (mode) { case CLOCK_EVT_MODE_RESUME: case CLOCK_EVT_MODE_PERIODIC: break; case CLOCK_EVT_MODE_ONESHOT: + msm_active_clock = clock; writel(TIMER_ENABLE_EN, clock->regbase + TIMER_ENABLE); break; case CLOCK_EVT_MODE_UNUSED: case CLOCK_EVT_MODE_SHUTDOWN: + msm_active_clock = NULL; + clock->smem_in_sync = 0; writel(0, clock->regbase + TIMER_ENABLE); break; } } +static uint32_t msm_timer_sync_smem_clock(int exit_sleep) +{ + struct msm_clock *clock = &msm_clocks[MSM_CLOCK_GPT]; + uint32_t *smem_clock; + uint32_t smem_clock_val; + s64 timeout; + s64 entry_time; + uint32_t last_state; + uint32_t state; + uint32_t new_offset; + + smem_clock = smem_alloc(SMEM_SMEM_SLOW_CLOCK_VALUE, + sizeof(uint32_t)); + + if (smem_clock == NULL) { + printk(KERN_ERR "no smem clock\n"); + return 0; + } + + if (!exit_sleep && clock->smem_in_sync) + return 0; + + last_state = state = smsm_get_state(); + if (*smem_clock) { + printk(KERN_INFO "get_smem_clock: invalid start state %x " + "clock %u\n", state, *smem_clock); + smsm_change_state(SMSM_TIMEWAIT, SMSM_TIMEINIT); + entry_time = ktime_to_ns(ktime_get()); + timeout = ktime_to_ns(ktime_get()) + NSEC_PER_MSEC * 10; + while (*smem_clock != 0 && ktime_to_ns(ktime_get()) < timeout) + ; + if (*smem_clock) { + printk(KERN_INFO "get_smem_clock: timeout still " + "invalid state %x clock %u in %lld ns\n", + state, *smem_clock, + ktime_to_ns(ktime_get()) - entry_time); + return 0; + } + } + entry_time = ktime_to_ns(ktime_get()); + timeout = ktime_to_ns(ktime_get()) + NSEC_PER_MSEC * 10; + smsm_change_state(SMSM_TIMEINIT, SMSM_TIMEWAIT); + do { + smem_clock_val = *smem_clock; + state = smsm_get_state(); + if (state != last_state) { + last_state = state; + printk(KERN_INFO "get_smem_clock: state %x clock %u\n", + state, smem_clock_val); + } + } while (smem_clock_val == 0 && ktime_to_ns(ktime_get()) < timeout); + if (smem_clock_val) { + new_offset = smem_clock_val - msm_read_timer_count(clock); + writel(TIMER_ENABLE_EN, MSM_GPT_BASE + TIMER_ENABLE); + if (clock->offset + clock->smem_offset != new_offset) { + if (exit_sleep) + clock->offset = new_offset - clock->smem_offset; + else + clock->smem_offset = new_offset - clock->offset; + clock->smem_in_sync = 1; + if (msm_timer_debug_mask & MSM_TIMER_DEBUG_SYNC) + printk(KERN_INFO "get_smem_clock: state %x " + "clock %u new offset %u+%u\n", + state, smem_clock_val, + clock->offset, clock->smem_offset); + } + } else { + printk(KERN_INFO "get_smem_clock: timeout state %x clock %u " + "in %lld ns\n", state, *smem_clock, + ktime_to_ns(ktime_get()) - entry_time); + } + smsm_change_state(SMSM_TIMEWAIT, SMSM_TIMEINIT); + entry_time = ktime_to_ns(ktime_get()); + timeout = ktime_to_ns(ktime_get()) + NSEC_PER_MSEC * 10; + while (*smem_clock != 0 && ktime_to_ns(ktime_get()) < timeout) + ; + if (*smem_clock) + printk(KERN_INFO "get_smem_clock: exit timeout state %x " + "clock %u in %lld ns\n", state, *smem_clock, + ktime_to_ns(ktime_get()) - entry_time); + return smem_clock_val; +} + +static void msm_timer_reactivate_alarm(struct msm_clock *clock) +{ + long alarm_delta = clock->alarm_vtime - clock->offset - + msm_read_timer_count(clock); + if (alarm_delta < (long)clock->write_delay + 4) + alarm_delta = clock->write_delay + 4; + while (msm_timer_set_next_event(alarm_delta, &clock->clockevent)) + ; +} + +int64_t msm_timer_enter_idle(void) +{ + struct msm_clock *clock = msm_active_clock; + uint32_t alarm; + uint32_t count; + int32_t delta; + + if (clock != &msm_clocks[MSM_CLOCK_GPT]) + return 0; + + msm_timer_sync_smem_clock(0); + + count = msm_read_timer_count(clock); + alarm = readl(clock->regbase + TIMER_MATCH_VAL); + delta = alarm - count; + if (delta <= -(int32_t)((clock->freq << clock->shift) >> 10)) { + /* timer should have triggered 1ms ago */ + printk(KERN_ERR "msm_timer_enter_idle: timer late %d, " + "reprogram it\n", delta); + msm_timer_reactivate_alarm(clock); + } + if (delta <= 0) + return 0; + return cyc2ns(&clock->clocksource, (alarm - count) >> clock->shift); +} + +void msm_timer_exit_idle(int low_power) +{ + struct msm_clock *clock = msm_active_clock; + uint32_t smem_clock; + + if (!low_power || clock != &msm_clocks[MSM_CLOCK_GPT]) + return; + + if (!(readl(clock->regbase + TIMER_ENABLE) & TIMER_ENABLE_EN)) + smem_clock = msm_timer_sync_smem_clock(1); + msm_timer_reactivate_alarm(clock); +} + +unsigned long long sched_clock(void) +{ + if (msm_timer_ready) + return ktime_to_ns(ktime_get()); + else + return 0; +} + +#ifdef CONFIG_MSM7X00A_USE_GP_TIMER + #define DG_TIMER_RATING 100 +#else + #define DG_TIMER_RATING 300 +#endif + static struct msm_clock msm_clocks[] = { - { + [MSM_CLOCK_GPT] = { .clockevent = { .name = "gp_timer", .features = CLOCK_EVT_FEAT_ONESHOT, @@ -120,46 +344,54 @@ static struct msm_clock msm_clocks[] = { .rating = 200, .read = msm_gpt_read, .mask = CLOCKSOURCE_MASK(32), - .shift = 24, + .shift = 17, .flags = CLOCK_SOURCE_IS_CONTINUOUS, }, .irq = { .name = "gp_timer", - .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_TRIGGER_RISING, + .flags = IRQF_DISABLED | IRQF_TIMER | + IRQF_TRIGGER_RISING, .handler = msm_timer_interrupt, .dev_id = &msm_clocks[0].clockevent, .irq = INT_GP_TIMER_EXP }, .regbase = MSM_GPT_BASE, - .freq = GPT_HZ + .freq = GPT_HZ, + .flags = + MSM_CLOCK_FLAGS_UNSTABLE_COUNT | + MSM_CLOCK_FLAGS_ODD_MATCH_WRITE | + MSM_CLOCK_FLAGS_DELAYED_WRITE_POST, + .write_delay = 9, }, - { + [MSM_CLOCK_DGT] = { .clockevent = { .name = "dg_timer", .features = CLOCK_EVT_FEAT_ONESHOT, .shift = 32 + MSM_DGT_SHIFT, - .rating = 300, + .rating = DG_TIMER_RATING, .set_next_event = msm_timer_set_next_event, .set_mode = msm_timer_set_mode, }, .clocksource = { .name = "dg_timer", - .rating = 300, + .rating = DG_TIMER_RATING, .read = msm_dgt_read, - .mask = CLOCKSOURCE_MASK((32 - MSM_DGT_SHIFT)), + .mask = CLOCKSOURCE_MASK((32-MSM_DGT_SHIFT)), .shift = 24 - MSM_DGT_SHIFT, .flags = CLOCK_SOURCE_IS_CONTINUOUS, }, .irq = { .name = "dg_timer", - .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_TRIGGER_RISING, + .flags = IRQF_DISABLED | IRQF_TIMER | + IRQF_TRIGGER_RISING, .handler = msm_timer_interrupt, .dev_id = &msm_clocks[1].clockevent, .irq = INT_DEBUG_TIMER_EXP }, .regbase = MSM_DGT_BASE, .freq = DGT_HZ >> MSM_DGT_SHIFT, - .shift = MSM_DGT_SHIFT + .shift = MSM_DGT_SHIFT, + .write_delay = 2, } }; @@ -180,8 +412,9 @@ static void __init msm_timer_init(void) /* allow at least 10 seconds to notice that the timer wrapped */ ce->max_delta_ns = clockevent_delta2ns(0xf0000000 >> clock->shift, ce); - /* 4 gets rounded down to 3 */ - ce->min_delta_ns = clockevent_delta2ns(4, ce); + /* ticks gets rounded down by one */ + ce->min_delta_ns = + clockevent_delta2ns(clock->write_delay + 4, ce); ce->cpumask = cpumask_of(0); cs->mult = clocksource_hz2mult(clock->freq, cs->shift); @@ -196,6 +429,7 @@ static void __init msm_timer_init(void) "failed for %s\n", cs->name); clockevents_register_device(ce); + msm_timer_ready = 1; } } -- cgit v1.2.3 From ccd4d872b2071bc0b41054396324dc6498319027 Mon Sep 17 00:00:00 2001 From: Arve Hjønnevåg Date: Sat, 1 Dec 2007 18:05:26 -0800 Subject: [ARM] msm: irq: fix lockdep issues Signed-off-by: Brian Swetland --- arch/arm/mach-msm/irq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/irq.c b/arch/arm/mach-msm/irq.c index 69ca0dd79bdf..6c8d5f8caef3 100644 --- a/arch/arm/mach-msm/irq.c +++ b/arch/arm/mach-msm/irq.c @@ -101,11 +101,11 @@ static int msm_irq_set_type(unsigned int irq, unsigned int flow_type) if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) { writel(readl(treg) | b, treg); - set_irq_handler(irq, handle_edge_irq); + irq_desc[irq].handle_irq = handle_edge_irq; } if (flow_type & (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW)) { writel(readl(treg) & (~b), treg); - set_irq_handler(irq, handle_level_irq); + irq_desc[irq].handle_irq = handle_level_irq; } return 0; } -- cgit v1.2.3 From 48dfc6d56112175bda48b6aa539b18e86200a809 Mon Sep 17 00:00:00 2001 From: Arve Hjønnevåg Date: Wed, 22 Oct 2008 21:32:21 -0700 Subject: [ARM] msm: irq: Add sleep support. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add shadow registers for type and polarity and restore them in resume. Add wakeup support to main interrupt controller. Mask interrupt as soon as disable_irq is called. This is needed in some cases to allow power collapse from idle. Signed-off-by: Brian Swetland Signed-off-by: Arve Hjønnevåg --- arch/arm/mach-msm/irq.c | 304 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 297 insertions(+), 7 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/irq.c b/arch/arm/mach-msm/irq.c index 6c8d5f8caef3..299ef3012f70 100644 --- a/arch/arm/mach-msm/irq.c +++ b/arch/arm/mach-msm/irq.c @@ -26,6 +26,18 @@ #include +#include "smd_private.h" + +enum { + IRQ_DEBUG_SLEEP_INT_TRIGGER = 1U << 0, + IRQ_DEBUG_SLEEP_INT = 1U << 1, + IRQ_DEBUG_SLEEP_ABORT = 1U << 2, + IRQ_DEBUG_SLEEP = 1U << 3, + IRQ_DEBUG_SLEEP_REQUEST = 1U << 4, +}; +static int msm_irq_debug_mask; +module_param_named(debug_mask, msm_irq_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP); + #define VIC_REG(off) (MSM_VIC_BASE + (off)) #define VIC_INT_SELECT0 VIC_REG(0x0000) /* 1: FIQ, 0: IRQ */ @@ -64,6 +76,66 @@ #define VIC_VECTPRIORITY(n) VIC_REG(0x0200+((n) * 4)) #define VIC_VECTADDR(n) VIC_REG(0x0400+((n) * 4)) +static uint32_t msm_irq_smsm_wake_enable[2]; +static struct { + uint32_t int_en[2]; + uint32_t int_type; + uint32_t int_polarity; +} msm_irq_shadow_reg[2]; +static uint32_t msm_irq_idle_disable[2]; + +#define SMSM_FAKE_IRQ (0xff) +static uint8_t msm_irq_to_smsm[NR_MSM_IRQS] = { + [INT_MDDI_EXT] = 1, + [INT_MDDI_PRI] = 2, + [INT_MDDI_CLIENT] = 3, + [INT_USB_OTG] = 4, + + [INT_PWB_I2C] = 5, + [INT_SDC1_0] = 6, + [INT_SDC1_1] = 7, + [INT_SDC2_0] = 8, + + [INT_SDC2_1] = 9, + [INT_ADSP_A9_A11] = 10, + [INT_UART1] = 11, + [INT_UART2] = 12, + + [INT_UART3] = 13, + [INT_UART1_RX] = 14, + [INT_UART2_RX] = 15, + [INT_UART3_RX] = 16, + + [INT_UART1DM_IRQ] = 17, + [INT_UART1DM_RX] = 18, + [INT_KEYSENSE] = 19, + [INT_AD_HSSD] = 20, + + [INT_NAND_WR_ER_DONE] = 21, + [INT_NAND_OP_DONE] = 22, + [INT_TCHSCRN1] = 23, + [INT_TCHSCRN2] = 24, + + [INT_TCHSCRN_SSBI] = 25, + [INT_USB_HS] = 26, + [INT_UART2DM_RX] = 27, + [INT_UART2DM_IRQ] = 28, + + [INT_SDC4_1] = 29, + [INT_SDC4_0] = 30, + [INT_SDC3_1] = 31, + [INT_SDC3_0] = 32, + + /* fake wakeup interrupts */ + [INT_GPIO_GROUP1] = SMSM_FAKE_IRQ, + [INT_GPIO_GROUP2] = SMSM_FAKE_IRQ, + [INT_A9_M2A_0] = SMSM_FAKE_IRQ, + [INT_A9_M2A_1] = SMSM_FAKE_IRQ, + [INT_A9_M2A_5] = SMSM_FAKE_IRQ, + [INT_GP_TIMER_EXP] = SMSM_FAKE_IRQ, + [INT_DEBUG_TIMER_EXP] = SMSM_FAKE_IRQ, +}; + static void msm_irq_ack(unsigned int irq) { void __iomem *reg = VIC_INT_CLEAR0 + ((irq & 32) ? 4 : 0); @@ -74,44 +146,262 @@ static void msm_irq_ack(unsigned int irq) static void msm_irq_mask(unsigned int irq) { void __iomem *reg = VIC_INT_ENCLEAR0 + ((irq & 32) ? 4 : 0); - writel(1 << (irq & 31), reg); + unsigned index = (irq >> 5) & 1; + uint32_t mask = 1UL << (irq & 31); + int smsm_irq = msm_irq_to_smsm[irq]; + + msm_irq_shadow_reg[index].int_en[0] &= ~mask; + writel(mask, reg); + if (smsm_irq == 0) + msm_irq_idle_disable[index] &= ~mask; + else { + mask = 1UL << (smsm_irq - 1); + msm_irq_smsm_wake_enable[0] &= ~mask; + } } static void msm_irq_unmask(unsigned int irq) { void __iomem *reg = VIC_INT_ENSET0 + ((irq & 32) ? 4 : 0); - writel(1 << (irq & 31), reg); + unsigned index = (irq >> 5) & 1; + uint32_t mask = 1UL << (irq & 31); + int smsm_irq = msm_irq_to_smsm[irq]; + + msm_irq_shadow_reg[index].int_en[0] |= mask; + writel(mask, reg); + + if (smsm_irq == 0) + msm_irq_idle_disable[index] |= mask; + else { + mask = 1UL << (smsm_irq - 1); + msm_irq_smsm_wake_enable[0] |= mask; + } } static int msm_irq_set_wake(unsigned int irq, unsigned int on) { - return -EINVAL; + unsigned index = (irq >> 5) & 1; + uint32_t mask = 1UL << (irq & 31); + int smsm_irq = msm_irq_to_smsm[irq]; + + if (smsm_irq == 0) { + printk(KERN_ERR "msm_irq_set_wake: bad wakeup irq %d\n", irq); + return -EINVAL; + } + if (on) + msm_irq_shadow_reg[index].int_en[1] |= mask; + else + msm_irq_shadow_reg[index].int_en[1] &= ~mask; + + if (smsm_irq == SMSM_FAKE_IRQ) + return 0; + + mask = 1UL << (smsm_irq - 1); + if (on) + msm_irq_smsm_wake_enable[1] |= mask; + else + msm_irq_smsm_wake_enable[1] &= ~mask; + return 0; } static int msm_irq_set_type(unsigned int irq, unsigned int flow_type) { void __iomem *treg = VIC_INT_TYPE0 + ((irq & 32) ? 4 : 0); void __iomem *preg = VIC_INT_POLARITY0 + ((irq & 32) ? 4 : 0); + unsigned index = (irq >> 5) & 1; int b = 1 << (irq & 31); + uint32_t polarity; + uint32_t type; + polarity = msm_irq_shadow_reg[index].int_polarity; if (flow_type & (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_LOW)) - writel(readl(preg) | b, preg); + polarity |= b; if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_HIGH)) - writel(readl(preg) & (~b), preg); + polarity &= ~b; + writel(polarity, preg); + msm_irq_shadow_reg[index].int_polarity = polarity; + type = msm_irq_shadow_reg[index].int_type; if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) { - writel(readl(treg) | b, treg); + type |= b; irq_desc[irq].handle_irq = handle_edge_irq; } if (flow_type & (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW)) { - writel(readl(treg) & (~b), treg); + type &= ~b; irq_desc[irq].handle_irq = handle_level_irq; } + writel(type, treg); + msm_irq_shadow_reg[index].int_type = type; return 0; } +int msm_irq_pending(void) +{ + return readl(VIC_IRQ_STATUS0) || readl(VIC_IRQ_STATUS1); +} + +int msm_irq_idle_sleep_allowed(void) +{ + if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP_REQUEST) + printk(KERN_INFO "msm_irq_idle_sleep_allowed: disable %x %x\n", + msm_irq_idle_disable[0], msm_irq_idle_disable[1]); + return !(msm_irq_idle_disable[0] || msm_irq_idle_disable[1]); +} + +/* If arm9_wake is set: pass control to the other core. + * If from_idle is not set: disable non-wakeup interrupts. + */ +void msm_irq_enter_sleep1(bool arm9_wake, int from_idle) +{ + struct smsm_interrupt_info int_info; + if (arm9_wake) { + int_info.aArm_en_mask = msm_irq_smsm_wake_enable[!from_idle]; + int_info.aArm_interrupts_pending = 0; + smsm_set_interrupt_info(&int_info); + } +} + +int msm_irq_enter_sleep2(bool arm9_wake, int from_idle) +{ + int limit = 10; + uint32_t pending0, pending1; + + if (from_idle && !arm9_wake) + return 0; + + /* edge triggered interrupt may get lost if this mode is used */ + WARN_ON_ONCE(!arm9_wake && !from_idle); + + if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP) + printk(KERN_INFO "msm_irq_enter_sleep change irq, pend %x %x\n", + readl(VIC_IRQ_STATUS0), readl(VIC_IRQ_STATUS1)); + pending0 = readl(VIC_IRQ_STATUS0); + pending1 = readl(VIC_IRQ_STATUS1); + pending0 &= msm_irq_shadow_reg[0].int_en[!from_idle]; + /* Clear INT_A9_M2A_5 since requesting sleep triggers it */ + pending0 &= ~(1U << INT_A9_M2A_5); + pending1 &= msm_irq_shadow_reg[1].int_en[!from_idle]; + if (pending0 || pending1) { + if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP_ABORT) + printk(KERN_INFO "msm_irq_enter_sleep2 abort %x %x\n", + pending0, pending1); + return -EAGAIN; + } + + writel(0, VIC_INT_EN0); + writel(0, VIC_INT_EN1); + + while (limit-- > 0) { + int pend_irq; + int irq = readl(VIC_IRQ_VEC_RD); + if (irq == -1) + break; + pend_irq = readl(VIC_IRQ_VEC_PEND_RD); + if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP_INT) + printk(KERN_INFO "msm_irq_enter_sleep cleared " + "int %d (%d)\n", irq, pend_irq); + } + + if (arm9_wake) { + msm_irq_set_type(INT_A9_M2A_6, IRQF_TRIGGER_RISING); + writel(1U << INT_A9_M2A_6, VIC_INT_ENSET0); + } else { + writel(msm_irq_shadow_reg[0].int_en[1], VIC_INT_ENSET0); + writel(msm_irq_shadow_reg[1].int_en[1], VIC_INT_ENSET1); + } + return 0; +} + +void msm_irq_exit_sleep1(void) +{ + struct smsm_interrupt_info *int_info; + int i; + + msm_irq_ack(INT_A9_M2A_6); + for (i = 0; i < 2; i++) { + writel(msm_irq_shadow_reg[i].int_type, VIC_INT_TYPE0 + i * 4); + writel(msm_irq_shadow_reg[i].int_polarity, VIC_INT_POLARITY0 + i * 4); + writel(msm_irq_shadow_reg[i].int_en[0], VIC_INT_EN0 + i * 4); + } + writel(1, VIC_INT_MASTEREN); + int_info = smem_alloc(SMEM_SMSM_INT_INFO, sizeof(*int_info)); + if (int_info == NULL) { + printk(KERN_ERR "msm_irq_exit_sleep \n"); + return; + } + if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP) + printk(KERN_INFO "msm_irq_exit_sleep1 %x %x %x now %x %x\n", + int_info->aArm_en_mask, + int_info->aArm_interrupts_pending, + int_info->aArm_wakeup_reason, + readl(VIC_IRQ_STATUS0), readl(VIC_IRQ_STATUS1)); +} + +void msm_irq_exit_sleep2(void) +{ + int i; + uint32_t pending; + struct smsm_interrupt_info *int_info; + int_info = smem_alloc(SMEM_SMSM_INT_INFO, sizeof(*int_info)); + if (int_info == NULL) { + printk(KERN_ERR "msm_irq_exit_sleep \n"); + return; + } + if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP) + printk(KERN_INFO "msm_irq_exit_sleep2 %x %x %x now %x %x\n", + int_info->aArm_en_mask, + int_info->aArm_interrupts_pending, + int_info->aArm_wakeup_reason, + readl(VIC_IRQ_STATUS0), readl(VIC_IRQ_STATUS1)); + pending = int_info->aArm_interrupts_pending; + for (i = 0; pending && i < ARRAY_SIZE(msm_irq_to_smsm); i++) { + unsigned reg_offset = (i & 32) ? 4 : 0; + uint32_t reg_mask = 1UL << (i & 31); + int smsm_irq = msm_irq_to_smsm[i]; + uint32_t smsm_mask; + if (smsm_irq == 0) + continue; + smsm_mask = 1U << (smsm_irq - 1); + if (!(pending & smsm_mask)) + continue; + pending &= ~smsm_mask; + if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP_INT) + printk(KERN_INFO "msm_irq_exit_sleep2: irq %d " + "still pending %x now %x %x\n", i, pending, + readl(VIC_IRQ_STATUS0), readl(VIC_IRQ_STATUS1)); +#if 0 /* debug intetrrupt trigger */ + if (readl(VIC_IRQ_STATUS0 + reg_offset) & reg_mask) + writel(reg_mask, VIC_INT_CLEAR0 + reg_offset); +#endif + if (readl(VIC_IRQ_STATUS0 + reg_offset) & reg_mask) + continue; + writel(reg_mask, VIC_SOFTINT0 + reg_offset); + if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP_INT_TRIGGER) + printk(KERN_INFO "msm_irq_exit_sleep2: irq %d need " + "trigger, now %x %x\n", i, + readl(VIC_IRQ_STATUS0), readl(VIC_IRQ_STATUS1)); + } +} + +void msm_irq_exit_sleep3(void) +{ + struct smsm_interrupt_info *int_info; + int_info = smem_alloc(SMEM_SMSM_INT_INFO, sizeof(*int_info)); + if (int_info == NULL) { + printk(KERN_ERR "msm_irq_exit_sleep \n"); + return; + } + if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP) + printk(KERN_INFO "msm_irq_exit_sleep3 %x %x %x now %x %x " + "state %x\n", int_info->aArm_en_mask, + int_info->aArm_interrupts_pending, + int_info->aArm_wakeup_reason, readl(VIC_IRQ_STATUS0), + readl(VIC_IRQ_STATUS1), smsm_get_state()); +} + static struct irq_chip msm_irq_chip = { .name = "msm", + .disable = msm_irq_mask, .ack = msm_irq_ack, .mask = msm_irq_mask, .unmask = msm_irq_unmask, -- cgit v1.2.3 From 8b246c83b7e189f20c991340259a4ce67f5a8fca Mon Sep 17 00:00:00 2001 From: "Mike A. Chan" Date: Wed, 23 Jul 2008 18:55:01 -0700 Subject: [ARM] msm: clock: Cpu clk stepping. Jump in 256mhz increments, acpu_freq_tbl has up/down fields to specify next target freq if greater than 256mhz. Less loop spinning. Signed-off-by: Mike A. Chan Signed-off-by: San Mehat --- arch/arm/mach-msm/Makefile | 1 + arch/arm/mach-msm/acpuclock.c | 438 +++++++++++++++++++++++++++++++++ arch/arm/mach-msm/acpuclock.h | 62 +++++ arch/arm/mach-msm/board-halibut.c | 9 + arch/arm/mach-msm/include/mach/board.h | 10 + 5 files changed, 520 insertions(+) create mode 100644 arch/arm/mach-msm/acpuclock.c create mode 100644 arch/arm/mach-msm/acpuclock.h (limited to 'arch') diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 5e3a64507a27..c6835d4db56f 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -2,6 +2,7 @@ obj-y += io.o idle.o irq.o timer.o dma.o obj-y += devices.o obj-y += proc_comm.o obj-y += vreg.o +obj-y += acpuclock.o obj-y += clock.o clock-7x01a.o obj-y += gpio.o generic_gpio.o diff --git a/arch/arm/mach-msm/acpuclock.c b/arch/arm/mach-msm/acpuclock.c new file mode 100644 index 000000000000..4b08125bfcef --- /dev/null +++ b/arch/arm/mach-msm/acpuclock.c @@ -0,0 +1,438 @@ +/* arch/arm/mach-msm/acpuclock.c + * + * MSM architecture clock driver + * + * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2007 QUALCOMM Incorporated + * Author: San Mehat + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 "proc_comm.h" +#include "acpuclock.h" + +#define PERF_SWITCH_DEBUG 0 +#define PERF_SWITCH_STEP_DEBUG 0 + +struct clock_state +{ + struct clkctl_acpu_speed *current_speed; + struct mutex lock; + uint32_t acpu_switch_time_us; + uint32_t max_speed_delta_khz; + uint32_t vdd_switch_time_us; + unsigned long power_collapse_khz; + unsigned long wait_for_irq_khz; +}; + +static struct clock_state drv_state = { 0 }; + +static void __init acpuclk_init(void); +static unsigned long acpuclk_get_rate(void); + +/* MSM7201A Levels 3-6 all correspond to 1.2V, level 7 corresponds to 1.325V. */ +enum { + VDD_0 = 0, + VDD_1 = 1, + VDD_2 = 2, + VDD_3 = 3, + VDD_4 = 3, + VDD_5 = 3, + VDD_6 = 3, + VDD_7 = 7, + VDD_END +}; + +/* + * ACPU speed table. Complete table is shown but certain speeds are commented + * out to optimized speed switching. Initalize loops_per_jiffy to 0. + * + * Table stepping up/down is optimized for 256mhz jumps while staying on the + * same PLL. + */ +#if (0) +static struct clkctl_acpu_speed acpu_freq_tbl[] = { + { 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, VDD_0, 0, 0, 8 }, + { 61440, ACPU_PLL_0, 4, 3, 61440, 0, VDD_0, 0, 0, 8 }, + { 81920, ACPU_PLL_0, 4, 2, 40960, 1, VDD_0, 0, 0, 8 }, + { 96000, ACPU_PLL_1, 1, 7, 48000, 1, VDD_0, 0, 0, 9 }, + { 122880, ACPU_PLL_0, 4, 1, 61440, 1, VDD_3, 0, 0, 8 }, + { 128000, ACPU_PLL_1, 1, 5, 64000, 1, VDD_3, 0, 0, 12 }, + { 176000, ACPU_PLL_2, 2, 5, 88000, 1, VDD_3, 0, 0, 11 }, + { 192000, ACPU_PLL_1, 1, 3, 64000, 2, VDD_3, 0, 0, 12 }, + { 245760, ACPU_PLL_0, 4, 0, 81920, 2, VDD_4, 0, 0, 12 }, + { 256000, ACPU_PLL_1, 1, 2, 128000, 2, VDD_5, 0, 0, 12 }, + { 264000, ACPU_PLL_2, 2, 3, 88000, 2, VDD_5, 0, 6, 13 }, + { 352000, ACPU_PLL_2, 2, 2, 88000, 3, VDD_5, 0, 6, 13 }, + { 384000, ACPU_PLL_1, 1, 1, 128000, 2, VDD_6, 0, 5, -1 }, + { 528000, ACPU_PLL_2, 2, 1, 132000, 3, VDD_7, 0, 11, -1 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0 ,0}, +}; +#else /* Table of freq we currently use. */ +static struct clkctl_acpu_speed acpu_freq_tbl[] = { + { 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, VDD_0, 0, 0, 3 }, + { 122880, ACPU_PLL_0, 4, 1, 61440, 1, VDD_3, 0, 0, 3 }, + { 128000, ACPU_PLL_1, 1, 5, 64000, 1, VDD_3, 0, 0, 4 }, + { 245760, ACPU_PLL_0, 4, 0, 81920, 2, VDD_4, 0, 0, 4 }, + { 384000, ACPU_PLL_1, 1, 1, 128000, 2, VDD_6, 0, 2, -1 }, + { 528000, ACPU_PLL_2, 2, 1, 132000, 3, VDD_7, 0, 3, -1 }, + { 0, 0, 0, 0, 0, 0, 0}, +}; +#endif + +static int pc_pll_request(unsigned id, unsigned on) +{ + int res; + on = !!on; + +#if PERF_SWITCH_DEBUG + if (on) + printk(KERN_DEBUG "Enabling PLL %d\n", id); + else + printk(KERN_DEBUG "Disabling PLL %d\n", id); +#endif + + res = msm_proc_comm(PCOM_CLKCTL_RPC_PLL_REQUEST, &id, &on); + if (res < 0) + return res; + +#if PERF_SWITCH_DEBUG + if (on) + printk(KERN_DEBUG "PLL %d enabled\n", id); + else + printk(KERN_DEBUG "PLL %d disabled\n", id); +#endif + return res; +} + + +/*---------------------------------------------------------------------------- + * ARM11 'owned' clock control + *---------------------------------------------------------------------------*/ + +unsigned long acpuclk_power_collapse(void) { + int ret = acpuclk_get_rate(); + acpuclk_set_rate(drv_state.power_collapse_khz, 1); + return ret; +} + +unsigned long acpuclk_wait_for_irq(void) { + int ret = acpuclk_get_rate(); + acpuclk_set_rate(drv_state.wait_for_irq_khz, 1); + return ret; +} + +static int acpuclk_set_vdd_level(int vdd) +{ + uint32_t current_vdd; + + current_vdd = readl(A11S_VDD_SVS_PLEVEL_ADDR) & 0x07; + +#if PERF_SWITCH_DEBUG + printk(KERN_DEBUG "acpuclock: Switching VDD from %u -> %d\n", + current_vdd, vdd); +#endif + writel((1 << 7) | (vdd << 3), A11S_VDD_SVS_PLEVEL_ADDR); + udelay(drv_state.vdd_switch_time_us); + if ((readl(A11S_VDD_SVS_PLEVEL_ADDR) & 0x7) != vdd) { +#if PERF_SWITCH_DEBUG + printk(KERN_ERR "acpuclock: VDD set failed\n"); +#endif + return -EIO; + } + +#if PERF_SWITCH_DEBUG + printk(KERN_DEBUG "acpuclock: VDD switched\n"); +#endif + return 0; +} + +/* Set proper dividers for the given clock speed. */ +static void acpuclk_set_div(const struct clkctl_acpu_speed *hunt_s) { + uint32_t reg_clkctl, reg_clksel, clk_div; + + /* AHB_CLK_DIV */ + clk_div = (readl(A11S_CLK_SEL_ADDR) >> 1) & 0x03; + /* + * If the new clock divider is higher than the previous, then + * program the divider before switching the clock + */ + if (hunt_s->ahbclk_div > clk_div) { + reg_clksel = readl(A11S_CLK_SEL_ADDR); + reg_clksel &= ~(0x3 << 1); + reg_clksel |= (hunt_s->ahbclk_div << 1); + writel(reg_clksel, A11S_CLK_SEL_ADDR); + } + if ((readl(A11S_CLK_SEL_ADDR) & 0x01) == 0) { + /* SRC0 */ + + /* Program clock source */ + reg_clkctl = readl(A11S_CLK_CNTL_ADDR); + reg_clkctl &= ~(0x07 << 4); + reg_clkctl |= (hunt_s->a11clk_src_sel << 4); + writel(reg_clkctl, A11S_CLK_CNTL_ADDR); + + /* Program clock divider */ + reg_clkctl = readl(A11S_CLK_CNTL_ADDR); + reg_clkctl &= ~0xf; + reg_clkctl |= hunt_s->a11clk_src_div; + writel(reg_clkctl, A11S_CLK_CNTL_ADDR); + + /* Program clock source selection */ + reg_clksel = readl(A11S_CLK_SEL_ADDR); + reg_clksel |= 1; /* CLK_SEL_SRC1NO == SRC1 */ + writel(reg_clksel, A11S_CLK_SEL_ADDR); + } else { + /* SRC1 */ + + /* Program clock source */ + reg_clkctl = readl(A11S_CLK_CNTL_ADDR); + reg_clkctl &= ~(0x07 << 12); + reg_clkctl |= (hunt_s->a11clk_src_sel << 12); + writel(reg_clkctl, A11S_CLK_CNTL_ADDR); + + /* Program clock divider */ + reg_clkctl = readl(A11S_CLK_CNTL_ADDR); + reg_clkctl &= ~(0xf << 8); + reg_clkctl |= (hunt_s->a11clk_src_div << 8); + writel(reg_clkctl, A11S_CLK_CNTL_ADDR); + + /* Program clock source selection */ + reg_clksel = readl(A11S_CLK_SEL_ADDR); + reg_clksel &= ~1; /* CLK_SEL_SRC1NO == SRC0 */ + writel(reg_clksel, A11S_CLK_SEL_ADDR); + } + + /* + * If the new clock divider is lower than the previous, then + * program the divider after switching the clock + */ + if (hunt_s->ahbclk_div < clk_div) { + reg_clksel = readl(A11S_CLK_SEL_ADDR); + reg_clksel &= ~(0x3 << 1); + reg_clksel |= (hunt_s->ahbclk_div << 1); + writel(reg_clksel, A11S_CLK_SEL_ADDR); + } +} + +int acpuclk_set_rate(unsigned long rate, int for_power_collapse) +{ + uint32_t reg_clkctl; + struct clkctl_acpu_speed *cur_s, *tgt_s, *strt_s; + int rc = 0; + + strt_s = cur_s = drv_state.current_speed; + + WARN_ONCE(cur_s == NULL, "acpuclk_set_rate: not initialized\n"); + if (cur_s == NULL) + return -ENOENT; + + if (rate == (cur_s->a11clk_khz * 1000)) + return 0; + + for (tgt_s = acpu_freq_tbl; tgt_s->a11clk_khz != 0; tgt_s++) { + if (tgt_s->a11clk_khz == (rate / 1000)) + break; + } + + if (tgt_s->a11clk_khz == 0) + return -EINVAL; + + /* Choose the highest speed speed at or below 'rate' with same PLL. */ + if (for_power_collapse && tgt_s->a11clk_khz < cur_s->a11clk_khz) { + while (tgt_s->pll != ACPU_PLL_TCXO && tgt_s->pll != cur_s->pll) + tgt_s--; + } + + if (!for_power_collapse) { + mutex_lock(&drv_state.lock); + if (strt_s->pll != tgt_s->pll && tgt_s->pll != ACPU_PLL_TCXO) { + if ((rc = pc_pll_request(tgt_s->pll, 1)) < 0) { + printk(KERN_ERR "PLL enable failed (%d)\n", rc); + goto out; + } + } + /* Increase VDD if needed. */ + if (tgt_s->vdd > cur_s->vdd) { + if ((rc = acpuclk_set_vdd_level(tgt_s->vdd)) < 0) { + printk(KERN_ERR "Unable to switch ACPU vdd\n"); + goto out; + } + } + } + + /* Set wait states for CPU inbetween frequency changes */ + reg_clkctl = readl(A11S_CLK_CNTL_ADDR); + reg_clkctl |= (100 << 16); /* set WT_ST_CNT */ + writel(reg_clkctl, A11S_CLK_CNTL_ADDR); + +#if PERF_SWITCH_DEBUG + printk(KERN_INFO "acpuclock: Switching from ACPU rate %u -> %u\n", + strt_s->a11clk_khz * 1000, tgt_s->a11clk_khz * 1000); +#endif + + while (cur_s != tgt_s) { + /* + * Always jump to target freq if within 256mhz, regulardless of + * PLL. If differnece is greater, use the predefinied + * steppings in the table. + */ + int d = abs((int)(cur_s->a11clk_khz - tgt_s->a11clk_khz)); + if (d > drv_state.max_speed_delta_khz) { + /* Step up or down depending on target vs current. */ + int clk_index = tgt_s->a11clk_khz > cur_s->a11clk_khz ? + cur_s->up : cur_s->down; + if (clk_index < 0) { /* This should not happen. */ + printk(KERN_ERR "cur:%u target: %u\n", + cur_s->a11clk_khz, tgt_s->a11clk_khz); + rc = -EINVAL; + goto out; + } + cur_s = &acpu_freq_tbl[clk_index]; + } else { + cur_s = tgt_s; + } +#if PERF_SWITCH_STEP_DEBUG + printk(KERN_DEBUG "%s: STEP khz = %u, pll = %d\n", + __FUNCTION__, cur_s->a11clk_khz, cur_s->pll); +#endif + acpuclk_set_div(cur_s); + drv_state.current_speed = cur_s; + /* Re-adjust lpj for the new clock speed. */ + loops_per_jiffy = cur_s->lpj; + udelay(drv_state.acpu_switch_time_us); + } + + + /* Nothing else to do for power collapse. */ + if (for_power_collapse) + return 0; + + /* Disable PLL we are not using anymore. */ + if (strt_s->pll != tgt_s->pll && tgt_s->pll != ACPU_PLL_TCXO) { + if ((rc = pc_pll_request(strt_s->pll, 0)) < 0) { + printk(KERN_ERR "PLL disable failed (%d)\n", rc); + goto out; + } + } + + /* Drop VDD level if we can. */ + if (tgt_s->vdd < strt_s->vdd) { + if (acpuclk_set_vdd_level(tgt_s->vdd) < 0) + printk(KERN_ERR "acpuclock: Unable to drop ACPU vdd\n"); + } + +#if PERF_SWITCH_DEBUG + printk(KERN_DEBUG "%s: ACPU speed change complete\n", __FUNCTION__); +#endif +out: + if (!for_power_collapse) + mutex_unlock(&drv_state.lock); + return rc; +} + +static void __init acpuclk_init(void) +{ + struct clkctl_acpu_speed *speed; + uint32_t div, sel, current_vdd; + + /* + * Determine the rate of ACPU clock + */ + + if (!(readl(A11S_CLK_SEL_ADDR) & 0x01)) { /* CLK_SEL_SRC1N0 */ + /* CLK_SRC0_SEL */ + sel = (readl(A11S_CLK_CNTL_ADDR) >> 12) & 0x7; + /* CLK_SRC0_DIV */ + div = (readl(A11S_CLK_CNTL_ADDR) >> 8) & 0x0f; + } else { + /* CLK_SRC1_SEL */ + sel = (readl(A11S_CLK_CNTL_ADDR) >> 4) & 0x07; + /* CLK_SRC1_DIV */ + div = readl(A11S_CLK_CNTL_ADDR) & 0x0f; + } + + for (speed = acpu_freq_tbl; speed->a11clk_khz != 0; speed++) { + if (speed->a11clk_src_sel == sel + && (speed->a11clk_src_div == div)) + break; + } + if (speed->a11clk_khz == 0) { + printk(KERN_WARNING "Warning - ACPU clock reports invalid speed\n"); + return; + } + + drv_state.current_speed = speed; + + printk(KERN_INFO "ACPU running at %d KHz\n", speed->a11clk_khz); + /* + * Ensure that the current freq is okay at this VDD. Earlier + * versions of the bootloader would not update VDD properly. + */ + current_vdd = readl(A11S_VDD_SVS_PLEVEL_ADDR) & 0x07; + if (speed->vdd != current_vdd) + printk(KERN_WARNING "WARNING - Bad VDD (%d != %d) for this freq\n", + current_vdd, speed->vdd); +} + +static unsigned long acpuclk_get_rate(void) +{ + WARN_ONCE(drv_state.current_speed == NULL, + "acpuclk_get_rate: not initialized\n"); + if (drv_state.current_speed) + return drv_state.current_speed->a11clk_khz * 1000; + else + return 0; +} + +/*---------------------------------------------------------------------------- + * Clock driver initialization + *---------------------------------------------------------------------------*/ + +/* Initalize the lpj field in the acpu_freq_tbl. */ +static void __init lpj_init(void) +{ + int i; + const struct clkctl_acpu_speed *base_clk = drv_state.current_speed; + for (i = 0; acpu_freq_tbl[i].a11clk_khz; i++) { + acpu_freq_tbl[i].lpj = cpufreq_scale(loops_per_jiffy, + base_clk->a11clk_khz, + acpu_freq_tbl[i].a11clk_khz); + } +} + +void __init msm_acpu_clock_init(struct msm_acpu_clock_platform_data *clkdata) +{ + pr_info("acpu_clock_init()\n"); + + mutex_init(&drv_state.lock); + drv_state.acpu_switch_time_us = clkdata->acpu_switch_time_us; + drv_state.max_speed_delta_khz = clkdata->max_speed_delta_khz; + drv_state.vdd_switch_time_us = clkdata->vdd_switch_time_us; + drv_state.power_collapse_khz = clkdata->power_collapse_khz; + drv_state.wait_for_irq_khz = clkdata->wait_for_irq_khz; + acpuclk_init(); + lpj_init(); +} diff --git a/arch/arm/mach-msm/acpuclock.h b/arch/arm/mach-msm/acpuclock.h new file mode 100644 index 000000000000..8b213634576f --- /dev/null +++ b/arch/arm/mach-msm/acpuclock.h @@ -0,0 +1,62 @@ +/* arch/arm/mach-msm/acpuclock.h + * + * MSM architecture clock driver header + * + * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2007 QUALCOMM Incorporated + * Author: San Mehat + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#ifndef __ARCH_ARM_MACH_MSM_CLOCK_H +#define __ARCH_ARM_MACH_MSM_CLOCK_H + +#include + + +#define A11S_CLK_CNTL_ADDR (MSM_CSR_BASE + 0x100) +#define A11S_CLK_SEL_ADDR (MSM_CSR_BASE + 0x104) +#define A11S_VDD_SVS_PLEVEL_ADDR (MSM_CSR_BASE + 0x124) + +/* + * ARM11 clock configuration for specific ACPU speeds + */ + +#define ACPU_PLL_TCXO -1 +#define ACPU_PLL_0 0 +#define ACPU_PLL_1 1 +#define ACPU_PLL_2 2 +#define ACPU_PLL_3 3 + +struct clkctl_acpu_speed +{ + unsigned int a11clk_khz; + int pll; + unsigned int a11clk_src_sel; + unsigned int a11clk_src_div; + unsigned int ahbclk_khz; + unsigned int ahbclk_div; + int vdd; + unsigned long lpj; /* loops_per_jiffy */ +/* Index in acpu_freq_tbl[] for steppings. */ + short down; + short up; +}; + + +int acpuclk_set_rate(unsigned long rate, int for_power_collapse); +unsigned long acpuclk_wait_for_irq(void); +unsigned long acpuclk_power_collapse(void); + + +#endif + diff --git a/arch/arm/mach-msm/board-halibut.c b/arch/arm/mach-msm/board-halibut.c index e61967dde9a1..c39182f1a6ed 100644 --- a/arch/arm/mach-msm/board-halibut.c +++ b/arch/arm/mach-msm/board-halibut.c @@ -72,8 +72,17 @@ static void __init halibut_init_irq(void) msm_init_irq(); } +static struct msm_acpu_clock_platform_data halibut_clock_data = { + .acpu_switch_time_us = 50, + .max_speed_delta_khz = 256000, + .vdd_switch_time_us = 62, + .power_collapse_khz = 19200000, + .wait_for_irq_khz = 128000000, +}; + static void __init halibut_init(void) { + msm_acpu_clock_init(&halibut_clock_data); platform_add_devices(devices, ARRAY_SIZE(devices)); } diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h index 65bb79202d83..b730b4a59511 100644 --- a/arch/arm/mach-msm/include/mach/board.h +++ b/arch/arm/mach-msm/include/mach/board.h @@ -27,11 +27,21 @@ struct msm_mddi_platform_data unsigned has_vsync_irq:1; }; +struct msm_acpu_clock_platform_data +{ + uint32_t acpu_switch_time_us; + uint32_t max_speed_delta_khz; + uint32_t vdd_switch_time_us; + unsigned long power_collapse_khz; + unsigned long wait_for_irq_khz; +}; + /* common init routines for use by arch/arm/mach-msm/board-*.c */ void __init msm_add_devices(void); void __init msm_map_common_io(void); void __init msm_init_irq(void); void __init msm_clock_init(void); +void __init msm_acpu_clock_init(struct msm_acpu_clock_platform_data *); #endif -- cgit v1.2.3 From 70c0a69fe01f3b4b532fda8c8a1f67c9e12e9fbc Mon Sep 17 00:00:00 2001 From: Arve Hjønnevåg Date: Wed, 22 Oct 2008 20:46:57 -0700 Subject: [ARM] msm: power management - add wakeup support and implement suspend to ram as wait for interrupt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enter low power states from idle. Add idle statistics. If enabled /proc/msm_pm_stats reports time spent in different idle states. Spin waiting for interrupts for a while before entering a lower power state. Signed-off-by: Brian Swetland Signed-off-by: Arve Hjønnevåg --- arch/arm/mach-msm/Kconfig | 107 +++++++++ arch/arm/mach-msm/Makefile | 1 + arch/arm/mach-msm/idle.S | 71 +++++- arch/arm/mach-msm/pm.c | 552 +++++++++++++++++++++++++++++++++++++++++++++ arch/arm/mach-msm/pm.h | 31 +++ 5 files changed, 753 insertions(+), 9 deletions(-) create mode 100644 arch/arm/mach-msm/pm.c create mode 100644 arch/arm/mach-msm/pm.h (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index d6338806e058..e7ce5ac69d48 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -78,6 +78,113 @@ choice High resolution timer. endchoice +choice + prompt "Suspend sleep mode" + default MSM7X00A_SLEEP_MODE_POWER_COLLAPSE_SUSPEND + help + Allows overriding the sleep mode used. Leave at power + collapse suspend unless the arm9 image has problems. + + config MSM7X00A_SLEEP_MODE_POWER_COLLAPSE_SUSPEND + bool "Power collapse suspend" + help + Lowest sleep state. Returns through reset vector. + + config MSM7X00A_SLEEP_MODE_POWER_COLLAPSE + bool "Power collapse" + help + Sleep state that returns through reset vector. + + config MSM7X00A_SLEEP_MODE_APPS_SLEEP + bool "Apps Sleep" + + config MSM7X00A_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT + bool "Ramp down cpu clock and wait for interrupt" + + config MSM7X00A_SLEEP_WAIT_FOR_INTERRUPT + bool "Wait for interrupt" +endchoice + +config MSM7X00A_SLEEP_MODE + int + default 0 if MSM7X00A_SLEEP_MODE_POWER_COLLAPSE_SUSPEND + default 1 if MSM7X00A_SLEEP_MODE_POWER_COLLAPSE + default 2 if MSM7X00A_SLEEP_MODE_APPS_SLEEP + default 3 if MSM7X00A_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT + default 4 if MSM7X00A_SLEEP_WAIT_FOR_INTERRUPT + +choice + prompt "Idle sleep mode" + default MSM7X00A_IDLE_SLEEP_MODE_POWER_COLLAPSE + help + Allows overriding the sleep mode used from idle. Leave at power + collapse suspend unless the arm9 image has problems. + + config MSM7X00A_IDLE_SLEEP_MODE_POWER_COLLAPSE_SUSPEND + bool "Power collapse suspend" + help + Lowest sleep state. Returns through reset vector. + + config MSM7X00A_IDLE_SLEEP_MODE_POWER_COLLAPSE + bool "Power collapse" + help + Sleep state that returns through reset vector. + + config MSM7X00A_IDLE_SLEEP_MODE_APPS_SLEEP + bool "Apps Sleep" + + config MSM7X00A_IDLE_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT + bool "Ramp down cpu clock and wait for interrupt" + + config MSM7X00A_IDLE_SLEEP_WAIT_FOR_INTERRUPT + bool "Wait for interrupt" +endchoice + +config MSM7X00A_IDLE_SLEEP_MODE + int + default 0 if MSM7X00A_IDLE_SLEEP_MODE_POWER_COLLAPSE_SUSPEND + default 1 if MSM7X00A_IDLE_SLEEP_MODE_POWER_COLLAPSE + default 2 if MSM7X00A_IDLE_SLEEP_MODE_APPS_SLEEP + default 3 if MSM7X00A_IDLE_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT + default 4 if MSM7X00A_IDLE_SLEEP_WAIT_FOR_INTERRUPT + +config MSM7X00A_IDLE_SLEEP_MIN_TIME + int "Minimum idle time before sleep" + default 20000000 + help + Minimum idle time in nanoseconds before entering low power mode. + +config MSM7X00A_IDLE_SPIN_TIME + int "Idle spin time before cpu ramp down" + default 80000 + help + Spin time in nanoseconds before ramping down cpu clock and entering + any low power state. + +menuconfig MSM_IDLE_STATS + bool "Collect idle statistics" + default y + help + Collect idle statistics and export them in proc/msm_pm_stats. + +if MSM_IDLE_STATS + +config MSM_IDLE_STATS_FIRST_BUCKET + int "First bucket time" + default 62500 + help + Upper time limit in nanosconds of first bucket. + +config MSM_IDLE_STATS_BUCKET_SHIFT + int "Bucket shift" + default 2 + +config MSM_IDLE_STATS_BUCKET_COUNT + int "Bucket count" + default 10 + +endif # MSM_IDLE_STATS + config MSM_SMD default y bool "MSM Shared Memory Driver (SMD)" diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index c6835d4db56f..185c3ba2b02a 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_device.o obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_servers.o obj-$(CONFIG_MSM_RPCSERVERS) += rpc_server_dog_keepalive.o obj-$(CONFIG_MSM_RPCSERVERS) += rpc_server_time_remote.o +obj-$(CONFIG_PM) += pm.o obj-$(CONFIG_MACH_TROUT) += board-dream.o diff --git a/arch/arm/mach-msm/idle.S b/arch/arm/mach-msm/idle.S index 6a94f0527137..588eb072da82 100644 --- a/arch/arm/mach-msm/idle.S +++ b/arch/arm/mach-msm/idle.S @@ -1,9 +1,9 @@ -/* arch/arm/mach-msm/include/mach/idle.S +/* arch/arm/mach-msm/idle.S * - * Idle processing for MSM7K - work around bugs with SWFI. + * Idle processing for MSM7X00A - work around bugs with SWFI. * * Copyright (c) 2007 QUALCOMM Incorporated. - * Copyright (C) 2007 Google, Inc. + * Copyright (C) 2007 Google, Inc. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -14,23 +14,76 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - */ - + */ + #include #include -ENTRY(arch_idle) -#ifdef CONFIG_MSM7X00A_IDLE - mrc p15, 0, r1, c1, c0, 0 /* read current CR */ +ENTRY(msm_pm_collapse) + ldr r0, =saved_state + stmia r0!, {r4-r14} + mrc p15, 0, r1, c1, c0, 0 /* MMU control */ + mrc p15, 0, r2, c2, c0, 0 /* ttb */ + mrc p15, 0, r3, c3, c0, 0 /* dacr */ + mrc p15, 0, ip, c13, c0, 1 /* context ID */ + stmia r0!, {r1-r3, ip} + /* fall though */ +ENTRY(msm_arch_idle) +#if defined(CONFIG_MSM_FIQ_SUPPORT) + cpsid f +#endif + mrc p15, 0, r1, c1, c0, 0 /* read current CR */ bic r0, r1, #(1 << 2) /* clear dcache bit */ bic r0, r0, #(1 << 12) /* clear icache bit */ mcr p15, 0, r0, c1, c0, 0 /* disable d/i cache */ - mov r0, #0 /* prepare wfi value */ + mov r0, #0 /* prepare wfi value */ /* also used as return value from msm_pm_collapse */ mcr p15, 0, r0, c7, c10, 0 /* flush the cache */ mcr p15, 0, r0, c7, c10, 4 /* memory barrier */ mcr p15, 0, r0, c7, c0, 4 /* wait for interrupt */ mcr p15, 0, r1, c1, c0, 0 /* restore d/i cache */ +#if defined(CONFIG_MSM_FIQ_SUPPORT) + cpsie f +#endif + mov pc, lr + +ENTRY(msm_pm_collapse_exit) +#if 0 /* serial debug */ + mov r0, #0x80000016 + mcr p15, 0, r0, c15, c2, 4 + mov r0, #0xA9000000 + add r0, r0, #0x00A00000 /* UART1 */ + /*add r0, r0, #0x00C00000*/ /* UART3 */ + mov r1, #'A' + str r1, [r0, #0x00C] #endif + ldr r1, =saved_state_end + ldr r2, =msm_pm_collapse_exit + adr r3, msm_pm_collapse_exit + add r1, r1, r3 + sub r1, r1, r2 + ldmdb r1!, {r2-r5} + mcr p15, 0, r4, c3, c0, 0 /* dacr */ + mcr p15, 0, r3, c2, c0, 0 /* ttb */ + mcr p15, 0, r5, c13, c0, 1 /* context ID */ + ldmdb r1!, {r4-r14} + mov r0, #1 + + mcr p15, 0, r2, c1, c0, 0 /* MMU control */ mov pc, lr + nop + nop + nop + nop + nop +1: b 1b + + + .data + +saved_state: + .space 4 * 11 /* r4-14 */ + .space 4 * 4 /* cp15 */ +saved_state_end: + diff --git a/arch/arm/mach-msm/pm.c b/arch/arm/mach-msm/pm.c new file mode 100644 index 000000000000..17de9f20e408 --- /dev/null +++ b/arch/arm/mach-msm/pm.c @@ -0,0 +1,552 @@ +/* arch/arm/mach-msm/pm.c + * + * MSM Power Management Routines + * + * Copyright (C) 2007 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 "smd_private.h" +#include "acpuclock.h" +#include "proc_comm.h" +#ifdef CONFIG_HAS_WAKELOCK +#include +#endif + +enum { + MSM_PM_DEBUG_SUSPEND = 1U << 0, + MSM_PM_DEBUG_POWER_COLLAPSE = 1U << 1, + MSM_PM_DEBUG_STATE = 1U << 2, + MSM_PM_DEBUG_CLOCK = 1U << 3, + MSM_PM_DEBUG_RESET_VECTOR = 1U << 4, + MSM_PM_DEBUG_SMSM_STATE = 1U << 5, + MSM_PM_DEBUG_IDLE = 1U << 6, +}; +static int msm_pm_debug_mask; +module_param_named(debug_mask, msm_pm_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP); + +enum { + MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND, + MSM_PM_SLEEP_MODE_POWER_COLLAPSE, + MSM_PM_SLEEP_MODE_APPS_SLEEP, + MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT, + MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT, +}; +static int msm_pm_sleep_mode = CONFIG_MSM7X00A_SLEEP_MODE; +module_param_named(sleep_mode, msm_pm_sleep_mode, int, S_IRUGO | S_IWUSR | S_IWGRP); +static int msm_pm_idle_sleep_mode = CONFIG_MSM7X00A_IDLE_SLEEP_MODE; +module_param_named(idle_sleep_mode, msm_pm_idle_sleep_mode, int, S_IRUGO | S_IWUSR | S_IWGRP); +static int msm_pm_idle_sleep_min_time = CONFIG_MSM7X00A_IDLE_SLEEP_MIN_TIME; +module_param_named(idle_sleep_min_time, msm_pm_idle_sleep_min_time, int, S_IRUGO | S_IWUSR | S_IWGRP); +static int msm_pm_idle_spin_time = CONFIG_MSM7X00A_IDLE_SPIN_TIME; +module_param_named(idle_spin_time, msm_pm_idle_spin_time, int, S_IRUGO | S_IWUSR | S_IWGRP); + +#define A11S_CLK_SLEEP_EN (MSM_CSR_BASE + 0x11c) +#define A11S_PWRDOWN (MSM_CSR_BASE + 0x440) +#define A11S_STANDBY_CTL (MSM_CSR_BASE + 0x108) +#define A11RAMBACKBIAS (MSM_CSR_BASE + 0x508) + +int msm_pm_collapse(void); +int msm_arch_idle(void); +void msm_pm_collapse_exit(void); + +int64_t msm_timer_enter_idle(void); +void msm_timer_exit_idle(int low_power); +int msm_irq_idle_sleep_allowed(void); +int msm_irq_pending(void); + +static uint32_t *msm_pm_reset_vector; + +static uint32_t msm_pm_max_sleep_time; + +#ifdef CONFIG_MSM_IDLE_STATS +enum msm_pm_time_stats_id { + MSM_PM_STAT_REQUESTED_IDLE, + MSM_PM_STAT_IDLE_SPIN, + MSM_PM_STAT_IDLE_WFI, + MSM_PM_STAT_IDLE_SLEEP, + MSM_PM_STAT_IDLE_FAILED_SLEEP, + MSM_PM_STAT_NOT_IDLE, + MSM_PM_STAT_COUNT +}; + +static struct msm_pm_time_stats { + const char *name; + int bucket[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT]; + int64_t min_time[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT]; + int64_t max_time[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT]; + int count; + int64_t total_time; +} msm_pm_stats[MSM_PM_STAT_COUNT] = { + [MSM_PM_STAT_REQUESTED_IDLE].name = "idle-request", + [MSM_PM_STAT_IDLE_SPIN].name = "idle-spin", + [MSM_PM_STAT_IDLE_WFI].name = "idle-wfi", + [MSM_PM_STAT_IDLE_SLEEP].name = "idle-sleep", + [MSM_PM_STAT_IDLE_FAILED_SLEEP].name = "idle-failed-sleep", + [MSM_PM_STAT_NOT_IDLE].name = "not-idle", +}; + +static void msm_pm_add_stat(enum msm_pm_time_stats_id id, int64_t t) +{ + int i; + int64_t bt; + msm_pm_stats[id].total_time += t; + msm_pm_stats[id].count++; + bt = t; + do_div(bt, CONFIG_MSM_IDLE_STATS_FIRST_BUCKET); + if (bt < 1ULL << (CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT * + (CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1))) + i = DIV_ROUND_UP(fls((uint32_t)bt), + CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT); + else + i = CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1; + msm_pm_stats[id].bucket[i]++; + if (t < msm_pm_stats[id].min_time[i] || !msm_pm_stats[id].max_time[i]) + msm_pm_stats[id].min_time[i] = t; + if (t > msm_pm_stats[id].max_time[i]) + msm_pm_stats[id].max_time[i] = t; +} +#endif + +static int +msm_pm_wait_state(uint32_t wait_state_all_set, uint32_t wait_state_all_clear, + uint32_t wait_state_any_set, uint32_t wait_state_any_clear) +{ + int i; + uint32_t state; + + for (i = 0; i < 100000; i++) { + state = smsm_get_state(); + if (((state & wait_state_all_set) == wait_state_all_set) && + ((~state & wait_state_all_clear) == wait_state_all_clear) && + (wait_state_any_set == 0 || (state & wait_state_any_set) || + wait_state_any_clear == 0 || (state & wait_state_any_clear))) + return 0; + } + printk(KERN_ERR "msm_pm_wait_state(%x, %x, %x, %x) failed %x\n", + wait_state_all_set, wait_state_all_clear, + wait_state_any_set, wait_state_any_clear, state); + return -ETIMEDOUT; +} + +static int msm_sleep(int sleep_mode, uint32_t sleep_delay, int from_idle) +{ + uint32_t saved_vector[2]; + int collapsed; + void msm_irq_enter_sleep1(bool arm9_wake, int from_idle); + int msm_irq_enter_sleep2(bool arm9_wake, int from_idle); + void msm_irq_exit_sleep1(void); + void msm_irq_exit_sleep2(void); + void msm_irq_exit_sleep3(void); + void msm_gpio_enter_sleep(int from_idle); + void msm_gpio_exit_sleep(void); + void smd_sleep_exit(void); + uint32_t enter_state; + uint32_t enter_wait_set = 0; + uint32_t enter_wait_clear = 0; + uint32_t exit_state; + uint32_t exit_wait_clear = 0; + uint32_t exit_wait_set = 0; + unsigned long pm_saved_acpu_clk_rate = 0; + int ret; + int rv = -EINTR; + + if (msm_pm_debug_mask & MSM_PM_DEBUG_SUSPEND) + printk(KERN_INFO "msm_sleep(): mode %d delay %u idle %d\n", + sleep_mode, sleep_delay, from_idle); + + switch (sleep_mode) { + case MSM_PM_SLEEP_MODE_POWER_COLLAPSE: + enter_state = SMSM_PWRC; + enter_wait_set = SMSM_RSA; + exit_state = SMSM_WFPI; + exit_wait_clear = SMSM_RSA; + break; + case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND: + enter_state = SMSM_PWRC_SUSPEND; + enter_wait_set = SMSM_RSA; + exit_state = SMSM_WFPI; + exit_wait_clear = SMSM_RSA; + break; + case MSM_PM_SLEEP_MODE_APPS_SLEEP: + enter_state = SMSM_SLEEP; + exit_state = SMSM_SLEEPEXIT; + exit_wait_set = SMSM_SLEEPEXIT; + break; + default: + enter_state = 0; + exit_state = 0; + } + + msm_irq_enter_sleep1(!!enter_state, from_idle); + msm_gpio_enter_sleep(from_idle); + + if (enter_state) { + if (sleep_delay == 0 && sleep_mode >= MSM_PM_SLEEP_MODE_APPS_SLEEP) + sleep_delay = 192000*5; /* APPS_SLEEP does not allow infinite timeout */ + smsm_set_sleep_duration(sleep_delay); + ret = smsm_change_state(SMSM_RUN, enter_state); + if (ret) { + printk(KERN_ERR "msm_sleep(): smsm_change_state %x failed\n", enter_state); + enter_state = 0; + exit_state = 0; + } + ret = msm_pm_wait_state(enter_wait_set, enter_wait_clear, 0, 0); + if (ret) { + printk(KERN_INFO "msm_sleep(): msm_pm_wait_state failed, %x\n", smsm_get_state()); + goto enter_failed; + } + } + if (msm_irq_enter_sleep2(!!enter_state, from_idle)) + goto enter_failed; + + if (enter_state) { + writel(0x1f, A11S_CLK_SLEEP_EN); + writel(1, A11S_PWRDOWN); + + writel(0, A11S_STANDBY_CTL); + writel(0, A11RAMBACKBIAS); + + if (msm_pm_debug_mask & MSM_PM_DEBUG_STATE) + printk(KERN_INFO "msm_sleep(): enter " + "A11S_CLK_SLEEP_EN %x, A11S_PWRDOWN %x, " + "smsm_get_state %x\n", readl(A11S_CLK_SLEEP_EN), + readl(A11S_PWRDOWN), smsm_get_state()); + } + + if (sleep_mode <= MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT) { + pm_saved_acpu_clk_rate = acpuclk_power_collapse(); + if (msm_pm_debug_mask & MSM_PM_DEBUG_CLOCK) + printk(KERN_INFO "msm_sleep(): %ld enter power collapse" + "\n", pm_saved_acpu_clk_rate); + if (pm_saved_acpu_clk_rate == 0) + goto ramp_down_failed; + } + if (sleep_mode < MSM_PM_SLEEP_MODE_APPS_SLEEP) { + if (msm_pm_debug_mask & MSM_PM_DEBUG_SMSM_STATE) + smsm_print_sleep_info(); + saved_vector[0] = msm_pm_reset_vector[0]; + saved_vector[1] = msm_pm_reset_vector[1]; + msm_pm_reset_vector[0] = 0xE51FF004; /* ldr pc, 4 */ + msm_pm_reset_vector[1] = virt_to_phys(msm_pm_collapse_exit); + if (msm_pm_debug_mask & MSM_PM_DEBUG_RESET_VECTOR) + printk(KERN_INFO "msm_sleep(): vector %x %x -> " + "%x %x\n", saved_vector[0], saved_vector[1], + msm_pm_reset_vector[0], msm_pm_reset_vector[1]); + collapsed = msm_pm_collapse(); + msm_pm_reset_vector[0] = saved_vector[0]; + msm_pm_reset_vector[1] = saved_vector[1]; + if (collapsed) { + cpu_init(); + local_fiq_enable(); + rv = 0; + } + if (msm_pm_debug_mask & MSM_PM_DEBUG_POWER_COLLAPSE) + printk(KERN_INFO "msm_pm_collapse(): returned %d\n", + collapsed); + if (msm_pm_debug_mask & MSM_PM_DEBUG_SMSM_STATE) + smsm_print_sleep_info(); + } else { + msm_arch_idle(); + rv = 0; + } + + if (sleep_mode <= MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT) { + if (msm_pm_debug_mask & MSM_PM_DEBUG_CLOCK) + printk(KERN_INFO "msm_sleep(): exit power collapse %ld" + "\n", pm_saved_acpu_clk_rate); + if (acpuclk_set_rate(pm_saved_acpu_clk_rate, 1) < 0) + printk(KERN_ERR "msm_sleep(): clk_set_rate %ld " + "failed\n", pm_saved_acpu_clk_rate); + } + if (msm_pm_debug_mask & MSM_PM_DEBUG_STATE) + printk(KERN_INFO "msm_sleep(): exit A11S_CLK_SLEEP_EN %x, " + "A11S_PWRDOWN %x, smsm_get_state %x\n", + readl(A11S_CLK_SLEEP_EN), readl(A11S_PWRDOWN), + smsm_get_state()); +ramp_down_failed: + msm_irq_exit_sleep1(); +enter_failed: + if (enter_state) { + writel(0x00, A11S_CLK_SLEEP_EN); + writel(0, A11S_PWRDOWN); + smsm_change_state(enter_state, exit_state); + msm_pm_wait_state(exit_wait_set, exit_wait_clear, 0, 0); + if (msm_pm_debug_mask & MSM_PM_DEBUG_STATE) + printk(KERN_INFO "msm_sleep(): sleep exit " + "A11S_CLK_SLEEP_EN %x, A11S_PWRDOWN %x, " + "smsm_get_state %x\n", readl(A11S_CLK_SLEEP_EN), + readl(A11S_PWRDOWN), smsm_get_state()); + if (msm_pm_debug_mask & MSM_PM_DEBUG_SMSM_STATE) + smsm_print_sleep_info(); + } + msm_irq_exit_sleep2(); + if (enter_state) { + smsm_change_state(exit_state, SMSM_RUN); + msm_pm_wait_state(SMSM_RUN, 0, 0, 0); + if (msm_pm_debug_mask & MSM_PM_DEBUG_STATE) + printk(KERN_INFO "msm_sleep(): sleep exit " + "A11S_CLK_SLEEP_EN %x, A11S_PWRDOWN %x, " + "smsm_get_state %x\n", readl(A11S_CLK_SLEEP_EN), + readl(A11S_PWRDOWN), smsm_get_state()); + } + msm_irq_exit_sleep3(); + msm_gpio_exit_sleep(); + smd_sleep_exit(); + return rv; +} + +void arch_idle(void) +{ + int ret; + int spin; + int64_t sleep_time; + int low_power = 0; +#ifdef CONFIG_MSM_IDLE_STATS + int64_t t1; + static int64_t t2; + int exit_stat; +#endif + int allow_sleep = + msm_pm_idle_sleep_mode < MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT && +#ifdef CONFIG_HAS_WAKELOCK + !has_wake_lock(WAKE_LOCK_IDLE) && +#endif + msm_irq_idle_sleep_allowed(); + if (msm_pm_reset_vector == NULL) + return; + + sleep_time = msm_timer_enter_idle(); +#ifdef CONFIG_MSM_IDLE_STATS + t1 = ktime_to_ns(ktime_get()); + msm_pm_add_stat(MSM_PM_STAT_NOT_IDLE, t1 - t2); + msm_pm_add_stat(MSM_PM_STAT_REQUESTED_IDLE, sleep_time); +#endif + if (msm_pm_debug_mask & MSM_PM_DEBUG_IDLE) + printk(KERN_INFO "arch_idle: sleep time %llu, allow_sleep %d\n", + sleep_time, allow_sleep); + spin = msm_pm_idle_spin_time >> 10; + while (spin-- > 0) { + if (msm_irq_pending()) { +#ifdef CONFIG_MSM_IDLE_STATS + exit_stat = MSM_PM_STAT_IDLE_SPIN; +#endif + goto abort_idle; + } + udelay(1); + } + if (sleep_time < msm_pm_idle_sleep_min_time || !allow_sleep) { + unsigned long saved_rate; + saved_rate = acpuclk_wait_for_irq(); + if (msm_pm_debug_mask & MSM_PM_DEBUG_CLOCK) + printk(KERN_DEBUG "arch_idle: clk %ld -> swfi\n", + saved_rate); + if (saved_rate) + msm_arch_idle(); + else + while (!msm_irq_pending()) + udelay(1); + if (msm_pm_debug_mask & MSM_PM_DEBUG_CLOCK) + printk(KERN_DEBUG "msm_sleep: clk swfi -> %ld\n", + saved_rate); + if (saved_rate && acpuclk_set_rate(saved_rate, 1) < 0) + printk(KERN_ERR "msm_sleep(): clk_set_rate %ld " + "failed\n", saved_rate); +#ifdef CONFIG_MSM_IDLE_STATS + exit_stat = MSM_PM_STAT_IDLE_WFI; +#endif + } else { + low_power = 1; + do_div(sleep_time, NSEC_PER_SEC / 32768); + if (sleep_time > 0x6DDD000) { + printk("sleep_time too big %lld\n", sleep_time); + sleep_time = 0x6DDD000; + } + ret = msm_sleep(msm_pm_idle_sleep_mode, sleep_time, 1); +#ifdef CONFIG_MSM_IDLE_STATS + if (ret) + exit_stat = MSM_PM_STAT_IDLE_FAILED_SLEEP; + else + exit_stat = MSM_PM_STAT_IDLE_SLEEP; +#endif + } +abort_idle: + msm_timer_exit_idle(low_power); +#ifdef CONFIG_MSM_IDLE_STATS + t2 = ktime_to_ns(ktime_get()); + msm_pm_add_stat(exit_stat, t2 - t1); +#endif +} + +static int msm_pm_enter(suspend_state_t state) +{ + msm_sleep(msm_pm_sleep_mode, msm_pm_max_sleep_time, 0); + return 0; +} + +static struct platform_suspend_ops msm_pm_ops = { + .enter = msm_pm_enter, + .valid = suspend_valid_only_mem, +}; + +static uint32_t restart_reason = 0x776655AA; + +static void msm_pm_power_off(void) +{ + msm_proc_comm(PCOM_POWER_DOWN, 0, 0); + for (;;) ; +} + +static void msm_pm_restart(char str) +{ + /* If there's a hard reset hook and the restart_reason + * is the default, prefer that to the (slower) proc_comm + * reset command. + */ + if ((restart_reason == 0x776655AA) && msm_hw_reset_hook) { + msm_hw_reset_hook(); + } else { + msm_proc_comm(PCOM_RESET_CHIP, &restart_reason, 0); + } + for (;;) ; +} + +static int msm_reboot_call(struct notifier_block *this, unsigned long code, void *_cmd) +{ + if((code == SYS_RESTART) && _cmd) { + char *cmd = _cmd; + if (!strcmp(cmd, "bootloader")) { + restart_reason = 0x77665500; + } else if (!strcmp(cmd, "recovery")) { + restart_reason = 0x77665502; + } else if (!strcmp(cmd, "eraseflash")) { + restart_reason = 0x776655EF; + } else if (!strncmp(cmd, "oem-", 4)) { + unsigned code = simple_strtoul(cmd + 4, 0, 16) & 0xff; + restart_reason = 0x6f656d00 | code; + } else { + restart_reason = 0x77665501; + } + } + return NOTIFY_DONE; +} + +static struct notifier_block msm_reboot_notifier = +{ + .notifier_call = msm_reboot_call, +}; + +#ifdef CONFIG_MSM_IDLE_STATS +static int msm_pm_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = 0; + int i, j; + char *p = page; + + for (i = 0; i < ARRAY_SIZE(msm_pm_stats); i++) { + int64_t bucket_time; + int64_t s; + uint32_t ns; + s = msm_pm_stats[i].total_time; + ns = do_div(s, NSEC_PER_SEC); + p += sprintf(p, + "%s:\n" + " count: %7d\n" + " total_time: %lld.%09u\n", + msm_pm_stats[i].name, + msm_pm_stats[i].count, + s, ns); + bucket_time = CONFIG_MSM_IDLE_STATS_FIRST_BUCKET; + for (j = 0; j < CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1; j++) { + s = bucket_time; + ns = do_div(s, NSEC_PER_SEC); + p += sprintf(p, " <%2lld.%09u: %7d (%lld-%lld)\n", + s, ns, msm_pm_stats[i].bucket[j], + msm_pm_stats[i].min_time[j], + msm_pm_stats[i].max_time[j]); + bucket_time <<= CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT; + } + p += sprintf(p, " >=%2lld.%09u: %7d (%lld-%lld)\n", + s, ns, msm_pm_stats[i].bucket[j], + msm_pm_stats[i].min_time[j], + msm_pm_stats[i].max_time[j]); + } + *start = page + off; + + len = p - page; + if (len > off) + len -= off; + else + len = 0; + + return len < count ? len : count; +} +#endif + +void msm_pm_set_max_sleep_time(int64_t max_sleep_time_ns) +{ + int64_t max_sleep_time_bs = max_sleep_time_ns; + + /* Convert from ns -> BS units */ + do_div(max_sleep_time_bs, NSEC_PER_SEC / 32768); + + if (max_sleep_time_bs > 0x6DDD000) + msm_pm_max_sleep_time = (uint32_t) 0x6DDD000; + else + msm_pm_max_sleep_time = (uint32_t) max_sleep_time_bs; + + if (msm_pm_debug_mask & MSM_PM_DEBUG_SUSPEND) + printk("%s: Requested %lldns (%lldbs), Giving %ubs\n", + __func__, max_sleep_time_ns, + max_sleep_time_bs, + msm_pm_max_sleep_time); +} +EXPORT_SYMBOL(msm_pm_set_max_sleep_time); + +static int __init msm_pm_init(void) +{ + pm_power_off = msm_pm_power_off; + arm_pm_restart = msm_pm_restart; + msm_pm_max_sleep_time = 0; + + register_reboot_notifier(&msm_reboot_notifier); + + msm_pm_reset_vector = ioremap(0, PAGE_SIZE); + if (msm_pm_reset_vector == NULL) { + printk(KERN_ERR "msm_pm_init: failed to map reset vector\n"); + return -ENODEV; + } + + suspend_set_ops(&msm_pm_ops); + +#ifdef CONFIG_MSM_IDLE_STATS + create_proc_read_entry("msm_pm_stats", S_IRUGO, + NULL, msm_pm_read_proc, NULL); +#endif + return 0; +} + +__initcall(msm_pm_init); diff --git a/arch/arm/mach-msm/pm.h b/arch/arm/mach-msm/pm.h new file mode 100644 index 000000000000..159a7a610d75 --- /dev/null +++ b/arch/arm/mach-msm/pm.h @@ -0,0 +1,31 @@ +/* arch/arm/mach-msm/pm.h + * + * Copyright (C) 2007 Google, Inc. + * Author: San Mehat + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#ifndef __ARCH_ARM_MACH_MSM_PM_H +#define __ARCH_ARM_MACH_MSM_PM_H + +#include + +#define A11S_CLK_SLEEP_EN_ADDR MSM_CSR_BASE + 0x11c + +#define CLK_SLEEP_EN_ARM11_CORE 0x01 +#define CLK_SLEEP_EN_ARM11_AHB 0x02 +#define CLK_SLEEP_EN_ID_BRIDGE 0x04 +#define CLK_SLEEP_EN_DMA_BRIDGE 0x08 +#define CLK_SLEEP_EN_PBUS 0x10 +#define CLK_SLEEP_EN_DEBUG_TIME 0x20 +#define CLK_SLEEP_EN_GP_TIMER 0x40 +#endif -- cgit v1.2.3 From 6e61f9a20788ac7298121866e1a3a6c44ea370b9 Mon Sep 17 00:00:00 2001 From: Brian Swetland Date: Sat, 1 Dec 2007 19:54:04 -0800 Subject: [ARM] msm: pick up partition table from bootloader via private ATAG It's the wrong way to do this (according to rmk), but we've got bootloader code that's working this way, so here's support for it. Signed-off-by: Brian Swetland --- arch/arm/mach-msm/Makefile | 1 + arch/arm/mach-msm/nand_partitions.c | 87 +++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 arch/arm/mach-msm/nand_partitions.c (limited to 'arch') diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 185c3ba2b02a..9f2f89a5ec9d 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -5,6 +5,7 @@ obj-y += vreg.o obj-y += acpuclock.o obj-y += clock.o clock-7x01a.o obj-y += gpio.o generic_gpio.o +obj-y += nand_partitions.o obj-$(CONFIG_MSM_SMD) += smd.o smd_tty.o smd_qmi.o obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter.o diff --git a/arch/arm/mach-msm/nand_partitions.c b/arch/arm/mach-msm/nand_partitions.c new file mode 100644 index 000000000000..482e6958504b --- /dev/null +++ b/arch/arm/mach-msm/nand_partitions.c @@ -0,0 +1,87 @@ +/* arch/arm/mach-msm/nand_partitions.c + * + * Code to extract partition information from ATAG set up by the + * bootloader. + * + * Copyright (C) 2007 Google, Inc. + * Author: Brian Swetland + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 + +/* configuration tags specific to msm */ + +#define ATAG_MSM_PARTITION 0x4d534D70 /* MSMp */ + +struct msm_ptbl_entry +{ + char name[16]; + __u32 offset; + __u32 size; + __u32 flags; +}; + +#define MSM_MAX_PARTITIONS 8 + +static struct mtd_partition msm_nand_partitions[MSM_MAX_PARTITIONS]; +static char msm_nand_names[MSM_MAX_PARTITIONS * 16]; + +extern struct flash_platform_data msm_nand_data; + +static int __init parse_tag_msm_partition(const struct tag *tag) +{ + struct mtd_partition *ptn = msm_nand_partitions; + char *name = msm_nand_names; + struct msm_ptbl_entry *entry = (void *) &tag->u; + unsigned count, n; + + count = (tag->hdr.size - 2) / + (sizeof(struct msm_ptbl_entry) / sizeof(__u32)); + + if (count > MSM_MAX_PARTITIONS) + count = MSM_MAX_PARTITIONS; + + for (n = 0; n < count; n++) { + memcpy(name, entry->name, 15); + name[15] = 0; + + ptn->name = name; + ptn->offset = entry->offset * 64 * 2048; + ptn->size = entry->size * 64 * 2048; + + name += 16; + entry++; + ptn++; + } + + msm_nand_data.nr_parts = count; + msm_nand_data.parts = msm_nand_partitions; + + return 0; +} + +__tagtable(ATAG_MSM_PARTITION, parse_tag_msm_partition); -- cgit v1.2.3 From 00b5770d2593751128df36f88877734e0f5ac9fd Mon Sep 17 00:00:00 2001 From: Brian Swetland Date: Mon, 7 Apr 2008 17:50:22 -0700 Subject: [ARM] msm: enable installation of an FIQ handler Signed-off-by: Brian Swetland --- arch/arm/mach-msm/Kconfig | 4 ++ arch/arm/mach-msm/Makefile | 1 + arch/arm/mach-msm/fiq_glue.S | 64 +++++++++++++++++++++++++++++ arch/arm/mach-msm/include/mach/fiq.h | 32 +++++++++++++++ arch/arm/mach-msm/irq.c | 79 +++++++++++++++++++++++++++++++++++- 5 files changed, 178 insertions(+), 2 deletions(-) create mode 100644 arch/arm/mach-msm/fiq_glue.S create mode 100644 arch/arm/mach-msm/include/mach/fiq.h (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index e7ce5ac69d48..03dda24930c8 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -185,6 +185,10 @@ config MSM_IDLE_STATS_BUCKET_COUNT endif # MSM_IDLE_STATS +config MSM_FIQ_SUPPORT + default y + bool "Enable installation of an FIQ handler." + config MSM_SMD default y bool "MSM Shared Memory Driver (SMD)" diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 9f2f89a5ec9d..363b470b9c5f 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -7,6 +7,7 @@ obj-y += clock.o clock-7x01a.o obj-y += gpio.o generic_gpio.o obj-y += nand_partitions.o +obj-$(CONFIG_MSM_FIQ_SUPPORT) += fiq_glue.o obj-$(CONFIG_MSM_SMD) += smd.o smd_tty.o smd_qmi.o obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter.o obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_device.o diff --git a/arch/arm/mach-msm/fiq_glue.S b/arch/arm/mach-msm/fiq_glue.S new file mode 100644 index 000000000000..9ded61cc0de8 --- /dev/null +++ b/arch/arm/mach-msm/fiq_glue.S @@ -0,0 +1,64 @@ +/* arch/arm/mach-msm/fiq_glue.S + * + * Copyright (C) 2008 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 + + .text + + .global fiq_glue_end + +ENTRY(fiq_glue) + adr r12, fiq_glue_ctxt_addr + ldr r8, [r12] + ldmia r8, {r9, r10, sp} + + /* store pc, cpsr from previous mode */ + sub r11, lr, #4 + mrs r12, spsr + stmfd sp!, {r11-r12,lr} + + /* store r8-r14 from previous mode */ + sub sp, sp, #(7 * 4) + stmia sp, {r8-r14}^ + nop + + /* store r0-r7 from previous mode */ + stmfd sp!, {r0-r7} + + /* call func(data,regs) */ + mov r0, r10 + mov r1, sp + blx r9 + + /* restore/discard saved state */ + ldmfd sp!, {r0-r7} + add sp, sp, #(9 * 4) + ldmfd sp!, {lr} + + subs pc, lr, #4 + +fiq_glue_ctxt_addr: + .long fiq_glue_ctxt +fiq_glue_end: + +ENTRY(fiq_glue_setup) /* func, data, sp */ + ldr r3, =fiq_glue_ctxt + stmia r3, {r0-r2} + bx lr + + .data +fiq_glue_ctxt: + .long 0, 0, 0 diff --git a/arch/arm/mach-msm/include/mach/fiq.h b/arch/arm/mach-msm/include/mach/fiq.h new file mode 100644 index 000000000000..a272c890c68a --- /dev/null +++ b/arch/arm/mach-msm/include/mach/fiq.h @@ -0,0 +1,32 @@ +/* linux/include/asm-arm/arch-msm/irqs.h + * + * Copyright (C) 2008 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#ifndef __ASM_ARCH_MSM_FIQ_H +#define __ASM_ARCH_MSM_FIQ_H + +/* cause an interrupt to be an FIQ instead of a regular IRQ */ +void msm_fiq_select(int number); + +/* enable/disable an interrupt that is an FIQ (not safe from FIQ context) */ +void msm_fiq_enable(int number); +void msm_fiq_disable(int number); + +/* install an FIQ handler */ +int msm_fiq_set_handler(void (*func)(void *data, void *regs), void *data); + +/* cause an edge triggered interrupt to fire (safe from FIQ context */ +void msm_trigger_irq(int number); + +#endif diff --git a/arch/arm/mach-msm/irq.c b/arch/arm/mach-msm/irq.c index 299ef3012f70..a8f20a45432f 100644 --- a/arch/arm/mach-msm/irq.c +++ b/arch/arm/mach-msm/irq.c @@ -22,9 +22,12 @@ #include #include +#include + #include #include +#include #include "smd_private.h" @@ -81,6 +84,7 @@ static struct { uint32_t int_en[2]; uint32_t int_type; uint32_t int_polarity; + uint32_t int_select; } msm_irq_shadow_reg[2]; static uint32_t msm_irq_idle_disable[2]; @@ -322,8 +326,9 @@ void msm_irq_exit_sleep1(void) writel(msm_irq_shadow_reg[i].int_type, VIC_INT_TYPE0 + i * 4); writel(msm_irq_shadow_reg[i].int_polarity, VIC_INT_POLARITY0 + i * 4); writel(msm_irq_shadow_reg[i].int_en[0], VIC_INT_EN0 + i * 4); + writel(msm_irq_shadow_reg[i].int_select, VIC_INT_SELECT0 + i * 4); } - writel(1, VIC_INT_MASTEREN); + writel(3, VIC_INT_MASTEREN); int_info = smem_alloc(SMEM_SMSM_INT_INFO, sizeof(*int_info)); if (int_info == NULL) { printk(KERN_ERR "msm_irq_exit_sleep \n"); @@ -433,7 +438,7 @@ void __init msm_init_irq(void) writel(0, VIC_CONFIG); /* enable interrupt controller */ - writel(1, VIC_INT_MASTEREN); + writel(3, VIC_INT_MASTEREN); for (n = 0; n < NR_MSM_IRQS; n++) { set_irq_chip(n, &msm_irq_chip); @@ -441,3 +446,73 @@ void __init msm_init_irq(void) set_irq_flags(n, IRQF_VALID); } } + +#if defined(CONFIG_MSM_FIQ_SUPPORT) +void msm_trigger_irq(int irq) +{ + void __iomem *reg = VIC_SOFTINT0 + ((irq & 32) ? 4 : 0); + uint32_t mask = 1UL << (irq & 31); + writel(mask, reg); +} + +void msm_fiq_enable(int irq) +{ + unsigned long flags; + local_irq_save(flags); + msm_irq_unmask(irq); + local_irq_restore(flags); +} + +void msm_fiq_disable(int irq) +{ + unsigned long flags; + local_irq_save(flags); + msm_irq_mask(irq); + local_irq_restore(flags); +} + +void msm_fiq_select(int irq) +{ + void __iomem *reg = VIC_INT_SELECT0 + ((irq & 32) ? 4 : 0); + unsigned index = (irq >> 5) & 1; + uint32_t mask = 1UL << (irq & 31); + unsigned long flags; + + local_irq_save(flags); + msm_irq_shadow_reg[index].int_select |= mask; + writel(msm_irq_shadow_reg[index].int_select, reg); + local_irq_restore(flags); +} + +/* set_fiq_handler originally from arch/arm/kernel/fiq.c */ +static void set_fiq_handler(void *start, unsigned int length) +{ + memcpy((void *)0xffff001c, start, length); + flush_icache_range(0xffff001c, 0xffff001c + length); + if (!vectors_high()) + flush_icache_range(0x1c, 0x1c + length); +} + +extern unsigned char fiq_glue, fiq_glue_end; + +static void (*fiq_func)(void *data, void *regs); +static unsigned long long fiq_stack[256]; + +void fiq_glue_setup(void *func, void *data, void *sp); + +int msm_fiq_set_handler(void (*func)(void *data, void *regs), void *data) +{ + unsigned long flags; + int ret = -ENOMEM; + + local_irq_save(flags); + if (fiq_func == 0) { + fiq_func = func; + fiq_glue_setup(func, data, fiq_stack + 255); + set_fiq_handler(&fiq_glue, (&fiq_glue_end - &fiq_glue)); + ret = 0; + } + local_irq_restore(flags); + return ret; +} +#endif -- cgit v1.2.3 From 573f21161874e85c226126e2accbf5a382c35d3c Mon Sep 17 00:00:00 2001 From: Arve Hjønnevåg Date: Wed, 29 Oct 2008 21:45:46 -0700 Subject: [ARM] msm: halibut: Add memory configuration. --- arch/arm/mach-msm/board-halibut.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/board-halibut.c b/arch/arm/mach-msm/board-halibut.c index c39182f1a6ed..eb75c33ce132 100644 --- a/arch/arm/mach-msm/board-halibut.c +++ b/arch/arm/mach-msm/board-halibut.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -86,6 +87,15 @@ static void __init halibut_init(void) platform_add_devices(devices, ARRAY_SIZE(devices)); } +static void __init halibut_fixup(struct machine_desc *desc, struct tag *tags, + char **cmdline, struct meminfo *mi) +{ + mi->nr_banks=1; + mi->bank[0].start = PHYS_OFFSET; + mi->bank[0].node = PHYS_TO_NID(PHYS_OFFSET); + mi->bank[0].size = (101*1024*1024); +} + static void __init halibut_map_io(void) { msm_map_common_io(); @@ -94,6 +104,7 @@ static void __init halibut_map_io(void) MACHINE_START(HALIBUT, "Halibut Board (QCT SURF7200A)") .boot_params = 0x10000100, + .fixup = halibut_fixup, .map_io = halibut_map_io, .init_irq = halibut_init_irq, .init_machine = halibut_init, -- cgit v1.2.3 From c286f81b499c44061a0b1dc49b5c69d87d94f1cd Mon Sep 17 00:00:00 2001 From: "Mike A. Chan" Date: Wed, 29 Oct 2008 13:18:57 -0700 Subject: [ARM] msm: clock: Simple cpufreq scaling based on screen ON/OFF Signed-off-by: Mike A. Chan --- arch/arm/mach-msm/Kconfig | 19 +++++++++++++++++++ arch/arm/mach-msm/Makefile | 1 + arch/arm/mach-msm/cpufreq.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+) create mode 100644 arch/arm/mach-msm/cpufreq.c (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index 03dda24930c8..99c0a0151a86 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -214,4 +214,23 @@ config MSM_RPCSERVERS help none +menuconfig MSM_CPU_FREQ_SCREEN + depends on HAS_EARLYSUSPEND + default n + bool "Enable simple cpu frequency scaling" + help + Simple cpufreq scaling based on screen ON/OFF. + +if MSM_CPU_FREQ_SCREEN + +config MSM_CPU_FREQ_SCREEN_OFF + int "Screen off cpu frequency" + default 245760 + +config MSM_CPU_FREQ_SCREEN_ON + int "Screen on cpu frequency" + default 384000 + +endif # MSM_CPU_FREQ_SCREEN + endif diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 363b470b9c5f..c28c32dba410 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_servers.o obj-$(CONFIG_MSM_RPCSERVERS) += rpc_server_dog_keepalive.o obj-$(CONFIG_MSM_RPCSERVERS) += rpc_server_time_remote.o obj-$(CONFIG_PM) += pm.o +obj-$(CONFIG_MSM_CPU_FREQ_SCREEN) += cpufreq.o obj-$(CONFIG_MACH_TROUT) += board-dream.o diff --git a/arch/arm/mach-msm/cpufreq.c b/arch/arm/mach-msm/cpufreq.c new file mode 100644 index 000000000000..efa46a0c9fa5 --- /dev/null +++ b/arch/arm/mach-msm/cpufreq.c @@ -0,0 +1,43 @@ +/* arch/arm/mach-msm/cpufreq.c + * + * MSM architecture cpufreq driver + * + * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2007 QUALCOMM Incorporated + * Author: Mike A. Chan + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 "acpuclock.h" + +static void msm_early_suspend(struct early_suspend *handler) { + acpuclk_set_rate(CONFIG_MSM_CPU_FREQ_SCREEN_OFF * 1000, 0); +} + +static void msm_late_resume(struct early_suspend *handler) { + acpuclk_set_rate(CONFIG_MSM_CPU_FREQ_SCREEN_ON * 1000, 0); +} + +static struct early_suspend msm_power_suspend = { + .suspend = msm_early_suspend, + .resume = msm_late_resume, +}; + +static int __init clock_late_init(void) +{ + register_early_suspend(&msm_power_suspend); + return 0; +} + +late_initcall(clock_late_init); -- cgit v1.2.3 From 102c0436783ef246a5fe7ae6d2d75a7849fb3894 Mon Sep 17 00:00:00 2001 From: Brian Swetland Date: Mon, 7 Apr 2008 17:59:14 -0700 Subject: [ARM] msm: halibut: support fiq mode kernel debugger if configured Signed-off-by: Brian Swetland --- arch/arm/mach-msm/board-halibut.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/board-halibut.c b/arch/arm/mach-msm/board-halibut.c index eb75c33ce132..8664478dd38f 100644 --- a/arch/arm/mach-msm/board-halibut.c +++ b/arch/arm/mach-msm/board-halibut.c @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -58,7 +59,9 @@ static struct platform_device smc91x_device = { }; static struct platform_device *devices[] __initdata = { +#if !defined(CONFIG_MSM_SERIAL_DEBUGGER) &msm_device_uart3, +#endif &msm_device_smd, &msm_device_nand, &msm_device_hsusb, @@ -81,8 +84,15 @@ static struct msm_acpu_clock_platform_data halibut_clock_data = { .wait_for_irq_khz = 128000000, }; +void msm_serial_debug_init(unsigned int base, int irq, + struct device *clk_device, int signal_irq); + static void __init halibut_init(void) { +#if defined(CONFIG_MSM_SERIAL_DEBUGGER) + msm_serial_debug_init(MSM_UART3_PHYS, INT_UART3, + &msm_device_uart3.dev, 1); +#endif msm_acpu_clock_init(&halibut_clock_data); platform_add_devices(devices, ARRAY_SIZE(devices)); } -- cgit v1.2.3 From c21ffd749c40904de90b9e8e116aa2b949dcaf35 Mon Sep 17 00:00:00 2001 From: Arve Hjønnevåg Date: Sat, 1 Dec 2007 19:01:30 -0800 Subject: [ARM] msm: add keypad for halibut board Signed-off-by: Brian Swetland --- arch/arm/mach-msm/Makefile | 2 +- arch/arm/mach-msm/board-halibut-keypad.c | 117 +++++++++++++++++++++++++++++++ 2 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-msm/board-halibut-keypad.c (limited to 'arch') diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index c28c32dba410..b597ef02d872 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -19,4 +19,4 @@ obj-$(CONFIG_MSM_CPU_FREQ_SCREEN) += cpufreq.o obj-$(CONFIG_MACH_TROUT) += board-dream.o -obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o +obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o board-halibut-keypad.o diff --git a/arch/arm/mach-msm/board-halibut-keypad.c b/arch/arm/mach-msm/board-halibut-keypad.c new file mode 100644 index 000000000000..46bf666c8f41 --- /dev/null +++ b/arch/arm/mach-msm/board-halibut-keypad.c @@ -0,0 +1,117 @@ +/* linux/arch/arm/mach-msm/board-halibut-keypad.c + * + * Copyright (C) 2007 Google, Inc. + * Author: Brian Swetland + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 + +#define SCAN_FUNCTION_KEYS 0 + +static unsigned int halibut_row_gpios[] = { + 31, 32, 33, 34, 35, 41 +#if SCAN_FUNCTION_KEYS + , 42 +#endif +}; + +static unsigned int halibut_col_gpios[] = { 36, 37, 38, 39, 40 }; + +#define KEYMAP_INDEX(row, col) ((row)*ARRAY_SIZE(halibut_col_gpios) + (col)) + +static const unsigned short halibut_keymap[ARRAY_SIZE(halibut_col_gpios) * ARRAY_SIZE(halibut_row_gpios)] = { + [KEYMAP_INDEX(0, 0)] = KEY_5, + [KEYMAP_INDEX(0, 1)] = KEY_9, + [KEYMAP_INDEX(0, 2)] = 229, /* SOFT1 */ + [KEYMAP_INDEX(0, 3)] = KEY_6, + [KEYMAP_INDEX(0, 4)] = KEY_LEFT, + + [KEYMAP_INDEX(1, 0)] = KEY_0, + [KEYMAP_INDEX(1, 1)] = KEY_RIGHT, + [KEYMAP_INDEX(1, 2)] = KEY_1, + [KEYMAP_INDEX(1, 3)] = 228, /* KEY_SHARP */ + [KEYMAP_INDEX(1, 4)] = KEY_SEND, + + [KEYMAP_INDEX(2, 0)] = KEY_VOLUMEUP, + [KEYMAP_INDEX(2, 1)] = KEY_HOME, /* FA */ + [KEYMAP_INDEX(2, 2)] = KEY_F8, /* QCHT */ + [KEYMAP_INDEX(2, 3)] = KEY_F6, /* R+ */ + [KEYMAP_INDEX(2, 4)] = KEY_F7, /* R- */ + + [KEYMAP_INDEX(3, 0)] = KEY_UP, + [KEYMAP_INDEX(3, 1)] = KEY_CLEAR, + [KEYMAP_INDEX(3, 2)] = KEY_4, + [KEYMAP_INDEX(3, 3)] = KEY_MUTE, /* SPKR */ + [KEYMAP_INDEX(3, 4)] = KEY_2, + + [KEYMAP_INDEX(4, 0)] = 230, /* SOFT2 */ + [KEYMAP_INDEX(4, 1)] = 232, /* KEY_CENTER */ + [KEYMAP_INDEX(4, 2)] = KEY_DOWN, + [KEYMAP_INDEX(4, 3)] = KEY_BACK, /* FB */ + [KEYMAP_INDEX(4, 4)] = KEY_8, + + [KEYMAP_INDEX(5, 0)] = KEY_VOLUMEDOWN, + [KEYMAP_INDEX(5, 1)] = 227, /* KEY_STAR */ + [KEYMAP_INDEX(5, 2)] = KEY_MAIL, /* MESG */ + [KEYMAP_INDEX(5, 3)] = KEY_3, + [KEYMAP_INDEX(5, 4)] = KEY_7, + +#if SCAN_FUNCTION_KEYS + [KEYMAP_INDEX(6, 0)] = KEY_F5, + [KEYMAP_INDEX(6, 1)] = KEY_F4, + [KEYMAP_INDEX(6, 2)] = KEY_F3, + [KEYMAP_INDEX(6, 3)] = KEY_F2, + [KEYMAP_INDEX(6, 4)] = KEY_F1 +#endif +}; + +static struct gpio_event_matrix_info halibut_matrix_info = { + .info.func = gpio_event_matrix_func, + .keymap = halibut_keymap, + .output_gpios = halibut_row_gpios, + .input_gpios = halibut_col_gpios, + .noutputs = ARRAY_SIZE(halibut_row_gpios), + .ninputs = ARRAY_SIZE(halibut_col_gpios), + .settle_time.tv.nsec = 0, + .poll_time.tv.nsec = 20 * NSEC_PER_MSEC, + .flags = GPIOKPF_LEVEL_TRIGGERED_IRQ | GPIOKPF_DRIVE_INACTIVE | GPIOKPF_PRINT_UNMAPPED_KEYS /*| GPIOKPF_PRINT_MAPPED_KEYS*/ +}; + +struct gpio_event_info *halibut_keypad_info[] = { + &halibut_matrix_info.info +}; + +static struct gpio_event_platform_data halibut_keypad_data = { + .name = "halibut_keypad", + .info = halibut_keypad_info, + .info_count = ARRAY_SIZE(halibut_keypad_info) +}; + +static struct platform_device halibut_keypad_device = { + .name = GPIO_EVENT_DEV_NAME, + .id = -1, + .dev = { + .platform_data = &halibut_keypad_data, + }, +}; + +static int __init halibut_init_keypad(void) +{ + if (!machine_is_halibut()) + return 0; + return platform_device_register(&halibut_keypad_device); +} + +device_initcall(halibut_init_keypad); -- cgit v1.2.3 From ad86f77a23737c134031c5de9968e03c998f9706 Mon Sep 17 00:00:00 2001 From: Arve Hjønnevåg Date: Mon, 4 Feb 2008 17:14:40 -0800 Subject: [ARM] msm: Add FFA keymap to halibut. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add board_halibut.ffa=1 to the kernel command line to use it. Signed-off-by: Brian Swetland Signed-off-by: Arve Hjønnevåg --- arch/arm/mach-msm/board-halibut-keypad.c | 62 +++++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/board-halibut-keypad.c b/arch/arm/mach-msm/board-halibut-keypad.c index 46bf666c8f41..49c1075627d3 100644 --- a/arch/arm/mach-msm/board-halibut-keypad.c +++ b/arch/arm/mach-msm/board-halibut-keypad.c @@ -18,7 +18,12 @@ #include #include -#define SCAN_FUNCTION_KEYS 0 +#undef MODULE_PARAM_PREFIX +#define MODULE_PARAM_PREFIX "board_halibut." +static int halibut_ffa; +module_param_named(ffa, halibut_ffa, int, S_IRUGO | S_IWUSR | S_IWGRP); + +#define SCAN_FUNCTION_KEYS 0 /* don't turn this on without updating the ffa support */ static unsigned int halibut_row_gpios[] = { 31, 32, 33, 34, 35, 41 @@ -29,6 +34,21 @@ static unsigned int halibut_row_gpios[] = { static unsigned int halibut_col_gpios[] = { 36, 37, 38, 39, 40 }; +/* FFA: + 36: KEYSENSE_N(0) + 37: KEYSENSE_N(1) + 38: KEYSENSE_N(2) + 39: KEYSENSE_N(3) + 40: KEYSENSE_N(4) + + 31: KYPD_17 + 32: KYPD_15 + 33: KYPD_13 + 34: KYPD_11 + 35: KYPD_9 + 41: KYPD_MEMO +*/ + #define KEYMAP_INDEX(row, col) ((row)*ARRAY_SIZE(halibut_col_gpios) + (col)) static const unsigned short halibut_keymap[ARRAY_SIZE(halibut_col_gpios) * ARRAY_SIZE(halibut_row_gpios)] = { @@ -77,6 +97,44 @@ static const unsigned short halibut_keymap[ARRAY_SIZE(halibut_col_gpios) * ARRAY #endif }; +static const unsigned short halibut_keymap_ffa[ARRAY_SIZE(halibut_col_gpios) * ARRAY_SIZE(halibut_row_gpios)] = { + /*[KEYMAP_INDEX(0, 0)] = ,*/ + /*[KEYMAP_INDEX(0, 1)] = ,*/ + [KEYMAP_INDEX(0, 2)] = KEY_1, + [KEYMAP_INDEX(0, 3)] = KEY_SEND, + [KEYMAP_INDEX(0, 4)] = KEY_LEFT, + + [KEYMAP_INDEX(1, 0)] = KEY_3, + [KEYMAP_INDEX(1, 1)] = KEY_RIGHT, + [KEYMAP_INDEX(1, 2)] = KEY_VOLUMEUP, + /*[KEYMAP_INDEX(1, 3)] = ,*/ + [KEYMAP_INDEX(1, 4)] = KEY_6, + + [KEYMAP_INDEX(2, 0)] = KEY_HOME, /* A */ + [KEYMAP_INDEX(2, 1)] = KEY_BACK, /* B */ + [KEYMAP_INDEX(2, 2)] = KEY_0, + [KEYMAP_INDEX(2, 3)] = 228, /* KEY_SHARP */ + [KEYMAP_INDEX(2, 4)] = KEY_9, + + [KEYMAP_INDEX(3, 0)] = KEY_UP, + [KEYMAP_INDEX(3, 1)] = 232, /* KEY_CENTER */ /* i */ + [KEYMAP_INDEX(3, 2)] = KEY_4, + /*[KEYMAP_INDEX(3, 3)] = ,*/ + [KEYMAP_INDEX(3, 4)] = KEY_2, + + [KEYMAP_INDEX(4, 0)] = KEY_VOLUMEDOWN, + [KEYMAP_INDEX(4, 1)] = KEY_SOUND, + [KEYMAP_INDEX(4, 2)] = KEY_DOWN, + [KEYMAP_INDEX(4, 3)] = KEY_8, + [KEYMAP_INDEX(4, 4)] = KEY_5, + + /*[KEYMAP_INDEX(5, 0)] = ,*/ + [KEYMAP_INDEX(5, 1)] = 227, /* KEY_STAR */ + [KEYMAP_INDEX(5, 2)] = 230, /*SOFT2*/ /* 2 */ + [KEYMAP_INDEX(5, 3)] = KEY_MENU, /* 1 */ + [KEYMAP_INDEX(5, 4)] = KEY_7, +}; + static struct gpio_event_matrix_info halibut_matrix_info = { .info.func = gpio_event_matrix_func, .keymap = halibut_keymap, @@ -111,6 +169,8 @@ static int __init halibut_init_keypad(void) { if (!machine_is_halibut()) return 0; + if (halibut_ffa) + halibut_matrix_info.keymap = halibut_keymap_ffa; return platform_device_register(&halibut_keypad_device); } -- cgit v1.2.3 From 089bb14e28ffb1e3c6d29c5b99f5894964f9e641 Mon Sep 17 00:00:00 2001 From: Rebecca Schultz Date: Mon, 29 Sep 2008 17:32:13 -0700 Subject: [ARM] msm: trout: Add trout (aka Dream/G1) machine target and some defines Signed-off-by: Rebecca Schultz Signed-off-by: Mike Chan Signed-off-by: Mike Lockwood --- arch/arm/mach-msm/board-trout.c | 685 ++++++++++++++++++++++++++++++++++++++++ arch/arm/mach-msm/board-trout.h | 162 ++++++++++ 2 files changed, 847 insertions(+) create mode 100644 arch/arm/mach-msm/board-trout.c create mode 100644 arch/arm/mach-msm/board-trout.h (limited to 'arch') diff --git a/arch/arm/mach-msm/board-trout.c b/arch/arm/mach-msm/board-trout.c new file mode 100644 index 000000000000..7da4611dc5ba --- /dev/null +++ b/arch/arm/mach-msm/board-trout.c @@ -0,0 +1,685 @@ +/* arch/arm/mach-msm/board-trout.c + * + * Copyright (C) 2008 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 <../../../drivers/staging/android/timed_gpio.h> +#include +#include +#include +#include +#ifdef CONFIG_USB_FUNCTION +#include +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "board-trout.h" + +#include "gpio_chip.h" + +#include +#ifdef CONFIG_USB_FUNCTION +#include +#endif + +#include "proc_comm.h" +#include "devices.h" + +void msm_init_irq(void); +void msm_init_gpio(void); + +struct trout_axis_info { + struct gpio_event_axis_info info; + uint16_t in_state; + uint16_t out_state; +}; +static bool nav_just_on; +static int nav_on_jiffies; + +uint16_t trout_axis_map(struct gpio_event_axis_info *info, uint16_t in) +{ + struct trout_axis_info *ai = container_of(info, struct trout_axis_info, info); + uint16_t out = ai->out_state; + + if (nav_just_on) { + if (jiffies == nav_on_jiffies || jiffies == nav_on_jiffies + 1) + goto ignore; + nav_just_on = 0; + } + if((ai->in_state ^ in) & 1) + out--; + if((ai->in_state ^ in) & 2) + out++; + ai->out_state = out; +ignore: + ai->in_state = in; + return out; +} + +int trout_nav_power(const struct gpio_event_platform_data *pdata, bool on) +{ + gpio_set_value(TROUT_GPIO_JOG_EN, on); + if (on) { + nav_just_on = 1; + nav_on_jiffies = jiffies; + } + return 0; +} + +static uint32_t trout_4_x_axis_gpios[] = { + TROUT_4_BALL_LEFT_0, TROUT_4_BALL_RIGHT_0 +}; +static uint32_t trout_5_x_axis_gpios[] = { + TROUT_5_BALL_LEFT_0, TROUT_5_BALL_RIGHT_0 +}; + +static struct trout_axis_info trout_x_axis = { + .info = { + .info.func = gpio_event_axis_func, + .count = ARRAY_SIZE(trout_5_x_axis_gpios), + .type = EV_REL, + .code = REL_X, + .decoded_size = 1U << ARRAY_SIZE(trout_5_x_axis_gpios), + .map = trout_axis_map, + .gpio = trout_5_x_axis_gpios, + .flags = GPIOEAF_PRINT_UNKNOWN_DIRECTION /*| GPIOEAF_PRINT_RAW | GPIOEAF_PRINT_EVENT */ + } +}; + +static uint32_t trout_4_y_axis_gpios[] = { + TROUT_4_BALL_UP_0, TROUT_4_BALL_DOWN_0 +}; +static uint32_t trout_5_y_axis_gpios[] = { + TROUT_5_BALL_UP_0, TROUT_5_BALL_DOWN_0 +}; + +static struct trout_axis_info trout_y_axis = { + .info = { + .info.func = gpio_event_axis_func, + .count = ARRAY_SIZE(trout_5_y_axis_gpios), + .type = EV_REL, + .code = REL_Y, + .decoded_size = 1U << ARRAY_SIZE(trout_5_y_axis_gpios), + .map = trout_axis_map, + .gpio = trout_5_y_axis_gpios, + .flags = GPIOEAF_PRINT_UNKNOWN_DIRECTION /*| GPIOEAF_PRINT_RAW | GPIOEAF_PRINT_EVENT */ + } +}; + +static struct gpio_event_direct_entry trout_nav_buttons[] = { + { TROUT_GPIO_NAVI_ACT_N, BTN_MOUSE } +}; + +static struct gpio_event_input_info trout_nav_button_info = { + .info.func = gpio_event_input_func, + .flags = 0, + .type = EV_KEY, + .keymap = trout_nav_buttons, + .keymap_size = ARRAY_SIZE(trout_nav_buttons) +}; + +static struct gpio_event_info *trout_nav_info[] = { + &trout_x_axis.info.info, + &trout_y_axis.info.info, + &trout_nav_button_info.info +}; + +static struct gpio_event_platform_data trout_nav_data = { + .name = "trout-nav", + .info = trout_nav_info, + .info_count = ARRAY_SIZE(trout_nav_info), + .power = trout_nav_power, +}; + +static struct platform_device trout_nav_device = { + .name = GPIO_EVENT_DEV_NAME, + .id = 2, + .dev = { + .platform_data = &trout_nav_data, + }, +}; + +static int trout_ts_power(int on) +{ + int tp_ls_gpio = system_rev < 5 ? TROUT_4_TP_LS_EN : TROUT_5_TP_LS_EN; + if (on) { + gpio_set_value(TROUT_GPIO_TP_I2C_PULL, 1); + gpio_set_value(TROUT_GPIO_TP_EN, 1); + /* touchscreen must be powered before we enable i2c pullup */ + msleep(2); + /* enable touch panel level shift */ + gpio_set_value(tp_ls_gpio, 1); + msleep(2); + } + else { + gpio_set_value(tp_ls_gpio, 0); + gpio_set_value(TROUT_GPIO_TP_EN, 0); + gpio_set_value(TROUT_GPIO_TP_I2C_PULL, 0); + } + return 0; +} + +static struct synaptics_i2c_rmi_platform_data trout_ts_data[] = { + { + .version = 0x010c, + .power = trout_ts_power, + .flags = SYNAPTICS_FLIP_Y | SYNAPTICS_SNAP_TO_INACTIVE_EDGE, + .inactive_left = -100 * 0x10000 / 4334, + .inactive_right = -100 * 0x10000 / 4334, + .inactive_top = -40 * 0x10000 / 6696, + .inactive_bottom = -40 * 0x10000 / 6696, + .snap_left_on = 300 * 0x10000 / 4334, + .snap_left_off = 310 * 0x10000 / 4334, + .snap_right_on = 300 * 0x10000 / 4334, + .snap_right_off = 310 * 0x10000 / 4334, + .snap_top_on = 100 * 0x10000 / 6696, + .snap_top_off = 110 * 0x10000 / 6696, + .snap_bottom_on = 100 * 0x10000 / 6696, + .snap_bottom_off = 110 * 0x10000 / 6696, + }, + { + .flags = SYNAPTICS_FLIP_Y | SYNAPTICS_SNAP_TO_INACTIVE_EDGE, + .inactive_left = ((4674 - 4334) / 2 + 200) * 0x10000 / 4334, + .inactive_right = ((4674 - 4334) / 2 + 200) * 0x10000 / 4334, + .inactive_top = ((6946 - 6696) / 2) * 0x10000 / 6696, + .inactive_bottom = ((6946 - 6696) / 2) * 0x10000 / 6696, + } +}; + +static struct akm8976_platform_data compass_platform_data = { + .reset = TROUT_GPIO_COMPASS_RST_N, + .clk_on = TROUT_GPIO_COMPASS_32K_EN, + .intr = TROUT_GPIO_COMPASS_IRQ, +}; + +static struct i2c_board_info i2c_devices[] = { + { + I2C_BOARD_INFO(SYNAPTICS_I2C_RMI_NAME, 0x20), + .platform_data = trout_ts_data, + .irq = TROUT_GPIO_TO_INT(TROUT_GPIO_TP_ATT_N) + }, + { + I2C_BOARD_INFO("akm8976", 0x1C), + .platform_data = &compass_platform_data, + .irq = TROUT_GPIO_TO_INT(TROUT_GPIO_COMPASS_IRQ), + }, + { + I2C_BOARD_INFO("pca963x", 0x62), + }, +}; + +static struct android_pmem_platform_data android_pmem_pdata = { + .name = "pmem", + .start = MSM_PMEM_MDP_BASE, + .size = MSM_PMEM_MDP_SIZE, + .no_allocator = 1, + .cached = 1, +}; + +static struct android_pmem_platform_data android_pmem_adsp_pdata = { + .name = "pmem_adsp", + .start = MSM_PMEM_ADSP_BASE, + .size = MSM_PMEM_ADSP_SIZE, + .no_allocator = 0, + .cached = 0, +}; + +static struct android_pmem_platform_data android_pmem_camera_pdata = { + .name = "pmem_camera", + .start = MSM_PMEM_CAMERA_BASE, + .size = MSM_PMEM_CAMERA_SIZE, + .no_allocator = 0, + .cached = 0, +}; + +static struct android_pmem_platform_data android_pmem_gpu0_pdata = { + .name = "pmem_gpu0", + .start = MSM_PMEM_GPU0_BASE, + .size = MSM_PMEM_GPU0_SIZE, + .no_allocator = 1, + .cached = 0, + .buffered = 1, +}; + +static struct android_pmem_platform_data android_pmem_gpu1_pdata = { + .name = "pmem_gpu1", + .start = MSM_PMEM_GPU1_BASE, + .size = MSM_PMEM_GPU1_SIZE, + .no_allocator = 1, + .cached = 0, + .buffered = 1, +}; + +static struct platform_device android_pmem_device = { + .name = "android_pmem", + .id = 0, + .dev = { .platform_data = &android_pmem_pdata }, +}; + +static struct platform_device android_pmem_adsp_device = { + .name = "android_pmem", + .id = 1, + .dev = { .platform_data = &android_pmem_adsp_pdata }, +}; + +static struct platform_device android_pmem_gpu0_device = { + .name = "android_pmem", + .id = 2, + .dev = { .platform_data = &android_pmem_gpu0_pdata }, +}; + +static struct platform_device android_pmem_gpu1_device = { + .name = "android_pmem", + .id = 3, + .dev = { .platform_data = &android_pmem_gpu1_pdata }, +}; + +static struct platform_device android_pmem_camera_device = { + .name = "android_pmem", + .id = 4, + .dev = { .platform_data = &android_pmem_camera_pdata }, +}; + +static struct timed_gpio timed_gpios[] = { + { + .name = "vibrator", + .gpio = TROUT_GPIO_HAPTIC_PWM, + .max_timeout = 15000, + }, + { + .name = "flash", + .gpio = TROUT_GPIO_FLASH_EN, + .max_timeout = 400, + }, +}; + +static struct timed_gpio_platform_data timed_gpio_data = { + .num_gpios = ARRAY_SIZE(timed_gpios), + .gpios = timed_gpios, +}; + +static struct platform_device android_timed_gpios = { + .name = "timed-gpio", + .id = -1, + .dev = { + .platform_data = &timed_gpio_data, + }, +}; + +static struct gpio_led android_led_list[] = { + { + .name = "spotlight", + .gpio = TROUT_GPIO_SPOTLIGHT_EN, + }, + { + .name = "keyboard-backlight", + .gpio = TROUT_GPIO_QTKEY_LED_EN, + }, + { + .name = "button-backlight", + .gpio = TROUT_GPIO_UI_LED_EN, + }, +}; + +static struct gpio_led_platform_data android_leds_data = { + .num_leds = ARRAY_SIZE(android_led_list), + .leds = android_led_list, +}; + +static struct platform_device android_leds = { + .name = "leds-gpio", + .id = -1, + .dev = { + .platform_data = &android_leds_data, + }, +}; + +static struct gpio_switch_platform_data sd_door_switch_data = { + .name = "sd-door", + .gpio = TROUT_GPIO_SD_DOOR_N, + .state_on = "open", + .state_off = "closed", +}; + +static struct platform_device sd_door_switch = { + .name = "switch-gpio", + .id = -1, + .dev = { + .platform_data = &sd_door_switch_data, + }, +}; + +#ifdef CONFIG_USB_FUNCTION + +/* adjust eye diagram, disable vbusvalid interrupts */ +static int trout_phy_init_seq[] = { 0x40, 0x31, 0x1D, 0x0D, 0x1D, 0x10, -1 }; + +static void trout_phy_reset(void) +{ + gpio_set_value(TROUT_GPIO_USB_PHY_RST_N, 0); + mdelay(10); + gpio_set_value(TROUT_GPIO_USB_PHY_RST_N, 1); + mdelay(10); +} + +static char *trout_usb_functions[] = { +#if defined(CONFIG_USB_FUNCTION_MASS_STORAGE) || defined(CONFIG_USB_FUNCTION_UMS) + "usb_mass_storage", +#endif +#ifdef CONFIG_USB_FUNCTION_ADB + "adb", +#endif +}; + +static struct msm_hsusb_product trout_usb_products[] = { + { + .product_id = 0x0c01, + .functions = 0x00000001, /* "usb_mass_storage" only */ + }, + { + .product_id = 0x0c02, + .functions = 0x00000003, /* "usb_mass_storage" and "adb" */ + }, +}; + +static struct msm_hsusb_platform_data msm_hsusb_pdata = { + .phy_reset = trout_phy_reset, + .phy_init_seq = trout_phy_init_seq, + .vendor_id = 0x0bb4, + .product_id = 0x0c02, + .version = 0x0100, + .product_name = "Android Phone", + .manufacturer_name = "HTC", + + .functions = trout_usb_functions, + .num_functions = ARRAY_SIZE(trout_usb_functions), + .products = trout_usb_products, + .num_products = ARRAY_SIZE(trout_usb_products), +}; + +static struct usb_mass_storage_platform_data mass_storage_pdata = { + .nluns = 1, + .buf_size = 16384, + .vendor = "HTC ", + .product = "Android Phone ", + .release = 0x0100, +}; + +static struct platform_device usb_mass_storage_device = { + .name = "usb_mass_storage", + .id = -1, + .dev = { + .platform_data = &mass_storage_pdata, + }, +}; +#endif + +static struct resource trout_ram_console_resource[] = { + { + .start = MSM_RAM_CONSOLE_BASE, + .end = MSM_RAM_CONSOLE_BASE + MSM_RAM_CONSOLE_SIZE - 1, + .flags = IORESOURCE_MEM, + } +}; + +static struct platform_device trout_ram_console_device = { + .name = "ram_console", + .id = -1, + .num_resources = ARRAY_SIZE(trout_ram_console_resource), + .resource = trout_ram_console_resource, +}; + +static struct platform_device *devices[] __initdata = { + &msm_device_smd, + &msm_device_nand, + &msm_device_i2c, + &msm_device_uart1, +#if !defined(CONFIG_MSM_SERIAL_DEBUGGER) && !defined(CONFIG_TROUT_H2W) + &msm_device_uart3, +#endif +#ifdef CONFIG_USB_FUNCTION + &msm_device_hsusb, + &usb_mass_storage_device, +#endif + &trout_nav_device, + &android_leds, + &sd_door_switch, + &android_timed_gpios, + &android_pmem_device, + &android_pmem_adsp_device, + &android_pmem_gpu0_device, + &android_pmem_gpu1_device, + &android_pmem_camera_device, + &trout_ram_console_device, +}; + +extern struct sys_timer msm_timer; + +static void __init trout_init_irq(void) +{ + printk("trout_init_irq()\n"); + msm_init_irq(); +} + +static uint cpld_iset; +static uint cpld_charger_en; +static uint cpld_usb_h2w_sw; +static uint opt_disable_uart3; + +module_param_named(iset, cpld_iset, uint, 0); +module_param_named(charger_en, cpld_charger_en, uint, 0); +module_param_named(usb_h2w_sw, cpld_usb_h2w_sw, uint, 0); +module_param_named(disable_uart3, opt_disable_uart3, uint, 0); + +static int trout_bluetooth_power_on; + +static void bluetooth_set_power(int on) +{ + if (on) { + gpio_set_value(TROUT_GPIO_BT_32K_EN, 1); + udelay(10); + gpio_configure(101, GPIOF_DRIVE_OUTPUT | GPIOF_OUTPUT_HIGH); + } else { + gpio_configure(101, GPIOF_DRIVE_OUTPUT | GPIOF_OUTPUT_LOW); + gpio_set_value(TROUT_GPIO_BT_32K_EN, 0); + } +} + +static int bluetooth_set_power_on(const char *val, struct kernel_param *kp) +{ + int ret; + ret = param_set_bool(val, kp); + if (!ret) + bluetooth_set_power(trout_bluetooth_power_on); + return ret; +} + +module_param_call(bluetooth_power_on, bluetooth_set_power_on, param_get_bool, + &trout_bluetooth_power_on, S_IWUSR | S_IRUGO); + +static int __init trout_serialno_setup(char *str) +{ +#ifdef CONFIG_USB_FUNCTION + msm_hsusb_pdata.serial_number = str; +#endif + return 1; +} + +__setup("androidboot.serialno=", trout_serialno_setup); + +static void trout_reset(void) +{ + gpio_set_value(TROUT_GPIO_PS_HOLD, 0); +} + +static uint32_t gpio_table[] = { + /* BLUETOOTH */ + PCOM_GPIO_CFG(43, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* RTS */ + PCOM_GPIO_CFG(44, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* CTS */ + PCOM_GPIO_CFG(45, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* RX */ + PCOM_GPIO_CFG(46, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* TX */ +}; + +static void config_gpio_table(uint32_t *table, int len) +{ + int n; + unsigned id; + for(n = 0; n < len; n++) { + id = table[n]; + msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0); + } +} + +static void __init config_gpios(void) +{ + config_gpio_table(gpio_table, ARRAY_SIZE(gpio_table)); +} + +void msm_serial_debug_init(unsigned int base, int irq, + struct device *clk_device, int signal_irq); + +static struct msm_acpu_clock_platform_data trout_clock_data = { + .acpu_switch_time_us = 20, + .max_speed_delta_khz = 256000, + .vdd_switch_time_us = 62, + .power_collapse_khz = 19200000, + .wait_for_irq_khz = 128000000, +}; + +static void __init trout_init(void) +{ + printk("trout_init() revision=%d\n", system_rev); + + /* + * Setup common MSM GPIOS + */ + config_gpios(); + + msm_hw_reset_hook = trout_reset; + + msm_acpu_clock_init(&trout_clock_data); + + /* adjust GPIOs based on bootloader request */ + printk("trout_init: cpld_usb_hw2_sw = %d\n", cpld_usb_h2w_sw); + gpio_set_value(TROUT_GPIO_USB_H2W_SW, cpld_usb_h2w_sw); + +#if defined(CONFIG_MSM_SERIAL_DEBUGGER) + if (!opt_disable_uart3) + msm_serial_debug_init(MSM_UART3_PHYS, INT_UART3, + &msm_device_uart3.dev, 1); +#endif + + /* gpio_configure(108, IRQF_TRIGGER_LOW); */ + +#if defined(CONFIG_LL_DEBUG_UART1) + /* H2W pins <-> UART1 */ + gpio_set_value(TROUT_GPIO_H2W_SEL0, 1); + gpio_set_value(TROUT_GPIO_H2W_SEL1, 0); +#else + /* H2W pins <-> UART3, Bluetooth <-> UART1 */ + gpio_set_value(TROUT_GPIO_H2W_SEL0, 0); + gpio_set_value(TROUT_GPIO_H2W_SEL1, 1); +#endif + + /* Init bluetooth clock and shutdown pin */ + bluetooth_set_power(trout_bluetooth_power_on); + + /* put the AF VCM in powerdown mode to avoid noise */ + gpio_set_value(TROUT_GPIO_VCM_PWDN, 1); + mdelay(100); + + if (system_rev < 5) { + trout_x_axis.info.gpio = trout_4_x_axis_gpios; + trout_y_axis.info.gpio = trout_4_y_axis_gpios; + } + + msm_device_hsusb.dev.platform_data = &msm_hsusb_pdata; + + platform_add_devices(devices, ARRAY_SIZE(devices)); + i2c_register_board_info(0, i2c_devices, ARRAY_SIZE(i2c_devices)); + + /* SD card door should wake the device */ + set_irq_wake(TROUT_GPIO_TO_INT(TROUT_GPIO_SD_DOOR_N), 1); +} + +static struct map_desc trout_io_desc[] __initdata = { + { + .virtual = TROUT_CPLD_BASE, + .pfn = __phys_to_pfn(TROUT_CPLD_START), + .length = TROUT_CPLD_SIZE, + .type = MT_DEVICE_NONSHARED + } +}; + +static void __init trout_fixup(struct machine_desc *desc, struct tag *tags, + char **cmdline, struct meminfo *mi) +{ + mi->nr_banks=1; + mi->bank[0].start = PHYS_OFFSET; + mi->bank[0].node = PHYS_TO_NID(PHYS_OFFSET); + mi->bank[0].size = (101*1024*1024); +} + +static void __init trout_map_io(void) +{ + printk("trout_init_map_io()\n"); + msm_map_common_io(); + iotable_init(trout_io_desc, ARRAY_SIZE(trout_io_desc)); + msm_clock_init(); +} + +MACHINE_START(TROUT, "trout") +/* Maintainer: Brian Swetland */ + +/* this is broken... can we just opt out of specifying something here? */ + .phys_io = 0x80000000, + .io_pg_offst = ((0x80000000) >> 18) & 0xfffc, + + .boot_params = 0x10000100, + .fixup = trout_fixup, + .map_io = trout_map_io, + .init_irq = trout_init_irq, + .init_machine = trout_init, + .timer = &msm_timer, +MACHINE_END diff --git a/arch/arm/mach-msm/board-trout.h b/arch/arm/mach-msm/board-trout.h new file mode 100644 index 000000000000..308c4df90189 --- /dev/null +++ b/arch/arm/mach-msm/board-trout.h @@ -0,0 +1,162 @@ +/* linux/arch/arm/mach-msm/board-trout.h +** Author: Brian Swetland +*/ +#ifndef __ARCH_ARM_MACH_MSM_BOARD_TROUT_H +#define __ARCH_ARM_MACH_MSM_BOARD_TROUT_H + +#include + +#define MSM_SMI_BASE 0x00000000 +#define MSM_SMI_SIZE 0x00800000 + +#define MSM_EBI_BASE 0x10000000 +#define MSM_EBI_SIZE 0x06e00000 + +#define MSM_PMEM_GPU0_BASE 0x00000000 +#define MSM_PMEM_GPU0_SIZE 0x00700000 + +#define MSM_PMEM_MDP_BASE 0x02000000 +#define MSM_PMEM_MDP_SIZE 0x00800000 + +#define MSM_PMEM_ADSP_BASE 0x02800000 +#define MSM_PMEM_ADSP_SIZE 0x00800000 + +#define MSM_PMEM_CAMERA_BASE 0x03000000 +#define MSM_PMEM_CAMERA_SIZE 0x00800000 + +#define MSM_FB_BASE 0x03800000 +#define MSM_FB_SIZE 0x00100000 + +#define MSM_LINUX_BASE MSM_EBI_BASE +#define MSM_LINUX_SIZE 0x06500000 + +#define MSM_PMEM_GPU1_SIZE 0x800000 +#define MSM_PMEM_GPU1_BASE MSM_RAM_CONSOLE_BASE - MSM_PMEM_GPU1_SIZE + +#define MSM_RAM_CONSOLE_BASE MSM_EBI_BASE + 0x6d00000 +#define MSM_RAM_CONSOLE_SIZE 128 * SZ_1K + +#if (MSM_FB_BASE + MSM_FB_SIZE) >= (MSM_PMEM_GPU1_BASE) +#error invalid memory map +#endif + +#define DECLARE_MSM_IOMAP +#include + +#define TROUT_4_BALL_UP_0 1 +#define TROUT_4_BALL_LEFT_0 18 +#define TROUT_4_BALL_DOWN_0 57 +#define TROUT_4_BALL_RIGHT_0 91 + +#define TROUT_5_BALL_UP_0 94 +#define TROUT_5_BALL_LEFT_0 18 +#define TROUT_5_BALL_DOWN_0 90 +#define TROUT_5_BALL_RIGHT_0 19 + +#define TROUT_POWER_KEY 20 + +#define TROUT_4_TP_LS_EN 19 +#define TROUT_5_TP_LS_EN 1 + +#define TROUT_CPLD_BASE 0xE8100000 +#define TROUT_CPLD_START 0x98000000 +#define TROUT_CPLD_SIZE SZ_4K + +#define TROUT_GPIO_CABLE_IN1 (83) +#define TROUT_GPIO_CABLE_IN2 (49) + +#define TROUT_GPIO_START (128) + +#define TROUT_GPIO_INT_MASK0_REG (0x0c) +#define TROUT_GPIO_INT_STAT0_REG (0x0e) +#define TROUT_GPIO_INT_MASK1_REG (0x14) +#define TROUT_GPIO_INT_STAT1_REG (0x10) + +#define TROUT_GPIO_HAPTIC_PWM (28) +#define TROUT_GPIO_PS_HOLD (25) + +#define TROUT_GPIO_MISC2_BASE (TROUT_GPIO_START + 0x00) +#define TROUT_GPIO_MISC3_BASE (TROUT_GPIO_START + 0x08) +#define TROUT_GPIO_MISC4_BASE (TROUT_GPIO_START + 0x10) +#define TROUT_GPIO_MISC5_BASE (TROUT_GPIO_START + 0x18) +#define TROUT_GPIO_INT2_BASE (TROUT_GPIO_START + 0x20) +#define TROUT_GPIO_MISC1_BASE (TROUT_GPIO_START + 0x28) +#define TROUT_GPIO_VIRTUAL_BASE (TROUT_GPIO_START + 0x30) +#define TROUT_GPIO_INT5_BASE (TROUT_GPIO_START + 0x48) + +#define TROUT_GPIO_CHARGER_EN (TROUT_GPIO_MISC2_BASE + 0) +#define TROUT_GPIO_ISET (TROUT_GPIO_MISC2_BASE + 1) +#define TROUT_GPIO_H2W_DAT_DIR (TROUT_GPIO_MISC2_BASE + 2) +#define TROUT_GPIO_H2W_CLK_DIR (TROUT_GPIO_MISC2_BASE + 3) +#define TROUT_GPIO_H2W_DAT_GPO (TROUT_GPIO_MISC2_BASE + 4) +#define TROUT_GPIO_H2W_CLK_GPO (TROUT_GPIO_MISC2_BASE + 5) +#define TROUT_GPIO_H2W_SEL0 (TROUT_GPIO_MISC2_BASE + 6) +#define TROUT_GPIO_H2W_SEL1 (TROUT_GPIO_MISC2_BASE + 7) + +#define TROUT_GPIO_SPOTLIGHT_EN (TROUT_GPIO_MISC3_BASE + 0) +#define TROUT_GPIO_FLASH_EN (TROUT_GPIO_MISC3_BASE + 1) +#define TROUT_GPIO_I2C_PULL (TROUT_GPIO_MISC3_BASE + 2) +#define TROUT_GPIO_TP_I2C_PULL (TROUT_GPIO_MISC3_BASE + 3) +#define TROUT_GPIO_TP_EN (TROUT_GPIO_MISC3_BASE + 4) +#define TROUT_GPIO_JOG_EN (TROUT_GPIO_MISC3_BASE + 5) +#define TROUT_GPIO_UI_LED_EN (TROUT_GPIO_MISC3_BASE + 6) +#define TROUT_GPIO_QTKEY_LED_EN (TROUT_GPIO_MISC3_BASE + 7) + +#define TROUT_GPIO_VCM_PWDN (TROUT_GPIO_MISC4_BASE + 0) +#define TROUT_GPIO_USB_H2W_SW (TROUT_GPIO_MISC4_BASE + 1) +#define TROUT_GPIO_COMPASS_RST_N (TROUT_GPIO_MISC4_BASE + 2) +#define TROUT_GPIO_HAPTIC_EN_UP (TROUT_GPIO_MISC4_BASE + 3) +#define TROUT_GPIO_HAPTIC_EN_MAIN (TROUT_GPIO_MISC4_BASE + 4) +#define TROUT_GPIO_USB_PHY_RST_N (TROUT_GPIO_MISC4_BASE + 5) +#define TROUT_GPIO_WIFI_PA_RESETX (TROUT_GPIO_MISC4_BASE + 6) +#define TROUT_GPIO_WIFI_EN (TROUT_GPIO_MISC4_BASE + 7) + +#define TROUT_GPIO_BT_32K_EN (TROUT_GPIO_MISC5_BASE + 0) +#define TROUT_GPIO_MAC_32K_EN (TROUT_GPIO_MISC5_BASE + 1) +#define TROUT_GPIO_MDDI_32K_EN (TROUT_GPIO_MISC5_BASE + 2) +#define TROUT_GPIO_COMPASS_32K_EN (TROUT_GPIO_MISC5_BASE + 3) + +#define TROUT_GPIO_NAVI_ACT_N (TROUT_GPIO_INT2_BASE + 0) +#define TROUT_GPIO_COMPASS_IRQ (TROUT_GPIO_INT2_BASE + 1) +#define TROUT_GPIO_SLIDING_DET (TROUT_GPIO_INT2_BASE + 2) +#define TROUT_GPIO_AUD_HSMIC_DET_N (TROUT_GPIO_INT2_BASE + 3) +#define TROUT_GPIO_SD_DOOR_N (TROUT_GPIO_INT2_BASE + 4) +#define TROUT_GPIO_CAM_BTN_STEP1_N (TROUT_GPIO_INT2_BASE + 5) +#define TROUT_GPIO_CAM_BTN_STEP2_N (TROUT_GPIO_INT2_BASE + 6) +#define TROUT_GPIO_TP_ATT_N (TROUT_GPIO_INT2_BASE + 7) +#define TROUT_GPIO_BANK0_FIRST_INT_SOURCE (TROUT_GPIO_NAVI_ACT_N) +#define TROUT_GPIO_BANK0_LAST_INT_SOURCE (TROUT_GPIO_TP_ATT_N) + +#define TROUT_GPIO_H2W_DAT_GPI (TROUT_GPIO_MISC1_BASE + 0) +#define TROUT_GPIO_H2W_CLK_GPI (TROUT_GPIO_MISC1_BASE + 1) +#define TROUT_GPIO_CPLD128_VER_0 (TROUT_GPIO_MISC1_BASE + 4) +#define TROUT_GPIO_CPLD128_VER_1 (TROUT_GPIO_MISC1_BASE + 5) +#define TROUT_GPIO_CPLD128_VER_2 (TROUT_GPIO_MISC1_BASE + 6) +#define TROUT_GPIO_CPLD128_VER_3 (TROUT_GPIO_MISC1_BASE + 7) + +#define TROUT_GPIO_SDMC_CD_N (TROUT_GPIO_VIRTUAL_BASE + 0) +#define TROUT_GPIO_END (TROUT_GPIO_SDMC_CD_N) +#define TROUT_GPIO_BANK1_FIRST_INT_SOURCE (TROUT_GPIO_SDMC_CD_N) +#define TROUT_GPIO_BANK1_LAST_INT_SOURCE (TROUT_GPIO_SDMC_CD_N) + +#define TROUT_GPIO_VIRTUAL_TO_REAL_OFFSET \ + (TROUT_GPIO_INT5_BASE - TROUT_GPIO_VIRTUAL_BASE) + +#define TROUT_INT_START (NR_MSM_IRQS + NR_GPIO_IRQS) +#define TROUT_INT_BANK0_COUNT (8) +#define TROUT_INT_BANK1_START (TROUT_INT_START + TROUT_INT_BANK0_COUNT) +#define TROUT_INT_BANK1_COUNT (1) +#define TROUT_INT_END (TROUT_INT_START + TROUT_INT_BANK0_COUNT + \ + TROUT_INT_BANK1_COUNT - 1) +#define TROUT_GPIO_TO_INT(n) (((n) <= TROUT_GPIO_BANK0_LAST_INT_SOURCE) ? \ + (TROUT_INT_START - TROUT_GPIO_BANK0_FIRST_INT_SOURCE + (n)) : \ + (TROUT_INT_BANK1_START - TROUT_GPIO_BANK1_FIRST_INT_SOURCE + (n))) + +#define TROUT_INT_TO_BANK(n) ((n - TROUT_INT_START) / TROUT_INT_BANK0_COUNT) +#define TROUT_INT_TO_MASK(n) (1U << ((n - TROUT_INT_START) & 7)) +#define TROUT_BANK_TO_MASK_REG(bank) \ + (bank ? TROUT_GPIO_INT_MASK1_REG : TROUT_GPIO_INT_MASK0_REG) +#define TROUT_BANK_TO_STAT_REG(bank) \ + (bank ? TROUT_GPIO_INT_STAT1_REG : TROUT_GPIO_INT_STAT0_REG) + +#endif /* GUARD */ -- cgit v1.2.3 From b2bbb7709aa9aab0590e3ad27807316a5ec5e635 Mon Sep 17 00:00:00 2001 From: Arve Hjønnevåg Date: Mon, 29 Sep 2008 11:16:12 -0700 Subject: [ARM] msm: trout: CPLD GPIO driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rebecca Schultz Signed-off-by: Arve Hjønnevåg --- arch/arm/mach-msm/board-trout-gpio.c | 267 +++++++++++++++++++++++++++++++++++ 1 file changed, 267 insertions(+) create mode 100644 arch/arm/mach-msm/board-trout-gpio.c (limited to 'arch') diff --git a/arch/arm/mach-msm/board-trout-gpio.c b/arch/arm/mach-msm/board-trout-gpio.c new file mode 100644 index 000000000000..0a06de6717ca --- /dev/null +++ b/arch/arm/mach-msm/board-trout-gpio.c @@ -0,0 +1,267 @@ +/* arch/arm/mach-msm/board-trout-gpio.c + * + * Copyright (C) 2008 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 "board-trout.h" +#include "gpio_chip.h" + +static uint8_t trout_cpld_shadow[4] = { + [0] = 0x40, // for serial debug, low current + [1] = 0x04, // I2C_PULL + [3] = 0x04, // mmdi 32k en +}; +static uint8_t trout_int_mask[2] = { + [0] = 0xff, /* mask all interrupts */ + [1] = 0xff, +}; +static uint8_t trout_sleep_int_mask[] = { + [0] = 0xff, + [1] = 0xff, +}; +static int trout_suspended; + +static int trout_gpio_read(struct gpio_chip *chip, unsigned n) +{ + uint8_t b; + int reg; + if (n >= TROUT_GPIO_VIRTUAL_BASE) + n += TROUT_GPIO_VIRTUAL_TO_REAL_OFFSET; + b = 1U << (n & 7); + reg = (n & 0x78) >> 2; // assumes base is 128 + return !!(readb(TROUT_CPLD_BASE + reg) & b); +} + +int trout_gpio_write(struct gpio_chip *chip, unsigned n, unsigned on) +{ + uint8_t b = 1U << (n & 7); + int reg = (n & 0x78) >> 2; // assumes base is 128 + unsigned long flags; + uint8_t reg_val; + + if ((reg >> 1) >= ARRAY_SIZE(trout_cpld_shadow)) { + printk(KERN_ERR "trout_gpio_write called on input %d\n", n); + return -ENOTSUPP; + } + + local_irq_save(flags); + if(on) + reg_val = trout_cpld_shadow[reg >> 1] |= b; + else + reg_val = trout_cpld_shadow[reg >> 1] &= ~b; + writeb(reg_val, TROUT_CPLD_BASE + reg); + local_irq_restore(flags); + return 0; +} + +static int trout_gpio_configure(struct gpio_chip *chip, unsigned int gpio, unsigned long flags) +{ + if(flags & (GPIOF_OUTPUT_LOW | GPIOF_OUTPUT_HIGH)) + trout_gpio_write(chip, gpio, flags & GPIOF_OUTPUT_HIGH); + return 0; +} + +static int trout_gpio_get_irq_num(struct gpio_chip *chip, unsigned int gpio, unsigned int *irqp, unsigned long *irqnumflagsp) +{ + if ((gpio < TROUT_GPIO_BANK0_FIRST_INT_SOURCE || + gpio > TROUT_GPIO_BANK0_LAST_INT_SOURCE) && + (gpio < TROUT_GPIO_BANK1_FIRST_INT_SOURCE || + gpio > TROUT_GPIO_BANK1_LAST_INT_SOURCE)) + return -ENOENT; + *irqp = TROUT_GPIO_TO_INT(gpio); + if(irqnumflagsp) + *irqnumflagsp = 0; + return 0; +} + +static void trout_gpio_irq_ack(unsigned int irq) +{ + int bank = TROUT_INT_TO_BANK(irq); + uint8_t mask = TROUT_INT_TO_MASK(irq); + int reg = TROUT_BANK_TO_STAT_REG(bank); + /*printk(KERN_INFO "trout_gpio_irq_ack irq %d\n", irq);*/ + writeb(mask, TROUT_CPLD_BASE + reg); +} + +static void trout_gpio_irq_mask(unsigned int irq) +{ + unsigned long flags; + uint8_t reg_val; + int bank = TROUT_INT_TO_BANK(irq); + uint8_t mask = TROUT_INT_TO_MASK(irq); + int reg = TROUT_BANK_TO_MASK_REG(bank); + + local_irq_save(flags); + reg_val = trout_int_mask[bank] |= mask; + /*printk(KERN_INFO "trout_gpio_irq_mask irq %d => %d:%02x\n", + irq, bank, reg_val);*/ + if (!trout_suspended) + writeb(reg_val, TROUT_CPLD_BASE + reg); + local_irq_restore(flags); +} + +static void trout_gpio_irq_unmask(unsigned int irq) +{ + unsigned long flags; + uint8_t reg_val; + int bank = TROUT_INT_TO_BANK(irq); + uint8_t mask = TROUT_INT_TO_MASK(irq); + int reg = TROUT_BANK_TO_MASK_REG(bank); + + local_irq_save(flags); + reg_val = trout_int_mask[bank] &= ~mask; + /*printk(KERN_INFO "trout_gpio_irq_unmask irq %d => %d:%02x\n", + irq, bank, reg_val);*/ + if (!trout_suspended) + writeb(reg_val, TROUT_CPLD_BASE + reg); + local_irq_restore(flags); +} + +int trout_gpio_irq_set_wake(unsigned int irq, unsigned int on) +{ + unsigned long flags; + int bank = TROUT_INT_TO_BANK(irq); + uint8_t mask = TROUT_INT_TO_MASK(irq); + + local_irq_save(flags); + if(on) + trout_sleep_int_mask[bank] &= ~mask; + else + trout_sleep_int_mask[bank] |= mask; + local_irq_restore(flags); + return 0; +} + +static void trout_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) +{ + int j, m; + unsigned v; + int bank; + int stat_reg; + int int_base = TROUT_INT_START; + uint8_t int_mask; + + for (bank = 0; bank < 2; bank++) { + stat_reg = TROUT_BANK_TO_STAT_REG(bank); + v = readb(TROUT_CPLD_BASE + stat_reg); + int_mask = trout_int_mask[bank]; + if (v & int_mask) { + writeb(v & int_mask, TROUT_CPLD_BASE + stat_reg); + printk(KERN_ERR "trout_gpio_irq_handler: got masked " + "interrupt: %d:%02x\n", bank, v & int_mask); + } + v &= ~int_mask; + while (v) { + m = v & -v; + j = fls(m) - 1; + /*printk(KERN_INFO "msm_gpio_irq_handler %d:%02x %02x b" + "it %d irq %d\n", bank, v, m, j, int_base + j);*/ + v &= ~m; + generic_handle_irq(int_base + j); + } + int_base += TROUT_INT_BANK0_COUNT; + } + desc->chip->ack(irq); +} + +static int trout_sysdev_suspend(struct sys_device *dev, pm_message_t state) +{ + trout_suspended = 1; + writeb(trout_sleep_int_mask[0], + TROUT_CPLD_BASE + TROUT_GPIO_INT_MASK0_REG); + writeb(trout_sleep_int_mask[1], + TROUT_CPLD_BASE + TROUT_GPIO_INT_MASK1_REG); + writeb(trout_sleep_int_mask[0], + TROUT_CPLD_BASE + TROUT_GPIO_INT_STAT0_REG); + writeb(trout_sleep_int_mask[1], + TROUT_CPLD_BASE + TROUT_GPIO_INT_STAT1_REG); + return 0; +} + +int trout_sysdev_resume(struct sys_device *dev) +{ + writeb(trout_int_mask[0], TROUT_CPLD_BASE + TROUT_GPIO_INT_MASK0_REG); + writeb(trout_int_mask[1], TROUT_CPLD_BASE + TROUT_GPIO_INT_MASK1_REG); + trout_suspended = 0; + return 0; +} + +static struct irq_chip trout_gpio_irq_chip = { + .name = "troutgpio", + .ack = trout_gpio_irq_ack, + .mask = trout_gpio_irq_mask, + .unmask = trout_gpio_irq_unmask, + .set_wake = trout_gpio_irq_set_wake, + //.set_type = trout_gpio_irq_set_type, +}; + +static struct gpio_chip trout_gpio_chip = { + .start = TROUT_GPIO_START, + .end = TROUT_GPIO_END, + .configure = trout_gpio_configure, + .get_irq_num = trout_gpio_get_irq_num, + .read = trout_gpio_read, + .write = trout_gpio_write, +// .read_detect_status = trout_gpio_read_detect_status, +// .clear_detect_status = trout_gpio_clear_detect_status +}; + +struct sysdev_class trout_sysdev_class = { + .name = "troutgpio_irq", + .suspend = trout_sysdev_suspend, + .resume = trout_sysdev_resume, +}; + +static struct sys_device trout_irq_device = { + .cls = &trout_sysdev_class, +}; + +static int __init trout_init_gpio(void) +{ + int i; + + if (!machine_is_trout()) + return 0; + + for(i = 0; i < ARRAY_SIZE(trout_cpld_shadow); i++) + writeb(trout_cpld_shadow[i], TROUT_CPLD_BASE + i * 2); + + for(i = TROUT_INT_START; i <= TROUT_INT_END; i++) { + set_irq_chip(i, &trout_gpio_irq_chip); + set_irq_handler(i, handle_edge_irq); + set_irq_flags(i, IRQF_VALID); + } + + register_gpio_chip(&trout_gpio_chip); + + set_irq_type(MSM_GPIO_TO_INT(17), IRQF_TRIGGER_HIGH); + set_irq_chained_handler(MSM_GPIO_TO_INT(17), trout_gpio_irq_handler); + set_irq_wake(MSM_GPIO_TO_INT(17), 1); + + if(sysdev_class_register(&trout_sysdev_class) == 0) + sysdev_register(&trout_irq_device); + + return 0; +} + +postcore_initcall(trout_init_gpio); -- cgit v1.2.3 From 25f4c54410b1c965516d59d898c9e03b7105aeb0 Mon Sep 17 00:00:00 2001 From: Arve Hjønnevåg Date: Mon, 29 Sep 2008 17:44:12 -0700 Subject: [ARM] msm: trout: platform specific keypad driver Signed-off-by: Rebecca Schultz --- arch/arm/mach-msm/board-trout-keypad.c | 345 +++++++++++++++++++++++++++++++++ 1 file changed, 345 insertions(+) create mode 100644 arch/arm/mach-msm/board-trout-keypad.c (limited to 'arch') diff --git a/arch/arm/mach-msm/board-trout-keypad.c b/arch/arm/mach-msm/board-trout-keypad.c new file mode 100644 index 000000000000..0299d0686de9 --- /dev/null +++ b/arch/arm/mach-msm/board-trout-keypad.c @@ -0,0 +1,345 @@ +/* arch/arm/mach-msm/board-trout-keypad.c + * + * Copyright (C) 2008 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 "board-trout.h" + +static char *keycaps = "--qwerty"; +#undef MODULE_PARAM_PREFIX +#define MODULE_PARAM_PREFIX "board_trout." +module_param_named(keycaps, keycaps, charp, 0); + + +static unsigned int trout_col_gpios[] = { 35, 34, 33, 32, 31, 23, 30, 78 }; +static unsigned int trout_row_gpios[] = { 42, 41, 40, 39, 38, 37, 36 }; + +#define KEYMAP_INDEX(col, row) ((col)*ARRAY_SIZE(trout_row_gpios) + (row)) + +static const unsigned short trout_keymap[ARRAY_SIZE(trout_col_gpios) * ARRAY_SIZE(trout_row_gpios)] = { + [KEYMAP_INDEX(0, 0)] = KEY_BACK, + [KEYMAP_INDEX(0, 1)] = KEY_HOME, +// [KEYMAP_INDEX(0, 2)] = KEY_, + [KEYMAP_INDEX(0, 3)] = KEY_BACKSPACE, + [KEYMAP_INDEX(0, 4)] = KEY_ENTER, + [KEYMAP_INDEX(0, 5)] = KEY_RIGHTALT, + [KEYMAP_INDEX(0, 6)] = KEY_P, + + [KEYMAP_INDEX(1, 0)] = KEY_MENU, +// [KEYMAP_INDEX(1, 0)] = 229, // SOFT1 + [KEYMAP_INDEX(1, 1)] = KEY_SEND, + [KEYMAP_INDEX(1, 2)] = KEY_END, + [KEYMAP_INDEX(1, 3)] = KEY_LEFTALT, + [KEYMAP_INDEX(1, 4)] = KEY_A, + [KEYMAP_INDEX(1, 5)] = KEY_LEFTSHIFT, + [KEYMAP_INDEX(1, 6)] = KEY_Q, + + [KEYMAP_INDEX(2, 0)] = KEY_U, + [KEYMAP_INDEX(2, 1)] = KEY_7, + [KEYMAP_INDEX(2, 2)] = KEY_K, + [KEYMAP_INDEX(2, 3)] = KEY_J, + [KEYMAP_INDEX(2, 4)] = KEY_M, + [KEYMAP_INDEX(2, 5)] = KEY_SLASH, + [KEYMAP_INDEX(2, 6)] = KEY_8, + + [KEYMAP_INDEX(3, 0)] = KEY_5, + [KEYMAP_INDEX(3, 1)] = KEY_6, + [KEYMAP_INDEX(3, 2)] = KEY_B, + [KEYMAP_INDEX(3, 3)] = KEY_H, + [KEYMAP_INDEX(3, 4)] = KEY_N, + [KEYMAP_INDEX(3, 5)] = KEY_SPACE, + [KEYMAP_INDEX(3, 6)] = KEY_Y, + + [KEYMAP_INDEX(4, 0)] = KEY_4, + [KEYMAP_INDEX(4, 1)] = KEY_R, + [KEYMAP_INDEX(4, 2)] = KEY_V, + [KEYMAP_INDEX(4, 3)] = KEY_G, + [KEYMAP_INDEX(4, 4)] = KEY_C, + //[KEYMAP_INDEX(4, 5)] = KEY_, + [KEYMAP_INDEX(4, 6)] = KEY_T, + + [KEYMAP_INDEX(5, 0)] = KEY_2, + [KEYMAP_INDEX(5, 1)] = KEY_W, + [KEYMAP_INDEX(5, 2)] = KEY_COMPOSE, + [KEYMAP_INDEX(5, 3)] = KEY_VOLUMEUP, + [KEYMAP_INDEX(5, 4)] = KEY_S, + [KEYMAP_INDEX(5, 5)] = KEY_Z, + [KEYMAP_INDEX(5, 6)] = KEY_1, + + [KEYMAP_INDEX(6, 0)] = KEY_I, + [KEYMAP_INDEX(6, 1)] = KEY_0, + [KEYMAP_INDEX(6, 2)] = KEY_O, + [KEYMAP_INDEX(6, 3)] = KEY_L, + [KEYMAP_INDEX(6, 4)] = KEY_DOT, + [KEYMAP_INDEX(6, 5)] = KEY_COMMA, + [KEYMAP_INDEX(6, 6)] = KEY_9, + + [KEYMAP_INDEX(7, 0)] = KEY_3, + [KEYMAP_INDEX(7, 1)] = KEY_E, + [KEYMAP_INDEX(7, 2)] = KEY_EMAIL, // @ + [KEYMAP_INDEX(7, 3)] = KEY_VOLUMEDOWN, + [KEYMAP_INDEX(7, 4)] = KEY_X, + [KEYMAP_INDEX(7, 5)] = KEY_F, + [KEYMAP_INDEX(7, 6)] = KEY_D +}; + +static unsigned int trout_col_gpios_evt2[] = { 35, 34, 33, 32, 31, 23, 30, 109 }; +static unsigned int trout_row_gpios_evt2[] = { 42, 41, 40, 39, 38, 37, 36 }; + +static const unsigned short trout_keymap_evt2_1[ARRAY_SIZE(trout_col_gpios) * ARRAY_SIZE(trout_row_gpios)] = { + [KEYMAP_INDEX(0, 0)] = KEY_BACK, + [KEYMAP_INDEX(0, 1)] = KEY_HOME, +// [KEYMAP_INDEX(0, 2)] = KEY_, + [KEYMAP_INDEX(0, 3)] = KEY_BACKSPACE, + [KEYMAP_INDEX(0, 4)] = KEY_ENTER, + [KEYMAP_INDEX(0, 5)] = KEY_RIGHTSHIFT, + [KEYMAP_INDEX(0, 6)] = KEY_P, + + [KEYMAP_INDEX(1, 0)] = KEY_MENU, + [KEYMAP_INDEX(1, 1)] = KEY_SEND, +// [KEYMAP_INDEX(1, 2)] = KEY_, + [KEYMAP_INDEX(1, 3)] = KEY_LEFTSHIFT, + [KEYMAP_INDEX(1, 4)] = KEY_A, + [KEYMAP_INDEX(1, 5)] = KEY_COMPOSE, + [KEYMAP_INDEX(1, 6)] = KEY_Q, + + [KEYMAP_INDEX(2, 0)] = KEY_U, + [KEYMAP_INDEX(2, 1)] = KEY_7, + [KEYMAP_INDEX(2, 2)] = KEY_K, + [KEYMAP_INDEX(2, 3)] = KEY_J, + [KEYMAP_INDEX(2, 4)] = KEY_M, + [KEYMAP_INDEX(2, 5)] = KEY_SLASH, + [KEYMAP_INDEX(2, 6)] = KEY_8, + + [KEYMAP_INDEX(3, 0)] = KEY_5, + [KEYMAP_INDEX(3, 1)] = KEY_6, + [KEYMAP_INDEX(3, 2)] = KEY_B, + [KEYMAP_INDEX(3, 3)] = KEY_H, + [KEYMAP_INDEX(3, 4)] = KEY_N, + [KEYMAP_INDEX(3, 5)] = KEY_SPACE, + [KEYMAP_INDEX(3, 6)] = KEY_Y, + + [KEYMAP_INDEX(4, 0)] = KEY_4, + [KEYMAP_INDEX(4, 1)] = KEY_R, + [KEYMAP_INDEX(4, 2)] = KEY_V, + [KEYMAP_INDEX(4, 3)] = KEY_G, + [KEYMAP_INDEX(4, 4)] = KEY_C, +// [KEYMAP_INDEX(4, 5)] = KEY_, + [KEYMAP_INDEX(4, 6)] = KEY_T, + + [KEYMAP_INDEX(5, 0)] = KEY_2, + [KEYMAP_INDEX(5, 1)] = KEY_W, + [KEYMAP_INDEX(5, 2)] = KEY_LEFTALT, + [KEYMAP_INDEX(5, 3)] = KEY_VOLUMEUP, + [KEYMAP_INDEX(5, 4)] = KEY_S, + [KEYMAP_INDEX(5, 5)] = KEY_Z, + [KEYMAP_INDEX(5, 6)] = KEY_1, + + [KEYMAP_INDEX(6, 0)] = KEY_I, + [KEYMAP_INDEX(6, 1)] = KEY_0, + [KEYMAP_INDEX(6, 2)] = KEY_O, + [KEYMAP_INDEX(6, 3)] = KEY_L, + [KEYMAP_INDEX(6, 4)] = KEY_COMMA, + [KEYMAP_INDEX(6, 5)] = KEY_DOT, + [KEYMAP_INDEX(6, 6)] = KEY_9, + + [KEYMAP_INDEX(7, 0)] = KEY_3, + [KEYMAP_INDEX(7, 1)] = KEY_E, + [KEYMAP_INDEX(7, 2)] = KEY_EMAIL, // @ + [KEYMAP_INDEX(7, 3)] = KEY_VOLUMEDOWN, + [KEYMAP_INDEX(7, 4)] = KEY_X, + [KEYMAP_INDEX(7, 5)] = KEY_F, + [KEYMAP_INDEX(7, 6)] = KEY_D +}; + +static const unsigned short trout_keymap_evt2_2[ARRAY_SIZE(trout_col_gpios) * ARRAY_SIZE(trout_row_gpios)] = { + [KEYMAP_INDEX(0, 0)] = KEY_BACK, + [KEYMAP_INDEX(0, 1)] = KEY_HOME, +// [KEYMAP_INDEX(0, 2)] = KEY_, + [KEYMAP_INDEX(0, 3)] = KEY_BACKSPACE, + [KEYMAP_INDEX(0, 4)] = KEY_ENTER, + [KEYMAP_INDEX(0, 5)] = KEY_RIGHTSHIFT, + [KEYMAP_INDEX(0, 6)] = KEY_P, + + [KEYMAP_INDEX(1, 0)] = KEY_MENU, /* external menu key */ + [KEYMAP_INDEX(1, 1)] = KEY_SEND, +// [KEYMAP_INDEX(1, 2)] = KEY_, + [KEYMAP_INDEX(1, 3)] = KEY_LEFTSHIFT, + [KEYMAP_INDEX(1, 4)] = KEY_A, + [KEYMAP_INDEX(1, 5)] = KEY_F1, /* qwerty menu key */ + [KEYMAP_INDEX(1, 6)] = KEY_Q, + + [KEYMAP_INDEX(2, 0)] = KEY_U, + [KEYMAP_INDEX(2, 1)] = KEY_7, + [KEYMAP_INDEX(2, 2)] = KEY_K, + [KEYMAP_INDEX(2, 3)] = KEY_J, + [KEYMAP_INDEX(2, 4)] = KEY_M, + [KEYMAP_INDEX(2, 5)] = KEY_DOT, + [KEYMAP_INDEX(2, 6)] = KEY_8, + + [KEYMAP_INDEX(3, 0)] = KEY_5, + [KEYMAP_INDEX(3, 1)] = KEY_6, + [KEYMAP_INDEX(3, 2)] = KEY_B, + [KEYMAP_INDEX(3, 3)] = KEY_H, + [KEYMAP_INDEX(3, 4)] = KEY_N, + [KEYMAP_INDEX(3, 5)] = KEY_SPACE, + [KEYMAP_INDEX(3, 6)] = KEY_Y, + + [KEYMAP_INDEX(4, 0)] = KEY_4, + [KEYMAP_INDEX(4, 1)] = KEY_R, + [KEYMAP_INDEX(4, 2)] = KEY_V, + [KEYMAP_INDEX(4, 3)] = KEY_G, + [KEYMAP_INDEX(4, 4)] = KEY_C, + [KEYMAP_INDEX(4, 5)] = KEY_EMAIL, // @ + [KEYMAP_INDEX(4, 6)] = KEY_T, + + [KEYMAP_INDEX(5, 0)] = KEY_2, + [KEYMAP_INDEX(5, 1)] = KEY_W, + [KEYMAP_INDEX(5, 2)] = KEY_LEFTALT, + [KEYMAP_INDEX(5, 3)] = KEY_VOLUMEUP, + [KEYMAP_INDEX(5, 4)] = KEY_S, + [KEYMAP_INDEX(5, 5)] = KEY_Z, + [KEYMAP_INDEX(5, 6)] = KEY_1, + + [KEYMAP_INDEX(6, 0)] = KEY_I, + [KEYMAP_INDEX(6, 1)] = KEY_0, + [KEYMAP_INDEX(6, 2)] = KEY_O, + [KEYMAP_INDEX(6, 3)] = KEY_L, + [KEYMAP_INDEX(6, 4)] = KEY_COMMA, + [KEYMAP_INDEX(6, 5)] = KEY_RIGHTALT, + [KEYMAP_INDEX(6, 6)] = KEY_9, + + [KEYMAP_INDEX(7, 0)] = KEY_3, + [KEYMAP_INDEX(7, 1)] = KEY_E, + [KEYMAP_INDEX(7, 2)] = KEY_COMPOSE, + [KEYMAP_INDEX(7, 3)] = KEY_VOLUMEDOWN, + [KEYMAP_INDEX(7, 4)] = KEY_X, + [KEYMAP_INDEX(7, 5)] = KEY_F, + [KEYMAP_INDEX(7, 6)] = KEY_D +}; + +static struct gpio_event_matrix_info trout_keypad_matrix_info = { + .info.func = gpio_event_matrix_func, + .keymap = trout_keymap, + .output_gpios = trout_col_gpios, + .input_gpios = trout_row_gpios, + .noutputs = ARRAY_SIZE(trout_col_gpios), + .ninputs = ARRAY_SIZE(trout_row_gpios), + .settle_time.tv.nsec = 40 * NSEC_PER_USEC, + .poll_time.tv.nsec = 20 * NSEC_PER_MSEC, + .flags = GPIOKPF_LEVEL_TRIGGERED_IRQ | GPIOKPF_REMOVE_PHANTOM_KEYS |GPIOKPF_PRINT_UNMAPPED_KEYS /*| GPIOKPF_PRINT_MAPPED_KEYS*/ +}; + +static struct gpio_event_direct_entry trout_keypad_nav_map[] = { + { TROUT_POWER_KEY, KEY_POWER }, + { TROUT_GPIO_CAM_BTN_STEP1_N, KEY_CAMERA-1 }, //steal KEY_HP + { TROUT_GPIO_CAM_BTN_STEP2_N, KEY_CAMERA }, +}; + +static struct gpio_event_direct_entry trout_keypad_nav_map_evt2[] = { + { TROUT_POWER_KEY, KEY_END }, + { TROUT_GPIO_CAM_BTN_STEP1_N, KEY_CAMERA-1 }, //steal KEY_HP + { TROUT_GPIO_CAM_BTN_STEP2_N, KEY_CAMERA }, +}; + +static struct gpio_event_input_info trout_keypad_nav_info = { + .info.func = gpio_event_input_func, + .flags = 0, + .type = EV_KEY, + .keymap = trout_keypad_nav_map, + .keymap_size = ARRAY_SIZE(trout_keypad_nav_map) +}; + +static struct gpio_event_direct_entry trout_keypad_switch_map[] = { + { TROUT_GPIO_SLIDING_DET, SW_LID } +}; + +static struct gpio_event_input_info trout_keypad_switch_info = { + .info.func = gpio_event_input_func, + .flags = 0, + .type = EV_SW, + .keymap = trout_keypad_switch_map, + .keymap_size = ARRAY_SIZE(trout_keypad_switch_map) +}; + +static struct gpio_event_info *trout_keypad_info[] = { + &trout_keypad_matrix_info.info, + &trout_keypad_nav_info.info, + &trout_keypad_switch_info.info, +}; + +static struct gpio_event_platform_data trout_keypad_data = { + .name = "trout-keypad", + .info = trout_keypad_info, + .info_count = ARRAY_SIZE(trout_keypad_info) +}; + +static struct platform_device trout_keypad_device = { + .name = GPIO_EVENT_DEV_NAME, + .id = 0, + .dev = { + .platform_data = &trout_keypad_data, + }, +}; + +static int __init trout_init_keypad(void) +{ + if (!machine_is_trout()) + return 0; + + switch (system_rev) { + case 0: + /* legacy default keylayout */ + break; + case 1: + /* v1 has a new keyboard layout */ + trout_keypad_matrix_info.keymap = trout_keymap_evt2_1; + trout_keypad_matrix_info.output_gpios = trout_col_gpios_evt2; + trout_keypad_matrix_info.input_gpios = trout_row_gpios_evt2; + + /* v1 has new direct keys */ + trout_keypad_nav_info.keymap = trout_keypad_nav_map_evt2; + trout_keypad_nav_info.keymap_size = ARRAY_SIZE(trout_keypad_nav_map_evt2); + + /* userspace needs to know about these changes as well */ + trout_keypad_data.name = "trout-keypad-v2"; + break; + default: /* 2, 3, 4 currently */ + /* v2 has a new keyboard layout */ + trout_keypad_matrix_info.keymap = trout_keymap_evt2_2; + trout_keypad_matrix_info.output_gpios = trout_col_gpios_evt2; + trout_keypad_matrix_info.input_gpios = trout_row_gpios_evt2; + + /* v2 has new direct keys */ + trout_keypad_nav_info.keymap = trout_keypad_nav_map_evt2; + trout_keypad_nav_info.keymap_size = ARRAY_SIZE(trout_keypad_nav_map_evt2); + + /* userspace needs to know about these changes as well */ + if (!strcmp(keycaps, "qwertz")) { + trout_keypad_data.name = "trout-keypad-qwertz"; + } else { + trout_keypad_data.name = "trout-keypad-v3"; + } + break; + } + return platform_device_register(&trout_keypad_device); +} + +device_initcall(trout_init_keypad); + -- cgit v1.2.3 From 09f5e501e82dab4638cd4d67161d3c35e0871e67 Mon Sep 17 00:00:00 2001 From: Rebecca Schultz Date: Mon, 29 Sep 2008 17:51:38 -0700 Subject: [ARM] msm: trout: obtain calibration data for the compass sensor Extracts compass calibraton from the ATAGs set up by the bootloader Signed-off-by: Rebecca Schultz --- arch/arm/mach-msm/Makefile | 1 + arch/arm/mach-msm/htc_akm_cal.c | 64 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 arch/arm/mach-msm/htc_akm_cal.c (limited to 'arch') diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index b597ef02d872..3518b1d71aea 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -20,3 +20,4 @@ obj-$(CONFIG_MSM_CPU_FREQ_SCREEN) += cpufreq.o obj-$(CONFIG_MACH_TROUT) += board-dream.o obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o board-halibut-keypad.o +obj-$(CONFIG_MACH_TROUT) += htc_akm_cal.o diff --git a/arch/arm/mach-msm/htc_akm_cal.c b/arch/arm/mach-msm/htc_akm_cal.c new file mode 100644 index 000000000000..943083fe0fbe --- /dev/null +++ b/arch/arm/mach-msm/htc_akm_cal.c @@ -0,0 +1,64 @@ +/* arch/arm/mach-msm/htc_akm_cal.c + * + * Code to extract compass calibration information from ATAG set up + * by the bootloader. + * + * Copyright (C) 2007-2008 HTC Corporation + * Author: Farmer Tseng + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 + +/* configuration tags specific to AKM8976 */ +#define ATAG_AKM8976 0x89768976 /* AKM8976 */ + +#define MAX_CALI_SIZE 0x1000U + +static char akm_cal_ram[MAX_CALI_SIZE]; + +char *get_akm_cal_ram(void) +{ + return(akm_cal_ram); +} +EXPORT_SYMBOL(get_akm_cal_ram); + +static int __init parse_tag_akm(const struct tag *tag) +{ + unsigned char *dptr = (unsigned char *)(&tag->u); + unsigned size; + + size = min((tag->hdr.size - 2) * sizeof(__u32), MAX_CALI_SIZE); + + printk(KERN_INFO "AKM Data size = %d , 0x%x, size = %d\n", + tag->hdr.size, tag->hdr.tag, size); + +#ifdef ATAG_COMPASS_DEBUG + unsigned i; + unsigned char *ptr; + + ptr = dptr; + printk(KERN_INFO + "AKM Data size = %d , 0x%x\n", + tag->hdr.size, tag->hdr.tag); + for (i = 0; i < size; i++) + printk(KERN_INFO "%02x ", *ptr++); +#endif + memcpy((void *)akm_cal_ram, (void *)dptr, size); + return 0; +} + +__tagtable(ATAG_AKM8976, parse_tag_akm); -- cgit v1.2.3 From 393deab0670c0cefa6b288a943576643c09540a9 Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Mon, 29 Sep 2008 17:55:10 -0700 Subject: [ARM] msm: trout: Code to extract wifi calibration data from ATAGs Signed-off-by: Rebecca Schultz --- arch/arm/mach-msm/Makefile | 2 +- arch/arm/mach-msm/htc_wifi_nvs.c | 56 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-msm/htc_wifi_nvs.c (limited to 'arch') diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 3518b1d71aea..c71d38dda3af 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -20,4 +20,4 @@ obj-$(CONFIG_MSM_CPU_FREQ_SCREEN) += cpufreq.o obj-$(CONFIG_MACH_TROUT) += board-dream.o obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o board-halibut-keypad.o -obj-$(CONFIG_MACH_TROUT) += htc_akm_cal.o +obj-$(CONFIG_MACH_TROUT) += htc_akm_cal.o htc_wifi_nvs.o diff --git a/arch/arm/mach-msm/htc_wifi_nvs.c b/arch/arm/mach-msm/htc_wifi_nvs.c new file mode 100644 index 000000000000..95b8c3bbae9d --- /dev/null +++ b/arch/arm/mach-msm/htc_wifi_nvs.c @@ -0,0 +1,56 @@ +/* arch/arm/mach-msm/htc_wifi_nvs.c + * + * Code to extract WiFi calibration information from ATAG set up + * by the bootloader. + * + * Copyright (C) 2008 Google, Inc. + * Author: Dmitry Shmidt + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 + +/* configuration tags specific to msm */ +#define ATAG_MSM_WIFI 0x57494649 /* MSM WiFi */ + +#define MAX_NVS_SIZE 0x800U +static unsigned char wifi_nvs_ram[MAX_NVS_SIZE]; + +unsigned char *get_wifi_nvs_ram( void ) +{ + return( wifi_nvs_ram ); +} +EXPORT_SYMBOL(get_wifi_nvs_ram); + +static int __init parse_tag_msm_wifi(const struct tag *tag) +{ + unsigned char *dptr = (unsigned char *)(&tag->u); + unsigned size; + + size = min((tag->hdr.size - 2) * sizeof(__u32), MAX_NVS_SIZE); +#ifdef ATAG_MSM_WIFI_DEBUG + unsigned i; + + printk("WiFi Data size = %d , 0x%x\n", tag->hdr.size, tag->hdr.tag); + for(i=0;( i < size );i++) { + printk("%02x ", *dptr++); + } +#endif + memcpy( (void *)wifi_nvs_ram, (void *)dptr, size ); + return 0; +} + +__tagtable(ATAG_MSM_WIFI, parse_tag_msm_wifi); -- cgit v1.2.3 From 6cc024ea66aad732f056ef092cdc1c0ca4bfcd4f Mon Sep 17 00:00:00 2001 From: Rebecca Schultz Date: Mon, 29 Sep 2008 17:58:03 -0700 Subject: [ARM] msm: trout: htc acoustic driver Allows userspace to set acoustic settings via memory mapped region Signed-off-by: Rebecca Schultz --- arch/arm/mach-msm/Makefile | 2 +- arch/arm/mach-msm/htc_acoustic.c | 99 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-msm/htc_acoustic.c (limited to 'arch') diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index c71d38dda3af..faecb271705c 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -20,4 +20,4 @@ obj-$(CONFIG_MSM_CPU_FREQ_SCREEN) += cpufreq.o obj-$(CONFIG_MACH_TROUT) += board-dream.o obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o board-halibut-keypad.o -obj-$(CONFIG_MACH_TROUT) += htc_akm_cal.o htc_wifi_nvs.o +obj-$(CONFIG_MACH_TROUT) += htc_akm_cal.o htc_wifi_nvs.o htc_acoustic.o diff --git a/arch/arm/mach-msm/htc_acoustic.c b/arch/arm/mach-msm/htc_acoustic.c new file mode 100644 index 000000000000..9fb92f588c0b --- /dev/null +++ b/arch/arm/mach-msm/htc_acoustic.c @@ -0,0 +1,99 @@ +/* arch/arm/mach-msm/htc_acoustic.c + * + * Copyright (C) 2007-2008 HTC Corporation + * Author: Laurence Chen + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 + +#define HTC_ACOUSTIC_TABLE_BASE_PHY_ADDR_START (0x01FE0000) +#define HTC_ACOUSTIC_TABLE_SIZE (0x10000) + +#define ACOUSTICE(x...) printk(KERN_ERR "[ACOUSTIC] " x) + +static int acoustic_mmap(struct file *file, struct vm_area_struct *vma) +{ + unsigned long pgoff; + size_t size = vma->vm_end - vma->vm_start; + + if (vma->vm_pgoff != 0) + return -EINVAL; + + if (size <= HTC_ACOUSTIC_TABLE_SIZE) + pgoff = HTC_ACOUSTIC_TABLE_BASE_PHY_ADDR_START >> PAGE_SHIFT; + else + return -EINVAL; + + vma->vm_flags |= VM_IO | VM_RESERVED; + + if (io_remap_pfn_range(vma, vma->vm_start, pgoff, + size, vma->vm_page_prot)) + return -EAGAIN; + + return 0; +} + +static int acoustic_open(struct inode *inode, struct file *file) +{ + return 0; +} + +static int acoustic_release(struct inode *inode, struct file *file) +{ + return 0; +} + +static struct file_operations acoustic_fops = { + .owner = THIS_MODULE, + .open = acoustic_open, + .release = acoustic_release, + .mmap = acoustic_mmap, +}; + +static struct miscdevice acoustic_misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = "htc-acoustic", + .fops = &acoustic_fops, +}; + +static int __init acoustic_init(void) +{ + int ret; + + ret = misc_register(&acoustic_misc); + if (ret < 0) { + ACOUSTICE("failed to register misc device!\n"); + return ret; + } + + return 0; +} + +static void __exit acoustic_exit(void) +{ + int ret; + + ret = misc_deregister(&acoustic_misc); + if (ret < 0) + ACOUSTICE("failed to unregister misc device!\n"); +} + +module_init(acoustic_init); +module_exit(acoustic_exit); + +MODULE_AUTHOR("Laurence Chen "); +MODULE_DESCRIPTION("HTC acoustic driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From f01d4ab239467c0b67ede607d3363f0f29b30fce Mon Sep 17 00:00:00 2001 From: Nick Pelly Date: Mon, 29 Sep 2008 18:19:37 -0700 Subject: [ARM] msm: trout: htc2wire driver to support htc headsets Signed-off-by: Rebecca Schultz --- arch/arm/mach-msm/Kconfig | 8 + arch/arm/mach-msm/Makefile | 1 + arch/arm/mach-msm/board-trout-h2w.c | 548 ++++++++++++++++++++++++++++++++++++ 3 files changed, 557 insertions(+) create mode 100644 arch/arm/mach-msm/board-trout-h2w.c (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index 99c0a0151a86..f2fbf6d1cb7f 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -63,6 +63,14 @@ config MACH_TROUT help Support for the HTC Dream, T-Mobile G1, Android ADP1 devices. +config TROUT_H2W + tristate "HTC 2 Wire detection driver" + default n + help + Provides support for detecting HTC 2 wire devices, such as wired + headset, on the trout platform. Can be used with the msm serial + debugger, but not with serial console. + choice prompt "Default Timer" default MSM7X00A_USE_GP_TIMER diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index faecb271705c..eb1fc0729c75 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -21,3 +21,4 @@ obj-$(CONFIG_MSM_CPU_FREQ_SCREEN) += cpufreq.o obj-$(CONFIG_MACH_TROUT) += board-dream.o obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o board-halibut-keypad.o obj-$(CONFIG_MACH_TROUT) += htc_akm_cal.o htc_wifi_nvs.o htc_acoustic.o +obj-$(CONFIG_TROUT_H2W) += board-trout-h2w.o diff --git a/arch/arm/mach-msm/board-trout-h2w.c b/arch/arm/mach-msm/board-trout-h2w.c new file mode 100644 index 000000000000..f8282b4e4899 --- /dev/null +++ b/arch/arm/mach-msm/board-trout-h2w.c @@ -0,0 +1,548 @@ +/* + * H2W device detection driver. + * + * Copyright (C) 2008 HTC Corporation. + * Copyright (C) 2008 Google, Inc. + * + * Authors: + * Laurence Chen + * Nick Pelly + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +/* For detecting HTC 2 Wire devices, such as wired headset. + + Logically, the H2W driver is always present, and H2W state (hi->state) + indicates what is currently plugged into the H2W interface. + + When the headset is plugged in, CABLE_IN1 is pulled low. When the headset + button is pressed, CABLE_IN2 is pulled low. These two lines are shared with + the TX and RX (respectively) of UART3 - used for serial debugging. + + This headset driver keeps the CPLD configured as UART3 for as long as + possible, so that we can do serial FIQ debugging even when the kernel is + locked and this driver no longer runs. So it only configures the CPLD to + GPIO while the headset is plugged in, and for 10ms during detection work. + + Unfortunately we can't leave the CPLD as UART3 while a headset is plugged + in, UART3 is pullup on TX but the headset is pull-down, causing a 55 mA + drain on trout. + + The headset detection work involves setting CPLD to GPIO, and then pulling + CABLE_IN1 high with a stronger pullup than usual. A H2W headset will still + pull this line low, whereas other attachments such as a serial console + would get pulled up by this stronger pullup. + + Headset insertion/removal causes UEvent's to be sent, and + /sys/class/switch/h2w/state to be updated. + + Button presses are interpreted as input event (KEY_MEDIA). Button presses + are ignored if the headset is plugged in, so the buttons on 11 pin -> 3.5mm + jack adapters do not work until a headset is plugged into the adapter. This + is to avoid serial RX traffic causing spurious button press events. + + We tend to check the status of CABLE_IN1 a few more times than strictly + necessary during headset detection, to avoid spurious headset insertion + events caused by serial debugger TX traffic. +*/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "board-trout.h" + +#ifdef CONFIG_DEBUG_TROUT_H2W +#define H2W_DBG(fmt, arg...) printk(KERN_INFO "[H2W] %s " fmt "\n", __FUNCTION__, ## arg) +#else +#define H2W_DBG(fmt, arg...) do {} while (0) +#endif + +static struct workqueue_struct *g_detection_work_queue; +static void detection_work(struct work_struct *work); +static DECLARE_WORK(g_detection_work, detection_work); +enum { + NO_DEVICE = 0, + HTC_HEADSET = 1, +}; + +enum { + UART3 = 0, + GPIO = 1, +}; + +struct h2w_info { + struct switch_dev sdev; + struct input_dev *input; + + atomic_t btn_state; + int ignore_btn; + + unsigned int irq; + unsigned int irq_btn; + + struct hrtimer timer; + ktime_t debounce_time; + + struct hrtimer btn_timer; + ktime_t btn_debounce_time; +}; +static struct h2w_info *hi; + +static ssize_t trout_h2w_print_name(struct switch_dev *sdev, char *buf) +{ + switch (switch_get_state(&hi->sdev)) { + case NO_DEVICE: + return sprintf(buf, "No Device\n"); + case HTC_HEADSET: + return sprintf(buf, "Headset\n"); + } + return -EINVAL; +} + +static void configure_cpld(int route) +{ + H2W_DBG(" route = %s", route == UART3 ? "UART3" : "GPIO"); + switch (route) { + case UART3: + gpio_set_value(TROUT_GPIO_H2W_SEL0, 0); + gpio_set_value(TROUT_GPIO_H2W_SEL1, 1); + break; + case GPIO: + gpio_set_value(TROUT_GPIO_H2W_SEL0, 0); + gpio_set_value(TROUT_GPIO_H2W_SEL1, 0); + break; + } +} + +static void button_pressed(void) +{ + H2W_DBG(""); + atomic_set(&hi->btn_state, 1); + input_report_key(hi->input, KEY_MEDIA, 1); + input_sync(hi->input); +} + +static void button_released(void) +{ + H2W_DBG(""); + atomic_set(&hi->btn_state, 0); + input_report_key(hi->input, KEY_MEDIA, 0); + input_sync(hi->input); +} + +#ifdef CONFIG_MSM_SERIAL_DEBUGGER +extern void msm_serial_debug_enable(int); +#endif + +static void insert_headset(void) +{ + unsigned long irq_flags; + + H2W_DBG(""); + + switch_set_state(&hi->sdev, HTC_HEADSET); + configure_cpld(GPIO); + +#ifdef CONFIG_MSM_SERIAL_DEBUGGER + msm_serial_debug_enable(false); +#endif + + + /* On some non-standard headset adapters (usually those without a + * button) the btn line is pulled down at the same time as the detect + * line. We can check here by sampling the button line, if it is + * low then it is probably a bad adapter so ignore the button. + * If the button is released then we stop ignoring the button, so that + * the user can recover from the situation where a headset is plugged + * in with button held down. + */ + hi->ignore_btn = !gpio_get_value(TROUT_GPIO_CABLE_IN2); + + /* Enable button irq */ + local_irq_save(irq_flags); + enable_irq(hi->irq_btn); + local_irq_restore(irq_flags); + + hi->debounce_time = ktime_set(0, 20000000); /* 20 ms */ +} + +static void remove_headset(void) +{ + unsigned long irq_flags; + + H2W_DBG(""); + + switch_set_state(&hi->sdev, NO_DEVICE); + configure_cpld(UART3); + + /* Disable button */ + local_irq_save(irq_flags); + disable_irq(hi->irq_btn); + local_irq_restore(irq_flags); + + if (atomic_read(&hi->btn_state)) + button_released(); + + hi->debounce_time = ktime_set(0, 100000000); /* 100 ms */ +} + +static void detection_work(struct work_struct *work) +{ + unsigned long irq_flags; + int clk, cable_in1; + + H2W_DBG(""); + + if (gpio_get_value(TROUT_GPIO_CABLE_IN1) != 0) { + /* Headset not plugged in */ + if (switch_get_state(&hi->sdev) == HTC_HEADSET) + remove_headset(); + return; + } + + /* Something plugged in, lets make sure its a headset */ + + /* Switch CPLD to GPIO to do detection */ + configure_cpld(GPIO); + /* Disable headset interrupt while detecting.*/ + local_irq_save(irq_flags); + disable_irq(hi->irq); + local_irq_restore(irq_flags); + + /* Set GPIO_CABLE_IN1 as output high */ + gpio_direction_output(TROUT_GPIO_CABLE_IN1, 1); + /* Delay 10ms for pin stable. */ + msleep(10); + /* Save H2W_CLK */ + clk = gpio_get_value(TROUT_GPIO_H2W_CLK_GPI); + /* Set GPIO_CABLE_IN1 as input */ + gpio_direction_input(TROUT_GPIO_CABLE_IN1); + + /* Restore IRQs */ + local_irq_save(irq_flags); + enable_irq(hi->irq); + local_irq_restore(irq_flags); + + cable_in1 = gpio_get_value(TROUT_GPIO_CABLE_IN1); + + if (cable_in1 == 0 && clk == 0) { + if (switch_get_state(&hi->sdev) == NO_DEVICE) + insert_headset(); + } else { + configure_cpld(UART3); + H2W_DBG("CABLE_IN1 was low, but not a headset " + "(recent cable_in1 = %d, clk = %d)", cable_in1, clk); + } +} + +static enum hrtimer_restart button_event_timer_func(struct hrtimer *data) +{ + H2W_DBG(""); + + if (switch_get_state(&hi->sdev) == HTC_HEADSET) { + if (gpio_get_value(TROUT_GPIO_CABLE_IN2)) { + if (hi->ignore_btn) + hi->ignore_btn = 0; + else if (atomic_read(&hi->btn_state)) + button_released(); + } else { + if (!hi->ignore_btn && !atomic_read(&hi->btn_state)) + button_pressed(); + } + } + + return HRTIMER_NORESTART; +} + +static enum hrtimer_restart detect_event_timer_func(struct hrtimer *data) +{ + H2W_DBG(""); + + queue_work(g_detection_work_queue, &g_detection_work); + return HRTIMER_NORESTART; +} + +static irqreturn_t detect_irq_handler(int irq, void *dev_id) +{ + int value1, value2; + int retry_limit = 10; + + H2W_DBG(""); + do { + value1 = gpio_get_value(TROUT_GPIO_CABLE_IN1); + set_irq_type(hi->irq, value1 ? + IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH); + value2 = gpio_get_value(TROUT_GPIO_CABLE_IN1); + } while (value1 != value2 && retry_limit-- > 0); + + H2W_DBG("value2 = %d (%d retries)", value2, (10-retry_limit)); + + if ((switch_get_state(&hi->sdev) == NO_DEVICE) ^ value2) { + if (switch_get_state(&hi->sdev) == HTC_HEADSET) + hi->ignore_btn = 1; + /* Do the rest of the work in timer context */ + hrtimer_start(&hi->timer, hi->debounce_time, HRTIMER_MODE_REL); + } + + return IRQ_HANDLED; +} + +static irqreturn_t button_irq_handler(int irq, void *dev_id) +{ + int value1, value2; + int retry_limit = 10; + + H2W_DBG(""); + do { + value1 = gpio_get_value(TROUT_GPIO_CABLE_IN2); + set_irq_type(hi->irq_btn, value1 ? + IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH); + value2 = gpio_get_value(TROUT_GPIO_CABLE_IN2); + } while (value1 != value2 && retry_limit-- > 0); + + H2W_DBG("value2 = %d (%d retries)", value2, (10-retry_limit)); + + hrtimer_start(&hi->btn_timer, hi->btn_debounce_time, HRTIMER_MODE_REL); + + return IRQ_HANDLED; +} + +#if defined(CONFIG_DEBUG_FS) +static void h2w_debug_set(void *data, u64 val) +{ + switch_set_state(&hi->sdev, (int)val); +} + +static u64 h2w_debug_get(void *data) +{ + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(h2w_debug_fops, h2w_debug_get, h2w_debug_set, "%llu\n"); +static int __init h2w_debug_init(void) +{ + struct dentry *dent; + + dent = debugfs_create_dir("h2w", 0); + if (IS_ERR(dent)) + return PTR_ERR(dent); + + debugfs_create_file("state", 0644, dent, NULL, &h2w_debug_fops); + + return 0; +} + +device_initcall(h2w_debug_init); +#endif + +static int trout_h2w_probe(struct platform_device *pdev) +{ + int ret; + unsigned long irq_flags; + + printk(KERN_INFO "H2W: Registering H2W (headset) driver\n"); + hi = kzalloc(sizeof(struct h2w_info), GFP_KERNEL); + if (!hi) + return -ENOMEM; + + atomic_set(&hi->btn_state, 0); + hi->ignore_btn = 0; + + hi->debounce_time = ktime_set(0, 100000000); /* 100 ms */ + hi->btn_debounce_time = ktime_set(0, 10000000); /* 10 ms */ + hi->sdev.name = "h2w"; + hi->sdev.print_name = trout_h2w_print_name; + + ret = switch_dev_register(&hi->sdev); + if (ret < 0) + goto err_switch_dev_register; + + g_detection_work_queue = create_workqueue("detection"); + if (g_detection_work_queue == NULL) { + ret = -ENOMEM; + goto err_create_work_queue; + } + + ret = gpio_request(TROUT_GPIO_CABLE_IN1, "h2w_detect"); + if (ret < 0) + goto err_request_detect_gpio; + + ret = gpio_request(TROUT_GPIO_CABLE_IN2, "h2w_button"); + if (ret < 0) + goto err_request_button_gpio; + + ret = gpio_direction_input(TROUT_GPIO_CABLE_IN1); + if (ret < 0) + goto err_set_detect_gpio; + + ret = gpio_direction_input(TROUT_GPIO_CABLE_IN2); + if (ret < 0) + goto err_set_button_gpio; + + hi->irq = gpio_to_irq(TROUT_GPIO_CABLE_IN1); + if (hi->irq < 0) { + ret = hi->irq; + goto err_get_h2w_detect_irq_num_failed; + } + + hi->irq_btn = gpio_to_irq(TROUT_GPIO_CABLE_IN2); + if (hi->irq_btn < 0) { + ret = hi->irq_btn; + goto err_get_button_irq_num_failed; + } + + /* Set CPLD MUX to H2W <-> CPLD GPIO */ + configure_cpld(UART3); + /* Set the CPLD connected H2W GPIO's to input */ + gpio_set_value(TROUT_GPIO_H2W_CLK_DIR, 0); + gpio_set_value(TROUT_GPIO_H2W_DAT_DIR, 0); + + hrtimer_init(&hi->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + hi->timer.function = detect_event_timer_func; + hrtimer_init(&hi->btn_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + hi->btn_timer.function = button_event_timer_func; + + local_irq_save(irq_flags); + + ret = request_irq(hi->irq, detect_irq_handler, + IRQF_TRIGGER_LOW, "h2w_detect", NULL); + if (ret < 0) + goto err_request_detect_irq; + + ret = request_irq(hi->irq_btn, button_irq_handler, + IRQF_TRIGGER_LOW, "h2w_button", NULL); + if (ret < 0) + goto err_request_h2w_headset_button_irq; + + ret = set_irq_wake(hi->irq, 1); + if (ret < 0) + goto err_request_input_dev; + ret = set_irq_wake(hi->irq_btn, 1); + if (ret < 0) + goto err_request_input_dev; + + /* Disable button until plugged in */ + disable_irq(hi->irq_btn); + local_irq_restore(irq_flags); + + hi->input = input_allocate_device(); + if (!hi->input) { + ret = -ENOMEM; + goto err_request_input_dev; + } + + hi->input->name = "h2w headset"; + hi->input->evbit[0] = BIT_MASK(EV_KEY); + hi->input->keybit[BIT_WORD(KEY_MEDIA)] = BIT_MASK(KEY_MEDIA); + + ret = input_register_device(hi->input); + if (ret < 0) + goto err_register_input_dev; + + return 0; + +err_register_input_dev: + input_free_device(hi->input); +err_request_input_dev: + free_irq(hi->irq_btn, 0); +err_request_h2w_headset_button_irq: + free_irq(hi->irq, 0); +err_request_detect_irq: + local_irq_restore(irq_flags); +err_get_button_irq_num_failed: +err_get_h2w_detect_irq_num_failed: +err_set_button_gpio: +err_set_detect_gpio: + gpio_free(TROUT_GPIO_CABLE_IN2); +err_request_button_gpio: + gpio_free(TROUT_GPIO_CABLE_IN1); +err_request_detect_gpio: + destroy_workqueue(g_detection_work_queue); +err_create_work_queue: + switch_dev_unregister(&hi->sdev); +err_switch_dev_register: + printk(KERN_ERR "H2W: Failed to register driver\n"); + + return ret; +} + +static int trout_h2w_remove(struct platform_device *pdev) +{ + H2W_DBG(""); + if (switch_get_state(&hi->sdev)) + remove_headset(); + input_unregister_device(hi->input); + gpio_free(TROUT_GPIO_CABLE_IN2); + gpio_free(TROUT_GPIO_CABLE_IN1); + free_irq(hi->irq_btn, 0); + free_irq(hi->irq, 0); + destroy_workqueue(g_detection_work_queue); + switch_dev_unregister(&hi->sdev); + + return 0; +} + +static struct platform_device trout_h2w_device = { + .name = "trout-h2w", +}; + +static struct platform_driver trout_h2w_driver = { + .probe = trout_h2w_probe, + .remove = trout_h2w_remove, + .driver = { + .name = "trout-h2w", + .owner = THIS_MODULE, + }, +}; + +static int __init trout_h2w_init(void) +{ + int ret; + H2W_DBG(""); + ret = platform_driver_register(&trout_h2w_driver); + if (ret) + return ret; + return platform_device_register(&trout_h2w_device); +} + +static void __exit trout_h2w_exit(void) +{ + platform_device_unregister(&trout_h2w_device); + platform_driver_unregister(&trout_h2w_driver); +} + +module_init(trout_h2w_init); +module_exit(trout_h2w_exit); + +MODULE_AUTHOR("Laurence Chen "); +MODULE_DESCRIPTION("HTC 2 Wire detection driver for trout"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 58722f247509fbec8bdd379ee8f9dbdf00844e9e Mon Sep 17 00:00:00 2001 From: Brian Swetland Date: Thu, 27 Mar 2008 18:18:01 -0700 Subject: [ARM] msm: add hook for vbus state notification The msm_hsusb_set_vbus_state() function allows the board file, battery/charger/power code, etc to inform the USB driver about the presence of VBUS. The driver now puts the USB client controller online when VBUS is present and suspends the PHY when it goes away. Signed-off-by: Brian Swetland --- arch/arm/mach-msm/include/mach/board.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h index b730b4a59511..51dce01a2197 100644 --- a/arch/arm/mach-msm/include/mach/board.h +++ b/arch/arm/mach-msm/include/mach/board.h @@ -44,4 +44,10 @@ void __init msm_init_irq(void); void __init msm_clock_init(void); void __init msm_acpu_clock_init(struct msm_acpu_clock_platform_data *); +#if defined(CONFIG_USB_FUNCTION_MSM_HSUSB) +void msm_hsusb_set_vbus_state(int online); +#else +static inline void msm_hsusb_set_vbus_state(int online) {} +#endif + #endif -- cgit v1.2.3 From b02760f800d6860e5675bea7b2b65e0aedb79885 Mon Sep 17 00:00:00 2001 From: Rebecca Schultz Date: Mon, 29 Sep 2008 18:24:57 -0700 Subject: [ARM] trout: htc platform battery driver Uses rpc to communicate with battery state/charging service on the baseband processor. Signed-off-by: Rebecca Schultz --- arch/arm/mach-msm/Kconfig | 5 + arch/arm/mach-msm/Makefile | 1 + arch/arm/mach-msm/htc_battery.c | 769 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 775 insertions(+) create mode 100644 arch/arm/mach-msm/htc_battery.c (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index f2fbf6d1cb7f..dc37099e83ae 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -71,6 +71,11 @@ config TROUT_H2W headset, on the trout platform. Can be used with the msm serial debugger, but not with serial console. +config TROUT_BATTCHG + depends on MACH_TROUT && POWER_SUPPLY + default y + bool "Trout battery / charger driver" + choice prompt "Default Timer" default MSM7X00A_USE_GP_TIMER diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index eb1fc0729c75..81d3bdb7e08b 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -22,3 +22,4 @@ obj-$(CONFIG_MACH_TROUT) += board-dream.o obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o board-halibut-keypad.o obj-$(CONFIG_MACH_TROUT) += htc_akm_cal.o htc_wifi_nvs.o htc_acoustic.o obj-$(CONFIG_TROUT_H2W) += board-trout-h2w.o +obj-$(CONFIG_TROUT_BATTCHG) += htc_battery.o diff --git a/arch/arm/mach-msm/htc_battery.c b/arch/arm/mach-msm/htc_battery.c new file mode 100644 index 000000000000..7320edbff1a9 --- /dev/null +++ b/arch/arm/mach-msm/htc_battery.c @@ -0,0 +1,769 @@ +/* arch/arm/mach-msm/htc_battery.c + * + * Copyright (C) 2008 HTC Corporation. + * Copyright (C) 2008 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 + +static struct wake_lock vbus_wake_lock; + +#define TRACE_BATT 0 + +#if TRACE_BATT +#define BATT(x...) printk(KERN_INFO "[BATT] " x) +#else +#define BATT(x...) do {} while (0) +#endif + +/* rpc related */ +#define APP_BATT_PDEV_NAME "rs30100001:00000000" +#define APP_BATT_PROG 0x30100001 +#define APP_BATT_VER 0 +#define HTC_PROCEDURE_BATTERY_NULL 0 +#define HTC_PROCEDURE_GET_BATT_LEVEL 1 +#define HTC_PROCEDURE_GET_BATT_INFO 2 +#define HTC_PROCEDURE_GET_CABLE_STATUS 3 +#define HTC_PROCEDURE_SET_BATT_DELTA 4 + +/* module debugger */ +#define HTC_BATTERY_DEBUG 1 +#define BATTERY_PREVENTION 1 + +/* Enable this will shut down if no battery */ +#define ENABLE_BATTERY_DETECTION 0 + +#define GPIO_BATTERY_DETECTION 21 +#define GPIO_BATTERY_CHARGER_EN 128 + +/* Charge current selection */ +#define GPIO_BATTERY_CHARGER_CURRENT 129 + +typedef enum { + DISABLE = 0, + ENABLE_SLOW_CHG, + ENABLE_FAST_CHG +} batt_ctl_t; + +/* This order is the same as htc_power_supplies[] + * And it's also the same as htc_cable_status_update() + */ +typedef enum { + CHARGER_BATTERY = 0, + CHARGER_USB, + CHARGER_AC +} charger_type_t; + +struct battery_info_reply { + u32 batt_id; /* Battery ID from ADC */ + u32 batt_vol; /* Battery voltage from ADC */ + u32 batt_temp; /* Battery Temperature (C) from formula and ADC */ + u32 batt_current; /* Battery current from ADC */ + u32 level; /* formula */ + u32 charging_source; /* 0: no cable, 1:usb, 2:AC */ + u32 charging_enabled; /* 0: Disable, 1: Enable */ + u32 full_bat; /* Full capacity of battery (mAh) */ +}; + +struct htc_battery_info { + int present; + unsigned long update_time; + + /* lock to protect the battery info */ + struct mutex lock; + + /* lock held while calling the arm9 to query the battery info */ + struct mutex rpc_lock; + struct battery_info_reply rep; +}; + +static struct msm_rpc_endpoint *endpoint; + +static struct htc_battery_info htc_batt_info; + +static unsigned int cache_time = 1000; + +static int htc_battery_initial = 0; + +static enum power_supply_property htc_battery_properties[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_CAPACITY, +}; + +static enum power_supply_property htc_power_properties[] = { + POWER_SUPPLY_PROP_ONLINE, +}; + +static char *supply_list[] = { + "battery", +}; + +/* HTC dedicated attributes */ +static ssize_t htc_battery_show_property(struct device *dev, + struct device_attribute *attr, + char *buf); + +static int htc_power_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val); + +static int htc_battery_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val); + +static struct power_supply htc_power_supplies[] = { + { + .name = "battery", + .type = POWER_SUPPLY_TYPE_BATTERY, + .properties = htc_battery_properties, + .num_properties = ARRAY_SIZE(htc_battery_properties), + .get_property = htc_battery_get_property, + }, + { + .name = "usb", + .type = POWER_SUPPLY_TYPE_USB, + .supplied_to = supply_list, + .num_supplicants = ARRAY_SIZE(supply_list), + .properties = htc_power_properties, + .num_properties = ARRAY_SIZE(htc_power_properties), + .get_property = htc_power_get_property, + }, + { + .name = "ac", + .type = POWER_SUPPLY_TYPE_MAINS, + .supplied_to = supply_list, + .num_supplicants = ARRAY_SIZE(supply_list), + .properties = htc_power_properties, + .num_properties = ARRAY_SIZE(htc_power_properties), + .get_property = htc_power_get_property, + }, +}; + + +/* -------------------------------------------------------------------------- */ + +#if defined(CONFIG_DEBUG_FS) +int htc_battery_set_charging(batt_ctl_t ctl); +static int batt_debug_set(void *data, u64 val) +{ + return htc_battery_set_charging((batt_ctl_t) val); +} + +static int batt_debug_get(void *data, u64 *val) +{ + return -ENOSYS; +} + +DEFINE_SIMPLE_ATTRIBUTE(batt_debug_fops, batt_debug_get, batt_debug_set, "%llu\n"); +static int __init batt_debug_init(void) +{ + struct dentry *dent; + + dent = debugfs_create_dir("htc_battery", 0); + if (IS_ERR(dent)) + return PTR_ERR(dent); + + debugfs_create_file("charger_state", 0644, dent, NULL, &batt_debug_fops); + + return 0; +} + +device_initcall(batt_debug_init); +#endif + +static int init_batt_gpio(void) +{ + if (gpio_request(GPIO_BATTERY_DETECTION, "batt_detect") < 0) + goto gpio_failed; + if (gpio_request(GPIO_BATTERY_CHARGER_EN, "charger_en") < 0) + goto gpio_failed; + if (gpio_request(GPIO_BATTERY_CHARGER_CURRENT, "charge_current") < 0) + goto gpio_failed; + + return 0; + +gpio_failed: + return -EINVAL; + +} + +/* + * battery_charging_ctrl - battery charing control. + * @ctl: battery control command + * + */ +static int battery_charging_ctrl(batt_ctl_t ctl) +{ + int result = 0; + + switch (ctl) { + case DISABLE: + BATT("charger OFF\n"); + /* 0 for enable; 1 disable */ + result = gpio_direction_output(GPIO_BATTERY_CHARGER_EN, 1); + break; + case ENABLE_SLOW_CHG: + BATT("charger ON (SLOW)\n"); + result = gpio_direction_output(GPIO_BATTERY_CHARGER_CURRENT, 0); + result = gpio_direction_output(GPIO_BATTERY_CHARGER_EN, 0); + break; + case ENABLE_FAST_CHG: + BATT("charger ON (FAST)\n"); + result = gpio_direction_output(GPIO_BATTERY_CHARGER_CURRENT, 1); + result = gpio_direction_output(GPIO_BATTERY_CHARGER_EN, 0); + break; + default: + printk(KERN_ERR "Not supported battery ctr called.!\n"); + result = -EINVAL; + break; + } + + return result; +} + +int htc_battery_set_charging(batt_ctl_t ctl) +{ + int rc; + + if ((rc = battery_charging_ctrl(ctl)) < 0) + goto result; + + if (!htc_battery_initial) { + htc_batt_info.rep.charging_enabled = ctl & 0x3; + } else { + mutex_lock(&htc_batt_info.lock); + htc_batt_info.rep.charging_enabled = ctl & 0x3; + mutex_unlock(&htc_batt_info.lock); + } +result: + return rc; +} + +int htc_battery_status_update(u32 curr_level) +{ + int notify; + if (!htc_battery_initial) + return 0; + + mutex_lock(&htc_batt_info.lock); + notify = (htc_batt_info.rep.level != curr_level); + htc_batt_info.rep.level = curr_level; + mutex_unlock(&htc_batt_info.lock); + + if (notify) + power_supply_changed(&htc_power_supplies[CHARGER_BATTERY]); + return 0; +} + +int htc_cable_status_update(int status) +{ + int rc = 0; + unsigned source; + + if (!htc_battery_initial) + return 0; + + mutex_lock(&htc_batt_info.lock); + switch(status) { + case CHARGER_BATTERY: + BATT("cable NOT PRESENT\n"); + htc_batt_info.rep.charging_source = CHARGER_BATTERY; + break; + case CHARGER_USB: + BATT("cable USB\n"); + htc_batt_info.rep.charging_source = CHARGER_USB; + break; + case CHARGER_AC: + BATT("cable AC\n"); + htc_batt_info.rep.charging_source = CHARGER_AC; + break; + default: + printk(KERN_ERR "%s: Not supported cable status received!\n", + __FUNCTION__); + rc = -EINVAL; + } + source = htc_batt_info.rep.charging_source; + mutex_unlock(&htc_batt_info.lock); + + msm_hsusb_set_vbus_state(source == CHARGER_USB); + if (source == CHARGER_USB) { + wake_lock(&vbus_wake_lock); + } else { + /* give userspace some time to see the uevent and update + * LED state or whatnot... + */ + wake_lock_timeout(&vbus_wake_lock, HZ / 2); + } + + /* if the power source changes, all power supplies may change state */ + power_supply_changed(&htc_power_supplies[CHARGER_BATTERY]); + power_supply_changed(&htc_power_supplies[CHARGER_USB]); + power_supply_changed(&htc_power_supplies[CHARGER_AC]); + + return rc; +} + +static int htc_get_batt_info(struct battery_info_reply *buffer) +{ + struct rpc_request_hdr req; + + struct htc_get_batt_info_rep { + struct rpc_reply_hdr hdr; + struct battery_info_reply info; + } rep; + + int rc; + + if (buffer == NULL) + return -EINVAL; + + rc = msm_rpc_call_reply(endpoint, HTC_PROCEDURE_GET_BATT_INFO, + &req, sizeof(req), + &rep, sizeof(rep), + 5 * HZ); + if ( rc < 0 ) + return rc; + + mutex_lock(&htc_batt_info.lock); + buffer->batt_id = be32_to_cpu(rep.info.batt_id); + buffer->batt_vol = be32_to_cpu(rep.info.batt_vol); + buffer->batt_temp = be32_to_cpu(rep.info.batt_temp); + buffer->batt_current = be32_to_cpu(rep.info.batt_current); + buffer->level = be32_to_cpu(rep.info.level); + buffer->charging_source = be32_to_cpu(rep.info.charging_source); + buffer->charging_enabled = be32_to_cpu(rep.info.charging_enabled); + buffer->full_bat = be32_to_cpu(rep.info.full_bat); + mutex_unlock(&htc_batt_info.lock); + + return 0; +} + +#if 0 +static int htc_get_cable_status(void) +{ + + struct rpc_request_hdr req; + + struct htc_get_cable_status_rep { + struct rpc_reply_hdr hdr; + int status; + } rep; + + int rc; + + rc = msm_rpc_call_reply(endpoint, HTC_PROCEDURE_GET_CABLE_STATUS, + &req, sizeof(req), + &rep, sizeof(rep), + 5 * HZ); + if (rc < 0) + return rc; + + return be32_to_cpu(rep.status); +} +#endif + +/* -------------------------------------------------------------------------- */ +static int htc_power_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + charger_type_t charger; + + mutex_lock(&htc_batt_info.lock); + charger = htc_batt_info.rep.charging_source; + mutex_unlock(&htc_batt_info.lock); + + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + if (psy->type == POWER_SUPPLY_TYPE_MAINS) + val->intval = (charger == CHARGER_AC ? 1 : 0); + else if (psy->type == POWER_SUPPLY_TYPE_USB) + val->intval = (charger == CHARGER_USB ? 1 : 0); + else + val->intval = 0; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int htc_battery_get_charging_status(void) +{ + u32 level; + charger_type_t charger; + int ret; + + mutex_lock(&htc_batt_info.lock); + charger = htc_batt_info.rep.charging_source; + + switch (charger) { + case CHARGER_BATTERY: + ret = POWER_SUPPLY_STATUS_NOT_CHARGING; + break; + case CHARGER_USB: + case CHARGER_AC: + level = htc_batt_info.rep.level; + if (level == 100) + ret = POWER_SUPPLY_STATUS_FULL; + else + ret = POWER_SUPPLY_STATUS_CHARGING; + break; + default: + ret = POWER_SUPPLY_STATUS_UNKNOWN; + } + mutex_unlock(&htc_batt_info.lock); + return ret; +} + +static int htc_battery_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + val->intval = htc_battery_get_charging_status(); + break; + case POWER_SUPPLY_PROP_HEALTH: + val->intval = POWER_SUPPLY_HEALTH_GOOD; + break; + case POWER_SUPPLY_PROP_PRESENT: + val->intval = htc_batt_info.present; + break; + case POWER_SUPPLY_PROP_TECHNOLOGY: + val->intval = POWER_SUPPLY_TECHNOLOGY_LION; + break; + case POWER_SUPPLY_PROP_CAPACITY: + mutex_lock(&htc_batt_info.lock); + val->intval = htc_batt_info.rep.level; + mutex_unlock(&htc_batt_info.lock); + break; + default: + return -EINVAL; + } + + return 0; +} + +#define HTC_BATTERY_ATTR(_name) \ +{ \ + .attr = { .name = #_name, .mode = S_IRUGO, .owner = THIS_MODULE }, \ + .show = htc_battery_show_property, \ + .store = NULL, \ +} + +static struct device_attribute htc_battery_attrs[] = { + HTC_BATTERY_ATTR(batt_id), + HTC_BATTERY_ATTR(batt_vol), + HTC_BATTERY_ATTR(batt_temp), + HTC_BATTERY_ATTR(batt_current), + HTC_BATTERY_ATTR(charging_source), + HTC_BATTERY_ATTR(charging_enabled), + HTC_BATTERY_ATTR(full_bat), +}; + +enum { + BATT_ID = 0, + BATT_VOL, + BATT_TEMP, + BATT_CURRENT, + CHARGING_SOURCE, + CHARGING_ENABLED, + FULL_BAT, +}; + +static int htc_rpc_set_delta(unsigned delta) +{ + struct set_batt_delta_req { + struct rpc_request_hdr hdr; + uint32_t data; + } req; + + req.data = cpu_to_be32(delta); + return msm_rpc_call(endpoint, HTC_PROCEDURE_SET_BATT_DELTA, + &req, sizeof(req), 5 * HZ); +} + + +static ssize_t htc_battery_set_delta(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int rc; + unsigned long delta = 0; + + delta = simple_strtoul(buf, NULL, 10); + + if (delta > 100) + return -EINVAL; + + mutex_lock(&htc_batt_info.rpc_lock); + rc = htc_rpc_set_delta(delta); + mutex_unlock(&htc_batt_info.rpc_lock); + if (rc < 0) + return rc; + return count; +} + +static struct device_attribute htc_set_delta_attrs[] = { + __ATTR(delta, S_IWUSR | S_IWGRP, NULL, htc_battery_set_delta), +}; + +static int htc_battery_create_attrs(struct device * dev) +{ + int i, j, rc; + + for (i = 0; i < ARRAY_SIZE(htc_battery_attrs); i++) { + rc = device_create_file(dev, &htc_battery_attrs[i]); + if (rc) + goto htc_attrs_failed; + } + + for (j = 0; j < ARRAY_SIZE(htc_set_delta_attrs); j++) { + rc = device_create_file(dev, &htc_set_delta_attrs[j]); + if (rc) + goto htc_delta_attrs_failed; + } + + goto succeed; + +htc_attrs_failed: + while (i--) + device_remove_file(dev, &htc_battery_attrs[i]); +htc_delta_attrs_failed: + while (j--) + device_remove_file(dev, &htc_set_delta_attrs[i]); +succeed: + return rc; +} + +static ssize_t htc_battery_show_property(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int i = 0; + const ptrdiff_t off = attr - htc_battery_attrs; + + /* rpc lock is used to prevent two threads from calling + * into the get info rpc at the same time + */ + + mutex_lock(&htc_batt_info.rpc_lock); + /* check cache time to decide if we need to update */ + if (htc_batt_info.update_time && + time_before(jiffies, htc_batt_info.update_time + + msecs_to_jiffies(cache_time))) + goto dont_need_update; + + if (htc_get_batt_info(&htc_batt_info.rep) < 0) { + printk(KERN_ERR "%s: rpc failed!!!\n", __FUNCTION__); + } else { + htc_batt_info.update_time = jiffies; + } +dont_need_update: + mutex_unlock(&htc_batt_info.rpc_lock); + + mutex_lock(&htc_batt_info.lock); + switch (off) { + case BATT_ID: + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + htc_batt_info.rep.batt_id); + break; + case BATT_VOL: + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + htc_batt_info.rep.batt_vol); + break; + case BATT_TEMP: + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + htc_batt_info.rep.batt_temp); + break; + case BATT_CURRENT: + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + htc_batt_info.rep.batt_current); + break; + case CHARGING_SOURCE: + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + htc_batt_info.rep.charging_source); + break; + case CHARGING_ENABLED: + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + htc_batt_info.rep.charging_enabled); + break; + case FULL_BAT: + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + htc_batt_info.rep.full_bat); + break; + default: + i = -EINVAL; + } + mutex_unlock(&htc_batt_info.lock); + + return i; +} + +static int htc_battery_probe(struct platform_device *pdev) +{ + int i, rc; + + /* init battery gpio */ + if ((rc = init_batt_gpio()) < 0) { + printk(KERN_ERR "%s: init battery gpio failed!\n", __FUNCTION__); + return rc; + } + + /* init structure data member */ + htc_batt_info.update_time = jiffies; + htc_batt_info.present = gpio_get_value(GPIO_BATTERY_DETECTION); + + /* init rpc */ + endpoint = msm_rpc_connect(APP_BATT_PROG, APP_BATT_VER, 0); + if (IS_ERR(endpoint)) { + printk(KERN_ERR "%s: init rpc failed! rc = %ld\n", + __FUNCTION__, PTR_ERR(endpoint)); + return rc; + } + + /* init power supplier framework */ + for (i = 0; i < ARRAY_SIZE(htc_power_supplies); i++) { + rc = power_supply_register(&pdev->dev, &htc_power_supplies[i]); + if (rc) + printk(KERN_ERR "Failed to register power supply (%d)\n", rc); + } + + /* create htc detail attributes */ + htc_battery_create_attrs(htc_power_supplies[CHARGER_BATTERY].dev); + + /* After battery driver gets initialized, send rpc request to inquiry + * the battery status in case of we lost some info + */ + htc_battery_initial = 1; + + mutex_lock(&htc_batt_info.rpc_lock); + if (htc_get_batt_info(&htc_batt_info.rep) < 0) + printk(KERN_ERR "%s: get info failed\n", __FUNCTION__); + + htc_cable_status_update(htc_batt_info.rep.charging_source); + battery_charging_ctrl(htc_batt_info.rep.charging_enabled ? + ENABLE_SLOW_CHG : DISABLE); + + if (htc_rpc_set_delta(1) < 0) + printk(KERN_ERR "%s: set delta failed\n", __FUNCTION__); + htc_batt_info.update_time = jiffies; + mutex_unlock(&htc_batt_info.rpc_lock); + + if (htc_batt_info.rep.charging_enabled == 0) + battery_charging_ctrl(DISABLE); + + return 0; +} + +static struct platform_driver htc_battery_driver = { + .probe = htc_battery_probe, + .driver = { + .name = APP_BATT_PDEV_NAME, + .owner = THIS_MODULE, + }, +}; + +/* batt_mtoa server definitions */ +#define BATT_MTOA_PROG 0x30100000 +#define BATT_MTOA_VERS 0 +#define RPC_BATT_MTOA_NULL 0 +#define RPC_BATT_MTOA_SET_CHARGING_PROC 1 +#define RPC_BATT_MTOA_CABLE_STATUS_UPDATE_PROC 2 +#define RPC_BATT_MTOA_LEVEL_UPDATE_PROC 3 + +struct rpc_batt_mtoa_set_charging_args { + int enable; +}; + +struct rpc_batt_mtoa_cable_status_update_args { + int status; +}; + +struct rpc_dem_battery_update_args { + uint32_t level; +}; + +static int handle_battery_call(struct msm_rpc_server *server, + struct rpc_request_hdr *req, unsigned len) +{ + switch (req->procedure) { + case RPC_BATT_MTOA_NULL: + return 0; + + case RPC_BATT_MTOA_SET_CHARGING_PROC: { + struct rpc_batt_mtoa_set_charging_args *args; + args = (struct rpc_batt_mtoa_set_charging_args *)(req + 1); + args->enable = be32_to_cpu(args->enable); + BATT("set_charging: enable=%d\n",args->enable); + htc_battery_set_charging(args->enable); + return 0; + } + case RPC_BATT_MTOA_CABLE_STATUS_UPDATE_PROC: { + struct rpc_batt_mtoa_cable_status_update_args *args; + args = (struct rpc_batt_mtoa_cable_status_update_args *)(req + 1); + args->status = be32_to_cpu(args->status); + BATT("cable_status_update: status=%d\n",args->status); + htc_cable_status_update(args->status); + return 0; + } + case RPC_BATT_MTOA_LEVEL_UPDATE_PROC: { + struct rpc_dem_battery_update_args *args; + args = (struct rpc_dem_battery_update_args *)(req + 1); + args->level = be32_to_cpu(args->level); + BATT("dem_battery_update: level=%d\n",args->level); + htc_battery_status_update(args->level); + return 0; + } + default: + printk(KERN_ERR "%s: program 0x%08x:%d: unknown procedure %d\n", + __FUNCTION__, req->prog, req->vers, req->procedure); + return -ENODEV; + } +} + +static struct msm_rpc_server battery_server = { + .prog = BATT_MTOA_PROG, + .vers = BATT_MTOA_VERS, + .rpc_call = handle_battery_call, +}; + +static int __init htc_battery_init(void) +{ + wake_lock_init(&vbus_wake_lock, WAKE_LOCK_SUSPEND, "vbus_present"); + mutex_init(&htc_batt_info.lock); + mutex_init(&htc_batt_info.rpc_lock); + msm_rpc_create_server(&battery_server); + platform_driver_register(&htc_battery_driver); + return 0; +} + +module_init(htc_battery_init); +MODULE_DESCRIPTION("HTC Battery Driver"); +MODULE_LICENSE("GPL"); + -- cgit v1.2.3 From 02f746be7fd6ee184bc9ec7374dfcd303c3675f4 Mon Sep 17 00:00:00 2001 From: Rebecca Schultz Date: Wed, 29 Oct 2008 16:57:59 -0700 Subject: [ARM] msm: trout: Add msm_fb support to trout architecture Signed-off-by: Rebecca Schultz --- arch/arm/mach-msm/board-trout-panel.c | 646 ++++++++++++++++++++++++++++++++++ 1 file changed, 646 insertions(+) create mode 100644 arch/arm/mach-msm/board-trout-panel.c (limited to 'arch') diff --git a/arch/arm/mach-msm/board-trout-panel.c b/arch/arm/mach-msm/board-trout-panel.c new file mode 100644 index 000000000000..e81374c30875 --- /dev/null +++ b/arch/arm/mach-msm/board-trout-panel.c @@ -0,0 +1,646 @@ +/* linux/arch/arm/mach-msm/board-trout-mddi.c +** Author: Brian Swetland +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#ifdef CONFIG_TROUT_PWRSINK +#include +#endif + +#include "board-trout.h" +#include "proc_comm.h" +#include "devices.h" + +#define TROUT_DEFAULT_BACKLIGHT_BRIGHTNESS 255 + +static struct clk *gp_clk; +static int trout_backlight_off; +static int trout_backlight_brightness = TROUT_DEFAULT_BACKLIGHT_BRIGHTNESS; +static int trout_new_backlight = 1; +static uint8_t trout_backlight_last_level = 33; +static DEFINE_MUTEX(trout_backlight_lock); + +static void trout_set_backlight_level(uint8_t level) +{ +#ifdef CONFIG_TROUT_PWRSINK + unsigned percent = ((int)level * 100) / 255; +#endif + + if (trout_new_backlight) { + unsigned long flags; + int i = 0; + level = (int)level * 34 / 256; + + if (trout_backlight_last_level == level) + return; + + if (level == 0) { + gpio_set_value(27, 0); + msleep(2); + } else { + local_irq_save(flags); + if (trout_backlight_last_level == 0) { + gpio_set_value(27, 1); + udelay(40); + trout_backlight_last_level = 33; + } + i = (trout_backlight_last_level - level + 33) % 33; + while (i-- > 0) { + gpio_set_value(27, 0); + udelay(1); + gpio_set_value(27, 1); + udelay(1); + } + local_irq_restore(flags); + } + trout_backlight_last_level = level; + } + else { + if(level) { + clk_enable(gp_clk); + writel((1U << 16) | (~level & 0xffff), + MSM_CLK_CTL_BASE + 0x58); + /* Going directly to a 100% duty cycle does not + * seem to work */ + if(level == 255) { + writel((~127 << 16) | 0xb20, + MSM_CLK_CTL_BASE + 0x5c); + udelay(1); + } + writel((~127 << 16) | 0xb58, MSM_CLK_CTL_BASE + 0x5c); + } + else { + writel(0x0, MSM_CLK_CTL_BASE + 0x5c); + clk_disable(gp_clk); + } + } +#ifdef CONFIG_TROUT_PWRSINK + trout_pwrsink_set(PWRSINK_BACKLIGHT, percent); +#endif +} + +#define MDDI_CLIENT_CORE_BASE 0x108000 +#define LCD_CONTROL_BLOCK_BASE 0x110000 +#define SPI_BLOCK_BASE 0x120000 +#define I2C_BLOCK_BASE 0x130000 +#define PWM_BLOCK_BASE 0x140000 +#define GPIO_BLOCK_BASE 0x150000 +#define SYSTEM_BLOCK1_BASE 0x160000 +#define SYSTEM_BLOCK2_BASE 0x170000 + + +#define DPSUS (MDDI_CLIENT_CORE_BASE|0x24) +#define SYSCLKENA (MDDI_CLIENT_CORE_BASE|0x2C) +#define PWM0OFF (PWM_BLOCK_BASE|0x1C) + +#define V_VDDE2E_VDD2_GPIO 0 +#define MDDI_RST_N 82 + +#define MDDICAP0 (MDDI_CLIENT_CORE_BASE|0x00) +#define MDDICAP1 (MDDI_CLIENT_CORE_BASE|0x04) +#define MDDICAP2 (MDDI_CLIENT_CORE_BASE|0x08) +#define MDDICAP3 (MDDI_CLIENT_CORE_BASE|0x0C) +#define MDCAPCHG (MDDI_CLIENT_CORE_BASE|0x10) +#define MDCRCERC (MDDI_CLIENT_CORE_BASE|0x14) +#define TTBUSSEL (MDDI_CLIENT_CORE_BASE|0x18) +#define DPSET0 (MDDI_CLIENT_CORE_BASE|0x1C) +#define DPSET1 (MDDI_CLIENT_CORE_BASE|0x20) +#define DPSUS (MDDI_CLIENT_CORE_BASE|0x24) +#define DPRUN (MDDI_CLIENT_CORE_BASE|0x28) +#define SYSCKENA (MDDI_CLIENT_CORE_BASE|0x2C) +#define TESTMODE (MDDI_CLIENT_CORE_BASE|0x30) +#define FIFOMONI (MDDI_CLIENT_CORE_BASE|0x34) +#define INTMONI (MDDI_CLIENT_CORE_BASE|0x38) +#define MDIOBIST (MDDI_CLIENT_CORE_BASE|0x3C) +#define MDIOPSET (MDDI_CLIENT_CORE_BASE|0x40) +#define BITMAP0 (MDDI_CLIENT_CORE_BASE|0x44) +#define BITMAP1 (MDDI_CLIENT_CORE_BASE|0x48) +#define BITMAP2 (MDDI_CLIENT_CORE_BASE|0x4C) +#define BITMAP3 (MDDI_CLIENT_CORE_BASE|0x50) +#define BITMAP4 (MDDI_CLIENT_CORE_BASE|0x54) + +#define SRST (LCD_CONTROL_BLOCK_BASE|0x00) +#define PORT_ENB (LCD_CONTROL_BLOCK_BASE|0x04) +#define START (LCD_CONTROL_BLOCK_BASE|0x08) +#define PORT (LCD_CONTROL_BLOCK_BASE|0x0C) +#define CMN (LCD_CONTROL_BLOCK_BASE|0x10) +#define GAMMA (LCD_CONTROL_BLOCK_BASE|0x14) +#define INTFLG (LCD_CONTROL_BLOCK_BASE|0x18) +#define INTMSK (LCD_CONTROL_BLOCK_BASE|0x1C) +#define MPLFBUF (LCD_CONTROL_BLOCK_BASE|0x20) +#define HDE_LEFT (LCD_CONTROL_BLOCK_BASE|0x24) +#define VDE_TOP (LCD_CONTROL_BLOCK_BASE|0x28) +#define PXL (LCD_CONTROL_BLOCK_BASE|0x30) +#define HCYCLE (LCD_CONTROL_BLOCK_BASE|0x34) +#define HSW (LCD_CONTROL_BLOCK_BASE|0x38) +#define HDE_START (LCD_CONTROL_BLOCK_BASE|0x3C) +#define HDE_SIZE (LCD_CONTROL_BLOCK_BASE|0x40) +#define VCYCLE (LCD_CONTROL_BLOCK_BASE|0x44) +#define VSW (LCD_CONTROL_BLOCK_BASE|0x48) +#define VDE_START (LCD_CONTROL_BLOCK_BASE|0x4C) +#define VDE_SIZE (LCD_CONTROL_BLOCK_BASE|0x50) +#define WAKEUP (LCD_CONTROL_BLOCK_BASE|0x54) +#define WSYN_DLY (LCD_CONTROL_BLOCK_BASE|0x58) +#define REGENB (LCD_CONTROL_BLOCK_BASE|0x5C) +#define VSYNIF (LCD_CONTROL_BLOCK_BASE|0x60) +#define WRSTB (LCD_CONTROL_BLOCK_BASE|0x64) +#define RDSTB (LCD_CONTROL_BLOCK_BASE|0x68) +#define ASY_DATA (LCD_CONTROL_BLOCK_BASE|0x6C) +#define ASY_DATB (LCD_CONTROL_BLOCK_BASE|0x70) +#define ASY_DATC (LCD_CONTROL_BLOCK_BASE|0x74) +#define ASY_DATD (LCD_CONTROL_BLOCK_BASE|0x78) +#define ASY_DATE (LCD_CONTROL_BLOCK_BASE|0x7C) +#define ASY_DATF (LCD_CONTROL_BLOCK_BASE|0x80) +#define ASY_DATG (LCD_CONTROL_BLOCK_BASE|0x84) +#define ASY_DATH (LCD_CONTROL_BLOCK_BASE|0x88) +#define ASY_CMDSET (LCD_CONTROL_BLOCK_BASE|0x8C) + +#define SSICTL (SPI_BLOCK_BASE|0x00) +#define SSITIME (SPI_BLOCK_BASE|0x04) +#define SSITX (SPI_BLOCK_BASE|0x08) +#define SSIRX (SPI_BLOCK_BASE|0x0C) +#define SSIINTC (SPI_BLOCK_BASE|0x10) +#define SSIINTS (SPI_BLOCK_BASE|0x14) +#define SSIDBG1 (SPI_BLOCK_BASE|0x18) +#define SSIDBG2 (SPI_BLOCK_BASE|0x1C) +#define SSIID (SPI_BLOCK_BASE|0x20) + +#define WKREQ (SYSTEM_BLOCK1_BASE|0x00) +#define CLKENB (SYSTEM_BLOCK1_BASE|0x04) +#define DRAMPWR (SYSTEM_BLOCK1_BASE|0x08) +#define INTMASK (SYSTEM_BLOCK1_BASE|0x0C) +#define GPIOSEL (SYSTEM_BLOCK2_BASE|0x00) + +#define GPIODATA (GPIO_BLOCK_BASE|0x00) +#define GPIODIR (GPIO_BLOCK_BASE|0x04) +#define GPIOIS (GPIO_BLOCK_BASE|0x08) +#define GPIOIBE (GPIO_BLOCK_BASE|0x0C) +#define GPIOIEV (GPIO_BLOCK_BASE|0x10) +#define GPIOIE (GPIO_BLOCK_BASE|0x14) +#define GPIORIS (GPIO_BLOCK_BASE|0x18) +#define GPIOMIS (GPIO_BLOCK_BASE|0x1C) +#define GPIOIC (GPIO_BLOCK_BASE|0x20) +#define GPIOOMS (GPIO_BLOCK_BASE|0x24) +#define GPIOPC (GPIO_BLOCK_BASE|0x28) +#define GPIOID (GPIO_BLOCK_BASE|0x30) + +#define SPI_WRITE(reg, val) \ + { SSITX, 0x00010000 | (((reg) & 0xff) << 8) | ((val) & 0xff) }, \ + { 0, 5 }, + +#define SPI_WRITE1(reg) \ + { SSITX, (reg) & 0xff }, \ + { 0, 5 }, + +struct mddi_table { + uint32_t reg; + uint32_t value; +}; +static struct mddi_table mddi_toshiba_init_table[] = { + { DPSET0, 0x09e90046 }, + { DPSET1, 0x00000118 }, + { DPSUS, 0x00000000 }, + { DPRUN, 0x00000001 }, + { 1, 14 }, /* msleep 14 */ + { SYSCKENA, 0x00000001 }, + //{ CLKENB, 0x000000EF }, + { CLKENB, 0x0000A1EF }, /* # SYS.CLKENB # Enable clocks for each module (without DCLK , i2cCLK) */ + //{ CLKENB, 0x000025CB }, /* Clock enable register */ + + { GPIODATA, 0x02000200 }, /* # GPI .GPIODATA # GPIO2(RESET_LCD_N) set to 0 , GPIO3(eDRAM_Power) set to 0 */ + { GPIODIR, 0x000030D }, /* 24D # GPI .GPIODIR # Select direction of GPIO port (0,2,3,6,9 output) */ + { GPIOSEL, 0/*0x00000173*/}, /* # SYS.GPIOSEL # GPIO port multiplexing control */ + { GPIOPC, 0x03C300C0 }, /* # GPI .GPIOPC # GPIO2,3 PD cut */ + { WKREQ, 0x00000000 }, /* # SYS.WKREQ # Wake-up request event is VSYNC alignment */ + + { GPIOIBE, 0x000003FF }, + { GPIOIS, 0x00000000 }, + { GPIOIC, 0x000003FF }, + { GPIOIE, 0x00000000 }, + + { GPIODATA, 0x00040004 }, /* # GPI .GPIODATA # eDRAM VD supply */ + { 1, 1 }, /* msleep 1 */ + { GPIODATA, 0x02040004 }, /* # GPI .GPIODATA # eDRAM VD supply */ + { DRAMPWR, 0x00000001 }, /* eDRAM power */ +}; + +static struct mddi_table mddi_toshiba_panel_init_table[] = { + { SRST, 0x00000003 }, /* FIFO/LCDC not reset */ + { PORT_ENB, 0x00000001 }, /* Enable sync. Port */ + { START, 0x00000000 }, /* To stop operation */ + //{ START, 0x00000001 }, /* To start operation */ + { PORT, 0x00000004 }, /* Polarity of VS/HS/DE. */ + { CMN, 0x00000000 }, + { GAMMA, 0x00000000 }, /* No Gamma correction */ + { INTFLG, 0x00000000 }, /* VSYNC interrupt flag clear/status */ + { INTMSK, 0x00000000 }, /* VSYNC interrupt mask is off. */ + { MPLFBUF, 0x00000000 }, /* Select frame buffer's base address. */ + { HDE_LEFT, 0x00000000 }, /* The value of HDE_LEFT. */ + { VDE_TOP, 0x00000000 }, /* The value of VDE_TPO. */ + { PXL, 0x00000001 }, /* 1. RGB666 */ + /* 2. Data is valid from 1st frame of beginning. */ + { HDE_START, 0x00000006 }, /* HDE_START= 14 PCLK */ + { HDE_SIZE, 0x0000009F }, /* HDE_SIZE=320 PCLK */ + { HSW, 0x00000004 }, /* HSW= 10 PCLK */ + { VSW, 0x00000001 }, /* VSW=2 HCYCLE */ + { VDE_START, 0x00000003 }, /* VDE_START=4 HCYCLE */ + { VDE_SIZE, 0x000001DF }, /* VDE_SIZE=480 HCYCLE */ + { WAKEUP, 0x000001e2 }, /* Wakeup position in VSYNC mode. */ + { WSYN_DLY, 0x00000000 }, /* Wakeup position in VSIN mode. */ + { REGENB, 0x00000001 }, /* Set 1 to enable to change the value of registers. */ + { CLKENB, 0x000025CB }, /* Clock enable register */ + + { SSICTL, 0x00000170 }, /* SSI control register */ + { SSITIME, 0x00000250 }, /* SSI timing control register */ + { SSICTL, 0x00000172 }, /* SSI control register */ +}; + + +static struct mddi_table mddi_sharp_init_table[] = { + { VCYCLE, 0x000001eb }, + { HCYCLE, 0x000000ae }, + { REGENB, 0x00000001 }, /* Set 1 to enable to change the value of registers. */ + { GPIODATA, 0x00040000 }, /* GPIO2 low */ + { GPIODIR, 0x00000004 }, /* GPIO2 out */ + { 1, 1 }, /* msleep 1 */ + { GPIODATA, 0x00040004 }, /* GPIO2 high */ + { 1, 10 }, /* msleep 10 */ + SPI_WRITE(0x5f, 0x01) + SPI_WRITE1(0x11) + { 1, 200 }, /* msleep 200 */ + SPI_WRITE1(0x29) + SPI_WRITE1(0xde) + { START, 0x00000001 }, /* To start operation */ +}; + +static struct mddi_table mddi_sharp_deinit_table[] = { + { 1, 200 }, /* msleep 200 */ + SPI_WRITE(0x10, 0x1) + { 1, 100 }, /* msleep 100 */ + { GPIODATA, 0x00040004 }, /* GPIO2 high */ + { GPIODIR, 0x00000004 }, /* GPIO2 out */ + { GPIODATA, 0x00040000 }, /* GPIO2 low */ + { 1, 10 }, /* msleep 10 */ +}; + +static struct mddi_table mddi_tpo_init_table[] = { + { VCYCLE, 0x000001e5 }, + { HCYCLE, 0x000000ac }, + { REGENB, 0x00000001 }, /* Set 1 to enable to change the value of registers. */ + { 0, 20 }, /* udelay 20 */ + { GPIODATA, 0x00000004 }, /* GPIO2 high */ + { GPIODIR, 0x00000004 }, /* GPIO2 out */ + { 0, 20 }, /* udelay 20 */ + + SPI_WRITE(0x08, 0x01) + { 0, 500 }, /* udelay 500 */ + SPI_WRITE(0x08, 0x00) + SPI_WRITE(0x02, 0x00) + SPI_WRITE(0x03, 0x04) + SPI_WRITE(0x04, 0x0e) + SPI_WRITE(0x09, 0x02) + SPI_WRITE(0x0b, 0x08) + SPI_WRITE(0x0c, 0x53) + SPI_WRITE(0x0d, 0x01) + SPI_WRITE(0x0e, 0xe0) + SPI_WRITE(0x0f, 0x01) + SPI_WRITE(0x10, 0x58) + SPI_WRITE(0x20, 0x1e) + SPI_WRITE(0x21, 0x0a) + SPI_WRITE(0x22, 0x0a) + SPI_WRITE(0x23, 0x1e) + SPI_WRITE(0x25, 0x32) + SPI_WRITE(0x26, 0x00) + SPI_WRITE(0x27, 0xac) + SPI_WRITE(0x29, 0x06) + SPI_WRITE(0x2a, 0xa4) + SPI_WRITE(0x2b, 0x45) + SPI_WRITE(0x2c, 0x45) + SPI_WRITE(0x2d, 0x15) + SPI_WRITE(0x2e, 0x5a) + SPI_WRITE(0x2f, 0xff) + SPI_WRITE(0x30, 0x6b) + SPI_WRITE(0x31, 0x0d) + SPI_WRITE(0x32, 0x48) + SPI_WRITE(0x33, 0x82) + SPI_WRITE(0x34, 0xbd) + SPI_WRITE(0x35, 0xe7) + SPI_WRITE(0x36, 0x18) + SPI_WRITE(0x37, 0x94) + SPI_WRITE(0x38, 0x01) + SPI_WRITE(0x39, 0x5d) + SPI_WRITE(0x3a, 0xae) + SPI_WRITE(0x3b, 0xff) + SPI_WRITE(0x07, 0x09) + { 0, 10 }, /* udelay 10 */ + { START, 0x00000001 }, /* To start operation */ +}; + +static struct mddi_table mddi_tpo_deinit_table[] = { + SPI_WRITE(0x07, 0x19) + { START, 0x00000000 }, /* To stop operation */ + { GPIODATA, 0x00040004 }, /* GPIO2 high */ + { GPIODIR, 0x00000004 }, /* GPIO2 out */ + { GPIODATA, 0x00040000 }, /* GPIO2 low */ + { 0, 5 }, /* usleep 5 */ +}; + + +#define GPIOSEL_VWAKEINT (1U << 0) +#define INTMASK_VWAKEOUT (1U << 0) + +static void trout_process_mddi_table(struct msm_mddi_client_data *cdata, + struct mddi_table *table, size_t count) +{ + int i; + for(i = 0; i < count; i++) { + uint32_t reg = table[i].reg; + uint32_t value = table[i].value; + + if (reg == 0) + udelay(value); + else if (reg == 1) + msleep(value); + else + cdata->remote_write(cdata, value, reg); + } +} + +static struct vreg *vreg_mddi_1v5; +static struct vreg *vreg_lcm_2v85; + +static void trout_mddi_power_client(struct msm_mddi_client_data *cdata, + int on) +{ + unsigned id, on_off; + if(on) { + on_off = 0; + id = PM_VREG_PDOWN_MDDI_ID; + msm_proc_comm(PCOM_VREG_PULLDOWN, &on_off, &id); + vreg_enable(vreg_mddi_1v5); + mdelay(5); // delay time >5ms and <10ms + gpio_set_value(V_VDDE2E_VDD2_GPIO, 1); + gpio_set_value(TROUT_GPIO_MDDI_32K_EN, 1); + msleep(3); + id = PM_VREG_PDOWN_AUX_ID; + msm_proc_comm(PCOM_VREG_PULLDOWN, &on_off, &id); + vreg_enable(vreg_lcm_2v85); + msleep(3); + gpio_set_value(MDDI_RST_N, 1); + msleep(10); + } else { + gpio_set_value(TROUT_GPIO_MDDI_32K_EN, 0); + gpio_set_value(MDDI_RST_N, 0); + msleep(10); + vreg_disable(vreg_lcm_2v85); + on_off = 1; + id = PM_VREG_PDOWN_AUX_ID; + msm_proc_comm(PCOM_VREG_PULLDOWN, &on_off, &id); + msleep(5); + gpio_set_value(V_VDDE2E_VDD2_GPIO, 0); + msleep(200); + vreg_disable(vreg_mddi_1v5); + id = PM_VREG_PDOWN_MDDI_ID; + msm_proc_comm(PCOM_VREG_PULLDOWN, &on_off, &id); + } +} + +static int trout_mddi_toshiba_client_init(struct msm_mddi_client_data *cdata) +{ + int panel_id; + + cdata->auto_hibernate(cdata, 0); + trout_process_mddi_table(cdata, mddi_toshiba_init_table, + ARRAY_SIZE(mddi_toshiba_init_table)); + cdata->auto_hibernate(cdata, 1); + panel_id = (cdata->remote_read(cdata, GPIODATA) >> 4) & 3; + if (panel_id > 1) { + printk("unknown panel id at mddi_enable\n"); + return -1; + } + return 0; +} + +static int trout_mddi_toshiba_client_uninit(struct msm_mddi_client_data *cdata) +{ + return 0; +} + +static int trout_mddi_panel_unblank(struct msm_panel_data *panel_data) +{ + struct msm_mddi_panel_info *panel = container_of(panel_data, + struct msm_mddi_panel_info, panel_data); + struct msm_mddi_client_data *mddi_client = panel->client_data; + + int panel_id, ret = 0; + + trout_set_backlight_level(0); + mddi_client->auto_hibernate(mddi_client, 0); + trout_process_mddi_table(mddi_client, mddi_toshiba_panel_init_table, + ARRAY_SIZE(mddi_toshiba_panel_init_table)); + panel_id = (mddi_client->remote_read(mddi_client, GPIODATA) >> 4) & 3; + switch(panel_id) { + case 0: + printk("init sharp panel\n"); + trout_process_mddi_table(mddi_client, + mddi_sharp_init_table, + ARRAY_SIZE(mddi_sharp_init_table)); + break; + case 1: + printk("init tpo panel\n"); + trout_process_mddi_table(mddi_client, + mddi_tpo_init_table, + ARRAY_SIZE(mddi_tpo_init_table)); + break; + default: + printk("unknown panel_id: %d\n", panel_id); + ret = -1; + }; + mutex_lock(&trout_backlight_lock); + trout_set_backlight_level(trout_backlight_brightness); + trout_backlight_off = 0; + mutex_unlock(&trout_backlight_lock); + mddi_client->auto_hibernate(mddi_client, 1); + // reenable vsync + mddi_client->remote_write(mddi_client, GPIOSEL_VWAKEINT, + GPIOSEL); + mddi_client->remote_write(mddi_client, INTMASK_VWAKEOUT, + INTMASK); + return ret; + +} + +static int trout_mddi_panel_blank(struct msm_panel_data *panel_data) +{ + struct msm_mddi_panel_info *panel = container_of(panel_data, + struct msm_mddi_panel_info, panel_data); + struct msm_mddi_client_data *mddi_client = panel->client_data; + int panel_id, ret = 0; + + panel_id = (mddi_client->remote_read(mddi_client, GPIODATA) >> 4) & 3; + mddi_client->auto_hibernate(mddi_client, 0); + switch(panel_id) { + case 0: + printk("deinit sharp panel\n"); + trout_process_mddi_table(mddi_client, + mddi_sharp_deinit_table, + ARRAY_SIZE(mddi_sharp_deinit_table)); + break; + case 1: + printk("deinit tpo panel\n"); + trout_process_mddi_table(mddi_client, + mddi_tpo_deinit_table, + ARRAY_SIZE(mddi_tpo_deinit_table)); + break; + default: + printk("unknown panel_id: %d\n", panel_id); + ret = -1; + }; + mddi_client->auto_hibernate(mddi_client,1); + mutex_lock(&trout_backlight_lock); + trout_set_backlight_level(0); + trout_backlight_off = 1; + mutex_unlock(&trout_backlight_lock); + mddi_client->remote_write(mddi_client, 0, SYSCLKENA); + mddi_client->remote_write(mddi_client, 1, DPSUS); + + return ret; +} + +static void trout_brightness_set(struct led_classdev *led_cdev, enum led_brightness value) +{ + mutex_lock(&trout_backlight_lock); + trout_backlight_brightness = value; + if(!trout_backlight_off) + trout_set_backlight_level(trout_backlight_brightness); + mutex_unlock(&trout_backlight_lock); +} + +static struct led_classdev trout_backlight_led = { + .name = "lcd-backlight", + .brightness = TROUT_DEFAULT_BACKLIGHT_BRIGHTNESS, + .brightness_set = trout_brightness_set, +}; + +static int trout_backlight_probe(struct platform_device *pdev) +{ + led_classdev_register(&pdev->dev, &trout_backlight_led); + return 0; +} + +static int trout_backlight_remove(struct platform_device *pdev) +{ + led_classdev_unregister(&trout_backlight_led); + return 0; +} + +static struct platform_driver trout_backlight_driver = { + .probe = trout_backlight_probe, + .remove = trout_backlight_remove, + .driver = { + .name = "trout-backlight", + .owner = THIS_MODULE, + }, +}; + +static struct resource resources_msm_fb[] = { + { + .start = MSM_FB_BASE, + .end = MSM_FB_BASE + MSM_FB_SIZE, + .flags = IORESOURCE_MEM, + }, +}; + +struct msm_mddi_toshiba_client_data toshiba_client_data = { + .init = trout_mddi_toshiba_client_init, + .uninit = trout_mddi_toshiba_client_uninit, + .blank = trout_mddi_panel_blank, + .unblank = trout_mddi_panel_unblank, + .fb_data = { + .xres = 320, + .yres = 480, + .output_format = 0, + }, +}; + +struct msm_mddi_platform_data mddi_pdata = { + .clk_rate = 122880000, + .power_client = trout_mddi_power_client, + .fb_resource = resources_msm_fb, + .num_clients = 1, + .client_platform_data = { + { + .product_id = (0xd263 << 16 | 0), + .name = "mddi_c_d263_0000", + .id = 0, + .client_data = &toshiba_client_data, + .clk_rate = 0, + }, + }, +}; + +static struct platform_device trout_backlight = { + .name = "trout-backlight", +}; + +int __init trout_init_panel(void) +{ + int rc; + + if (!machine_is_trout()) + return 0; + vreg_mddi_1v5 = vreg_get(0, "gp2"); + if (IS_ERR(vreg_mddi_1v5)) + return PTR_ERR(vreg_mddi_1v5); + vreg_lcm_2v85 = vreg_get(0, "gp4"); + if (IS_ERR(vreg_lcm_2v85)) + return PTR_ERR(vreg_lcm_2v85); + + trout_new_backlight = system_rev >= 5; + if (trout_new_backlight) { + uint32_t config = PCOM_GPIO_CFG(27, 0, GPIO_OUTPUT, + GPIO_NO_PULL, GPIO_8MA); + msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &config, 0); + } + else { + uint32_t config = PCOM_GPIO_CFG(27, 1, GPIO_OUTPUT, + GPIO_NO_PULL, GPIO_8MA); + msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &config, 0); + + gp_clk = clk_get(NULL, "gp_clk"); + if (IS_ERR(gp_clk)) { + printk(KERN_ERR "trout_init_panel: could not get gp" + "clock\n"); + gp_clk = NULL; + } + rc = clk_set_rate(gp_clk, 19200000); + if (rc) + printk(KERN_ERR "trout_init_panel: set clock rate " + "failed\n"); + } + + rc = platform_device_register(&msm_device_mdp); + if (rc) + return rc; + msm_device_mddi0.dev.platform_data = &mddi_pdata; + rc = platform_device_register(&msm_device_mddi0); + if (rc) + return rc; + platform_device_register(&trout_backlight); + return platform_driver_register(&trout_backlight_driver); +} + +device_initcall(trout_init_panel); -- cgit v1.2.3 From 559a70ad5ffb908de6727e72f36887a3e0842a91 Mon Sep 17 00:00:00 2001 From: "Mike A. Chan" Date: Fri, 7 Nov 2008 12:39:29 -0800 Subject: [ARM] msm: clock: Adding ondemand cpufreq scaling. Signed-off-by: Mike Chan --- arch/arm/mach-msm/Kconfig | 38 ++++++++++++++++++++---- arch/arm/mach-msm/Makefile | 2 +- arch/arm/mach-msm/acpuclock.c | 26 +++++++++++++---- arch/arm/mach-msm/acpuclock.h | 2 ++ arch/arm/mach-msm/cpufreq.c | 68 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 124 insertions(+), 12 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index dc37099e83ae..a74e78fff801 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -227,12 +227,26 @@ config MSM_RPCSERVERS help none -menuconfig MSM_CPU_FREQ_SCREEN - depends on HAS_EARLYSUSPEND - default n - bool "Enable simple cpu frequency scaling" - help - Simple cpufreq scaling based on screen ON/OFF. +config MSM_CPU_FREQ + bool + default y if MSM_CPU_FREQ_ONDEMAND || MSM_CPU_FREQ_SCREEN + +choice + prompt "Cpufreq mode" + default MSM_CPU_FREQ_ONDEMAND + default MSM_CPU_FREQ_SCREEN + + config MSM_CPU_FREQ_ONDEMAND + depends on CPU_FREQ_DEFAULT_GOV_ONDEMAND + bool "Enable ONDEMAND cpufreq govoner for" + + config MSM_CPU_FREQ_SCREEN + depends on HAS_EARLYSUSPEND + bool "Enable simple cpu frequency scaling" + help + Simple cpufreq scaling based on screen ON/OFF. + +endchoice if MSM_CPU_FREQ_SCREEN @@ -246,4 +260,16 @@ config MSM_CPU_FREQ_SCREEN_ON endif # MSM_CPU_FREQ_SCREEN +if MSM_CPU_FREQ_ONDEMAND + +config MSM_CPU_FREQ_ONDEMAND_MAX + int "Max" + default 384000 + +config MSM_CPU_FREQ_ONDEMAND_MIN + int "Min" + default 245760 + +endif # MSM_CPU_FREQ_ONDEMAND + endif diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 81d3bdb7e08b..297c1658c37d 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -15,7 +15,7 @@ obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_servers.o obj-$(CONFIG_MSM_RPCSERVERS) += rpc_server_dog_keepalive.o obj-$(CONFIG_MSM_RPCSERVERS) += rpc_server_time_remote.o obj-$(CONFIG_PM) += pm.o -obj-$(CONFIG_MSM_CPU_FREQ_SCREEN) += cpufreq.o +obj-$(CONFIG_MSM_CPU_FREQ) += cpufreq.o obj-$(CONFIG_MACH_TROUT) += board-dream.o diff --git a/arch/arm/mach-msm/acpuclock.c b/arch/arm/mach-msm/acpuclock.c index 4b08125bfcef..c228d365998f 100644 --- a/arch/arm/mach-msm/acpuclock.c +++ b/arch/arm/mach-msm/acpuclock.c @@ -50,7 +50,6 @@ struct clock_state static struct clock_state drv_state = { 0 }; static void __init acpuclk_init(void); -static unsigned long acpuclk_get_rate(void); /* MSM7201A Levels 3-6 all correspond to 1.2V, level 7 corresponds to 1.325V. */ enum { @@ -135,13 +134,13 @@ static int pc_pll_request(unsigned id, unsigned on) unsigned long acpuclk_power_collapse(void) { int ret = acpuclk_get_rate(); acpuclk_set_rate(drv_state.power_collapse_khz, 1); - return ret; + return ret * 1000; } unsigned long acpuclk_wait_for_irq(void) { int ret = acpuclk_get_rate(); acpuclk_set_rate(drv_state.wait_for_irq_khz, 1); - return ret; + return ret * 1000; } static int acpuclk_set_vdd_level(int vdd) @@ -242,6 +241,9 @@ int acpuclk_set_rate(unsigned long rate, int for_power_collapse) uint32_t reg_clkctl; struct clkctl_acpu_speed *cur_s, *tgt_s, *strt_s; int rc = 0; +#ifdef CONFIG_MSM_CPU_FREQ_ONDEMAND + struct cpufreq_freqs freqs; +#endif strt_s = cur_s = drv_state.current_speed; @@ -268,6 +270,12 @@ int acpuclk_set_rate(unsigned long rate, int for_power_collapse) if (!for_power_collapse) { mutex_lock(&drv_state.lock); +#ifdef CONFIG_MSM_CPU_FREQ_ONDEMAND + freqs.old = cur_s->a11clk_khz; + freqs.new = tgt_s->a11clk_khz; + freqs.cpu = smp_processor_id(); + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); +#endif if (strt_s->pll != tgt_s->pll && tgt_s->pll != ACPU_PLL_TCXO) { if ((rc = pc_pll_request(tgt_s->pll, 1)) < 0) { printk(KERN_ERR "PLL enable failed (%d)\n", rc); @@ -344,6 +352,9 @@ int acpuclk_set_rate(unsigned long rate, int for_power_collapse) printk(KERN_ERR "acpuclock: Unable to drop ACPU vdd\n"); } +#ifdef CONFIG_MSM_CPU_FREQ_ONDEMAND + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); +#endif #if PERF_SWITCH_DEBUG printk(KERN_DEBUG "%s: ACPU speed change complete\n", __FUNCTION__); #endif @@ -397,16 +408,21 @@ static void __init acpuclk_init(void) current_vdd, speed->vdd); } -static unsigned long acpuclk_get_rate(void) +unsigned long acpuclk_get_rate(void) { WARN_ONCE(drv_state.current_speed == NULL, "acpuclk_get_rate: not initialized\n"); if (drv_state.current_speed) - return drv_state.current_speed->a11clk_khz * 1000; + return drv_state.current_speed->a11clk_khz; else return 0; } +uint32_t acpuclk_get_switch_time(void) +{ + return drv_state.acpu_switch_time_us; +} + /*---------------------------------------------------------------------------- * Clock driver initialization *---------------------------------------------------------------------------*/ diff --git a/arch/arm/mach-msm/acpuclock.h b/arch/arm/mach-msm/acpuclock.h index 8b213634576f..0ce5e07e10b3 100644 --- a/arch/arm/mach-msm/acpuclock.h +++ b/arch/arm/mach-msm/acpuclock.h @@ -54,6 +54,8 @@ struct clkctl_acpu_speed int acpuclk_set_rate(unsigned long rate, int for_power_collapse); +unsigned long acpuclk_get_rate(void); +uint32_t acpuclk_get_switch_time(void); unsigned long acpuclk_wait_for_irq(void); unsigned long acpuclk_power_collapse(void); diff --git a/arch/arm/mach-msm/cpufreq.c b/arch/arm/mach-msm/cpufreq.c index efa46a0c9fa5..821d2be89fd3 100644 --- a/arch/arm/mach-msm/cpufreq.c +++ b/arch/arm/mach-msm/cpufreq.c @@ -21,6 +21,11 @@ #include #include "acpuclock.h" +#ifdef CONFIG_MSM_CPU_FREQ_ONDEMAND +#include +#endif + +#ifdef CONFIG_MSM_CPU_FREQ_SCREEN static void msm_early_suspend(struct early_suspend *handler) { acpuclk_set_rate(CONFIG_MSM_CPU_FREQ_SCREEN_OFF * 1000, 0); } @@ -41,3 +46,66 @@ static int __init clock_late_init(void) } late_initcall(clock_late_init); +#elif defined(CONFIG_MSM_CPU_FREQ_ONDEMAND) + +static int msm_cpufreq_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + unsigned int freq; + switch(relation) { + /* Lowest value at or above target frequency. */ + case CPUFREQ_RELATION_L: + /* Highest value at or below target frequency. */ + case CPUFREQ_RELATION_H: + if (target_freq < CONFIG_MSM_CPU_FREQ_ONDEMAND_MAX) + freq = CONFIG_MSM_CPU_FREQ_ONDEMAND_MIN; + else + freq = CONFIG_MSM_CPU_FREQ_ONDEMAND_MAX; + break; + default: + return -EINVAL; + } +#ifdef CONFIG_CPU_FREQ_DEBUG + printk("msm_cpufreq_target %d r %d (%d-%d) selected %d\n", target_freq, + relation, policy->min, policy->max, freq); +#endif + acpuclk_set_rate(freq * 1000, 0); + return 0; +} + +static int msm_cpufreq_verify(struct cpufreq_policy *policy) +{ + cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, + policy->cpuinfo.max_freq); +return 0; +} + +static int __init msm_cpufreq_init(struct cpufreq_policy *policy) +{ + policy->cur = acpuclk_get_rate(); + policy->min = CONFIG_MSM_CPU_FREQ_ONDEMAND_MIN; + policy->max = CONFIG_MSM_CPU_FREQ_ONDEMAND_MAX; + policy->cpuinfo.min_freq = CONFIG_MSM_CPU_FREQ_ONDEMAND_MIN; + policy->cpuinfo.max_freq = CONFIG_MSM_CPU_FREQ_ONDEMAND_MAX; + policy->cpuinfo.transition_latency = + acpuclk_get_switch_time() * NSEC_PER_USEC; + return 0; +} + +static struct cpufreq_driver msm_cpufreq_driver = { + /* lps calculstaions are handled here. */ + .flags = CPUFREQ_STICKY | CPUFREQ_CONST_LOOPS, + .init = msm_cpufreq_init, + .verify = msm_cpufreq_verify, + .target = msm_cpufreq_target, + .name = "msm", +}; + +static int __init msm_cpufreq_register(void) +{ + return cpufreq_register_driver(&msm_cpufreq_driver); +} + +device_initcall(msm_cpufreq_register); +#endif -- cgit v1.2.3 From 416133271086008ea0b285ae982f4e29c6070f35 Mon Sep 17 00:00:00 2001 From: San Mehat Date: Mon, 10 Nov 2008 16:30:27 -0800 Subject: [ARM] msm: common: Add SDC device runtime registration Signed-off-by: San Mehat --- arch/arm/mach-msm/devices.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/devices.c b/arch/arm/mach-msm/devices.c index 31b6b30e98bf..3004c2b0a0d1 100644 --- a/arch/arm/mach-msm/devices.c +++ b/arch/arm/mach-msm/devices.c @@ -24,6 +24,8 @@ #include #include +#include + static struct resource resources_uart1[] = { { .start = INT_UART1, @@ -266,3 +268,22 @@ struct platform_device msm_device_sdc4 = { .coherent_dma_mask = 0xffffffff, }, }; + +static struct platform_device *msm_sdcc_devices[] __initdata = { + &msm_device_sdc1, + &msm_device_sdc2, + &msm_device_sdc3, + &msm_device_sdc4, +}; + +int __init msm_add_sdcc(unsigned int controller, struct mmc_platform_data *plat) +{ + struct platform_device *pdev; + + if (controller < 1 || controller > 4) + return -EINVAL; + + pdev = msm_sdcc_devices[controller-1]; + pdev->dev.platform_data = plat; + return platform_device_register(pdev); +} -- cgit v1.2.3 From 8cb414734c338180fdd0c4f7f8356c5c099af452 Mon Sep 17 00:00:00 2001 From: San Mehat Date: Mon, 10 Nov 2008 17:57:27 -0800 Subject: [ARM] trout_mmc: Initial MMC support for Trout on 2.6.27 Signed-off-by: San Mehat trout: mmc: Re-enable WIFI SDIO code Signed-off-by: San Mehat trout: mmc: Re-enable wifi debugfs code Signed-off-by: San Mehat trout: mmc: Add maxblksize specifier to embedded data for wifi Signed-off-by: San Mehat --- arch/arm/mach-msm/Makefile | 1 + arch/arm/mach-msm/board-trout-mmc.c | 426 ++++++++++++++++++++++++++++++++++++ arch/arm/mach-msm/board-trout.c | 8 + 3 files changed, 435 insertions(+) create mode 100644 arch/arm/mach-msm/board-trout-mmc.c (limited to 'arch') diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 297c1658c37d..fb2f3fca95b2 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -21,5 +21,6 @@ obj-$(CONFIG_MSM_CPU_FREQ) += cpufreq.o obj-$(CONFIG_MACH_TROUT) += board-dream.o obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o board-halibut-keypad.o obj-$(CONFIG_MACH_TROUT) += htc_akm_cal.o htc_wifi_nvs.o htc_acoustic.o +obj-$(CONFIG_MACH_TROUT) += board-trout-mmc.o obj-$(CONFIG_TROUT_H2W) += board-trout-h2w.o obj-$(CONFIG_TROUT_BATTCHG) += htc_battery.o diff --git a/arch/arm/mach-msm/board-trout-mmc.c b/arch/arm/mach-msm/board-trout-mmc.c new file mode 100644 index 000000000000..c217cd65d7e6 --- /dev/null +++ b/arch/arm/mach-msm/board-trout-mmc.c @@ -0,0 +1,426 @@ +/* linux/arch/arm/mach-msm/board-trout-mmc.c +** Author: Brian Swetland +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include + +#include "devices.h" + +#include "board-trout.h" + +#include "proc_comm.h" + +#define DEBUG_SDSLOT_VDD 1 + +extern int msm_add_sdcc(unsigned int controller, struct mmc_platform_data *plat); + +/* ---- COMMON ---- */ +static void config_gpio_table(uint32_t *table, int len) +{ + int n; + unsigned id; + for(n = 0; n < len; n++) { + id = table[n]; + msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0); + } +} + +/* ---- SDCARD ---- */ + +static uint32_t sdcard_on_gpio_table[] = { + PCOM_GPIO_CFG(62, 2, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA), /* CLK */ + PCOM_GPIO_CFG(63, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* CMD */ + PCOM_GPIO_CFG(64, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* DAT3 */ + PCOM_GPIO_CFG(65, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* DAT2 */ + PCOM_GPIO_CFG(66, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT1 */ + PCOM_GPIO_CFG(67, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT0 */ +}; + +static uint32_t sdcard_off_gpio_table[] = { + PCOM_GPIO_CFG(62, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* CLK */ + PCOM_GPIO_CFG(63, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* CMD */ + PCOM_GPIO_CFG(64, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT3 */ + PCOM_GPIO_CFG(65, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT2 */ + PCOM_GPIO_CFG(66, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT1 */ + PCOM_GPIO_CFG(67, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT0 */ +}; + +static uint opt_disable_sdcard; + +static int __init trout_disablesdcard_setup(char *str) +{ + int cal = simple_strtol(str, NULL, 0); + + opt_disable_sdcard = cal; + return 1; +} + +__setup("board_trout.disable_sdcard=", trout_disablesdcard_setup); + +static struct vreg *vreg_sdslot; /* SD slot power */ + +struct mmc_vdd_xlat { + int mask; + int level; +}; + +static struct mmc_vdd_xlat mmc_vdd_table[] = { + { MMC_VDD_165_195, 1800 }, + { MMC_VDD_20_21, 2050 }, + { MMC_VDD_21_22, 2150 }, + { MMC_VDD_22_23, 2250 }, + { MMC_VDD_23_24, 2350 }, + { MMC_VDD_24_25, 2450 }, + { MMC_VDD_25_26, 2550 }, + { MMC_VDD_26_27, 2650 }, + { MMC_VDD_27_28, 2750 }, + { MMC_VDD_28_29, 2850 }, + { MMC_VDD_29_30, 2950 }, +}; + +static unsigned int sdslot_vdd = 0xffffffff; +static unsigned int sdslot_vreg_enabled; + +static uint32_t trout_sdslot_switchvdd(struct device *dev, unsigned int vdd) +{ + int i, rc; + + BUG_ON(!vreg_sdslot); + + if (vdd == sdslot_vdd) + return 0; + + sdslot_vdd = vdd; + + if (vdd == 0) { +#if DEBUG_SDSLOT_VDD + printk("%s: Disabling SD slot power\n", __func__); +#endif + config_gpio_table(sdcard_off_gpio_table, + ARRAY_SIZE(sdcard_off_gpio_table)); + vreg_disable(vreg_sdslot); + sdslot_vreg_enabled = 0; + return 0; + } + + if (!sdslot_vreg_enabled) { + rc = vreg_enable(vreg_sdslot); + if (rc) { + printk(KERN_ERR "%s: Error enabling vreg (%d)\n", + __func__, rc); + } + config_gpio_table(sdcard_on_gpio_table, + ARRAY_SIZE(sdcard_on_gpio_table)); + sdslot_vreg_enabled = 1; + } + + for (i = 0; i < ARRAY_SIZE(mmc_vdd_table); i++) { + if (mmc_vdd_table[i].mask == (1 << vdd)) { +#if DEBUG_SDSLOT_VDD + printk("%s: Setting level to %u\n", + __func__, mmc_vdd_table[i].level); +#endif + rc = vreg_set_level(vreg_sdslot, + mmc_vdd_table[i].level); + if (rc) { + printk(KERN_ERR + "%s: Error setting vreg level (%d)\n", + __func__, rc); + } + return 0; + } + } + + printk(KERN_ERR "%s: Invalid VDD %d specified\n", __func__, vdd); + return 0; +} + +static unsigned int trout_sdslot_status(struct device *dev) +{ + unsigned int status; + + status = (unsigned int) gpio_get_value(TROUT_GPIO_SDMC_CD_N); + return (!status); +} + +#define TROUT_MMC_VDD MMC_VDD_165_195 | MMC_VDD_20_21 | MMC_VDD_21_22 \ + | MMC_VDD_22_23 | MMC_VDD_23_24 | MMC_VDD_24_25 \ + | MMC_VDD_25_26 | MMC_VDD_26_27 | MMC_VDD_27_28 \ + | MMC_VDD_28_29 | MMC_VDD_29_30 + +static struct mmc_platform_data trout_sdslot_data = { + .ocr_mask = TROUT_MMC_VDD, + .status_irq = TROUT_GPIO_TO_INT(TROUT_GPIO_SDMC_CD_N), + .status = trout_sdslot_status, + .translate_vdd = trout_sdslot_switchvdd, +}; + +/* ---- WIFI ---- */ + +static uint32_t wifi_on_gpio_table[] = { + PCOM_GPIO_CFG(51, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT3 */ + PCOM_GPIO_CFG(52, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT2 */ + PCOM_GPIO_CFG(53, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT1 */ + PCOM_GPIO_CFG(54, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT0 */ + PCOM_GPIO_CFG(55, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* CMD */ + PCOM_GPIO_CFG(56, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA), /* CLK */ + PCOM_GPIO_CFG(29, 0, GPIO_INPUT, GPIO_NO_PULL, GPIO_4MA), /* WLAN IRQ */ +}; + +static uint32_t wifi_off_gpio_table[] = { + PCOM_GPIO_CFG(51, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT3 */ + PCOM_GPIO_CFG(52, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT2 */ + PCOM_GPIO_CFG(53, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT1 */ + PCOM_GPIO_CFG(54, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT0 */ + PCOM_GPIO_CFG(55, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* CMD */ + PCOM_GPIO_CFG(56, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* CLK */ + PCOM_GPIO_CFG(29, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* WLAN IRQ */ +}; + +static struct vreg *vreg_wifi_osc; /* WIFI 32khz oscilator */ +static int trout_wifi_cd = 0; /* WIFI virtual 'card detect' status */ + +static struct sdio_embedded_func wifi_func = { + .f_class = SDIO_CLASS_WLAN, + .f_maxblksize = 512, +}; + +static struct embedded_sdio_data trout_wifi_emb_data = { + .cis = { + .vendor = 0x104c, + .device = 0x9066, + .blksize = 512, + /*.max_dtr = 24000000, Max of chip - no worky on Trout */ + .max_dtr = 20000000, + }, + .cccr = { + .multi_block = 0, + .low_speed = 0, + .wide_bus = 1, + .high_power = 0, + .high_speed = 0, + }, + .funcs = &wifi_func, + .num_funcs = 1, +}; + +static void (*wifi_status_cb)(int card_present, void *dev_id); +static void *wifi_status_cb_devid; + +static int trout_wifi_status_register(void (*callback)(int card_present, void *dev_id), void *dev_id) +{ + if (wifi_status_cb) + return -EAGAIN; + wifi_status_cb = callback; + wifi_status_cb_devid = dev_id; + return 0; +} + +static unsigned int trout_wifi_status(struct device *dev) +{ + return trout_wifi_cd; +} + +static struct mmc_platform_data trout_wifi_data = { + .ocr_mask = MMC_VDD_28_29, + .status = trout_wifi_status, + .register_status_notify = trout_wifi_status_register, + .embedded_sdio = &trout_wifi_emb_data, +}; + +void trout_wifi_set_carddetect(int val) +{ + printk("%s: %d\n", __func__, val); + trout_wifi_cd = val; + if (wifi_status_cb) { + wifi_status_cb(val, wifi_status_cb_devid); + } else + printk(KERN_WARNING "%s: Nobody to notify\n", __func__); +} +EXPORT_SYMBOL(trout_wifi_set_carddetect); + +static int trout_wifi_power_state; + +int trout_wifi_power(int on) +{ + int rc; + + printk("%s: %d\n", __func__, on); + + if (on) { + config_gpio_table(wifi_on_gpio_table, + ARRAY_SIZE(wifi_on_gpio_table)); + rc = vreg_enable(vreg_wifi_osc); + if (rc) + return rc; + } else { + config_gpio_table(wifi_off_gpio_table, + ARRAY_SIZE(wifi_off_gpio_table)); + } + gpio_set_value( TROUT_GPIO_MAC_32K_EN, on); + mdelay(100); + gpio_set_value( TROUT_GPIO_WIFI_EN, on); + mdelay(100); + if (!on) { + vreg_disable(vreg_wifi_osc); + } + trout_wifi_power_state = on; + return 0; +} +EXPORT_SYMBOL(trout_wifi_power); + +static int trout_wifi_reset_state; +void trout_wifi_reset(int on) +{ + printk("%s: %d\n", __func__, on); + gpio_set_value( TROUT_GPIO_WIFI_PA_RESETX, !on ); + trout_wifi_reset_state = on; + mdelay(50); +} +EXPORT_SYMBOL(trout_wifi_reset); + +int __init trout_init_mmc(unsigned int sys_rev) +{ + wifi_status_cb = NULL; + + sdslot_vreg_enabled = 0; + + vreg_sdslot = vreg_get(0, "gp6"); + if (IS_ERR(vreg_sdslot)) + return PTR_ERR(vreg_sdslot); + vreg_wifi_osc = vreg_get(0, "mmc"); + if (IS_ERR(vreg_wifi_osc)) + return PTR_ERR(vreg_wifi_osc); + + set_irq_wake(TROUT_GPIO_TO_INT(TROUT_GPIO_SDMC_CD_N), 1); + + msm_add_sdcc(1, &trout_wifi_data); + + if (!opt_disable_sdcard) + msm_add_sdcc(2, &trout_sdslot_data); + else + printk(KERN_INFO "trout: SD-Card interface disabled\n"); + return 0; +} + +#if defined(CONFIG_DEBUG_FS) +static int troutmmc_dbg_wifi_reset_set(void *data, u64 val) +{ + trout_wifi_reset((int) val); + return 0; +} + +static int troutmmc_dbg_wifi_reset_get(void *data, u64 *val) +{ + *val = trout_wifi_reset_state; + return 0; +} + +static int troutmmc_dbg_wifi_cd_set(void *data, u64 val) +{ + trout_wifi_set_carddetect((int) val); + return 0; +} + +static int troutmmc_dbg_wifi_cd_get(void *data, u64 *val) +{ + *val = trout_wifi_cd; + return 0; +} + +static int troutmmc_dbg_wifi_pwr_set(void *data, u64 val) +{ + trout_wifi_power((int) val); + return 0; +} + +static int troutmmc_dbg_wifi_pwr_get(void *data, u64 *val) +{ + + *val = trout_wifi_power_state; + return 0; +} + +static int troutmmc_dbg_sd_pwr_set(void *data, u64 val) +{ + trout_sdslot_switchvdd(NULL, (unsigned int) val); + return 0; +} + +static int troutmmc_dbg_sd_pwr_get(void *data, u64 *val) +{ + *val = sdslot_vdd; + return 0; +} + +static int troutmmc_dbg_sd_cd_set(void *data, u64 val) +{ + return -ENOSYS; +} + +static int troutmmc_dbg_sd_cd_get(void *data, u64 *val) +{ + *val = trout_sdslot_status(NULL); + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(troutmmc_dbg_wifi_reset_fops, + troutmmc_dbg_wifi_reset_get, + troutmmc_dbg_wifi_reset_set, "%llu\n"); + +DEFINE_SIMPLE_ATTRIBUTE(troutmmc_dbg_wifi_cd_fops, + troutmmc_dbg_wifi_cd_get, + troutmmc_dbg_wifi_cd_set, "%llu\n"); + +DEFINE_SIMPLE_ATTRIBUTE(troutmmc_dbg_wifi_pwr_fops, + troutmmc_dbg_wifi_pwr_get, + troutmmc_dbg_wifi_pwr_set, "%llu\n"); + +DEFINE_SIMPLE_ATTRIBUTE(troutmmc_dbg_sd_pwr_fops, + troutmmc_dbg_sd_pwr_get, + troutmmc_dbg_sd_pwr_set, "%llu\n"); + +DEFINE_SIMPLE_ATTRIBUTE(troutmmc_dbg_sd_cd_fops, + troutmmc_dbg_sd_cd_get, + troutmmc_dbg_sd_cd_set, "%llu\n"); + +static int __init troutmmc_dbg_init(void) +{ + struct dentry *dent; + + dent = debugfs_create_dir("troutmmc_dbg", 0); + if (IS_ERR(dent)) + return PTR_ERR(dent); + + debugfs_create_file("wifi_reset", 0644, dent, NULL, + &troutmmc_dbg_wifi_reset_fops); + debugfs_create_file("wifi_cd", 0644, dent, NULL, + &troutmmc_dbg_wifi_cd_fops); + debugfs_create_file("wifi_pwr", 0644, dent, NULL, + &troutmmc_dbg_wifi_pwr_fops); + + debugfs_create_file("sd_pwr", 0644, dent, NULL, + &troutmmc_dbg_sd_pwr_fops); + debugfs_create_file("sd_cd", 0644, dent, NULL, + &troutmmc_dbg_sd_cd_fops); + + return 0; +} + +device_initcall(troutmmc_dbg_init); + +#endif diff --git a/arch/arm/mach-msm/board-trout.c b/arch/arm/mach-msm/board-trout.c index 7da4611dc5ba..9e95194828a1 100644 --- a/arch/arm/mach-msm/board-trout.c +++ b/arch/arm/mach-msm/board-trout.c @@ -69,6 +69,8 @@ void msm_init_irq(void); void msm_init_gpio(void); +extern int trout_init_mmc(unsigned int); + struct trout_axis_info { struct gpio_event_axis_info info; uint16_t in_state; @@ -589,6 +591,8 @@ static struct msm_acpu_clock_platform_data trout_clock_data = { static void __init trout_init(void) { + int rc; + printk("trout_init() revision=%d\n", system_rev); /* @@ -636,6 +640,10 @@ static void __init trout_init(void) msm_device_hsusb.dev.platform_data = &msm_hsusb_pdata; + rc = trout_init_mmc(system_rev); + if (rc) + printk(KERN_CRIT "%s: MMC init failure (%d)\n", __func__, rc); + platform_add_devices(devices, ARRAY_SIZE(devices)); i2c_register_board_info(0, i2c_devices, ARRAY_SIZE(i2c_devices)); -- cgit v1.2.3 From 647a204cbee0c4cda559646161e00d9b0b099cbe Mon Sep 17 00:00:00 2001 From: Rebecca Schultz Date: Wed, 1 Oct 2008 10:43:10 -0700 Subject: [ARM] msm: trout: Adds trout Power Sink Driver Signed-off-by: Rebecca Schultz --- arch/arm/mach-msm/Kconfig | 5 + arch/arm/mach-msm/Makefile | 1 + arch/arm/mach-msm/board-trout-gpio.c | 15 +++ arch/arm/mach-msm/board-trout-mmc.c | 3 + arch/arm/mach-msm/board-trout.c | 68 ++++++++++++ arch/arm/mach-msm/htc_pwrsink.c | 147 +++++++++++++++++++++++++ arch/arm/mach-msm/include/mach/trout_pwrsink.h | 58 ++++++++++ 7 files changed, 297 insertions(+) create mode 100644 arch/arm/mach-msm/htc_pwrsink.c create mode 100644 arch/arm/mach-msm/include/mach/trout_pwrsink.h (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index a74e78fff801..e9abede32c7d 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -76,6 +76,11 @@ config TROUT_BATTCHG default y bool "Trout battery / charger driver" +config TROUT_PWRSINK + depends on MSM_SMD + default y + bool "Trout Power Sink Driver" + choice prompt "Default Timer" default MSM7X00A_USE_GP_TIMER diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index fb2f3fca95b2..46cac8833724 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -24,3 +24,4 @@ obj-$(CONFIG_MACH_TROUT) += htc_akm_cal.o htc_wifi_nvs.o htc_acoustic.o obj-$(CONFIG_MACH_TROUT) += board-trout-mmc.o obj-$(CONFIG_TROUT_H2W) += board-trout-h2w.o obj-$(CONFIG_TROUT_BATTCHG) += htc_battery.o +obj-$(CONFIG_TROUT_PWRSINK) += htc_pwrsink.o diff --git a/arch/arm/mach-msm/board-trout-gpio.c b/arch/arm/mach-msm/board-trout-gpio.c index 0a06de6717ca..7d71958e9698 100644 --- a/arch/arm/mach-msm/board-trout-gpio.c +++ b/arch/arm/mach-msm/board-trout-gpio.c @@ -23,6 +23,8 @@ #include #include +#include + #include "board-trout.h" #include "gpio_chip.h" @@ -52,6 +54,18 @@ static int trout_gpio_read(struct gpio_chip *chip, unsigned n) return !!(readb(TROUT_CPLD_BASE + reg) & b); } +static void update_pwrsink(unsigned gpio, unsigned on) +{ + switch(gpio) { + case TROUT_GPIO_UI_LED_EN: + trout_pwrsink_set(PWRSINK_LED_BUTTON, on ? 100 : 0); + break; + case TROUT_GPIO_QTKEY_LED_EN: + trout_pwrsink_set(PWRSINK_LED_KEYBOARD, on ? 100 : 0); + break; + } +} + int trout_gpio_write(struct gpio_chip *chip, unsigned n, unsigned on) { uint8_t b = 1U << (n & 7); @@ -65,6 +79,7 @@ int trout_gpio_write(struct gpio_chip *chip, unsigned n, unsigned on) } local_irq_save(flags); + update_pwrsink(n, on); if(on) reg_val = trout_cpld_shadow[reg >> 1] |= b; else diff --git a/arch/arm/mach-msm/board-trout-mmc.c b/arch/arm/mach-msm/board-trout-mmc.c index c217cd65d7e6..a82eb3a42296 100644 --- a/arch/arm/mach-msm/board-trout-mmc.c +++ b/arch/arm/mach-msm/board-trout-mmc.c @@ -15,6 +15,7 @@ #include #include +#include #include @@ -267,9 +268,11 @@ int trout_wifi_power(int on) rc = vreg_enable(vreg_wifi_osc); if (rc) return rc; + trout_pwrsink_set(PWRSINK_WIFI, 70); } else { config_gpio_table(wifi_off_gpio_table, ARRAY_SIZE(wifi_off_gpio_table)); + trout_pwrsink_set(PWRSINK_WIFI, 0); } gpio_set_value( TROUT_GPIO_MAC_32K_EN, on); mdelay(100); diff --git a/arch/arm/mach-msm/board-trout.c b/arch/arm/mach-msm/board-trout.c index 9e95194828a1..185b56b4bf84 100644 --- a/arch/arm/mach-msm/board-trout.c +++ b/arch/arm/mach-msm/board-trout.c @@ -63,6 +63,8 @@ #include #endif +#include + #include "proc_comm.h" #include "devices.h" @@ -472,6 +474,67 @@ static struct platform_device trout_ram_console_device = { .resource = trout_ram_console_resource, }; +static struct pwr_sink trout_pwrsink_table[] = { + { + .id = PWRSINK_AUDIO, + .ua_max = 90000, + }, + { + .id = PWRSINK_BACKLIGHT, + .ua_max = 128000, + }, + { + .id = PWRSINK_LED_BUTTON, + .ua_max = 17000, + }, + { + .id = PWRSINK_LED_KEYBOARD, + .ua_max = 22000, + }, + { + .id = PWRSINK_GP_CLK, + .ua_max = 30000, + }, + { + .id = PWRSINK_BLUETOOTH, + .ua_max = 15000, + }, + { + .id = PWRSINK_CAMERA, + .ua_max = 0, + }, + { + .id = PWRSINK_SDCARD, + .ua_max = 0, + }, + { + .id = PWRSINK_VIDEO, + .ua_max = 0, + }, + { + .id = PWRSINK_WIFI, + .ua_max = 200000, + }, + { + .id = PWRSINK_SYSTEM_LOAD, + .ua_max = 63000, + .percent_util = 100, + }, +}; + +static struct pwr_sink_platform_data trout_pwrsink_data = { + .num_sinks = ARRAY_SIZE(trout_pwrsink_table), + .sinks = trout_pwrsink_table, +}; + +static struct platform_device trout_pwr_sink = { + .name = "trout_pwrsink", + .id = -1, + .dev = { + .platform_data = &trout_pwrsink_data, + }, +}; + static struct platform_device *devices[] __initdata = { &msm_device_smd, &msm_device_nand, @@ -494,6 +557,9 @@ static struct platform_device *devices[] __initdata = { &android_pmem_gpu1_device, &android_pmem_camera_device, &trout_ram_console_device, +#if defined(CONFIG_TROUT_PWRSINK) + &trout_pwr_sink, +#endif }; extern struct sys_timer msm_timer; @@ -522,9 +588,11 @@ static void bluetooth_set_power(int on) gpio_set_value(TROUT_GPIO_BT_32K_EN, 1); udelay(10); gpio_configure(101, GPIOF_DRIVE_OUTPUT | GPIOF_OUTPUT_HIGH); + trout_pwrsink_set(PWRSINK_BLUETOOTH, 100); } else { gpio_configure(101, GPIOF_DRIVE_OUTPUT | GPIOF_OUTPUT_LOW); gpio_set_value(TROUT_GPIO_BT_32K_EN, 0); + trout_pwrsink_set(PWRSINK_BLUETOOTH, 0); } } diff --git a/arch/arm/mach-msm/htc_pwrsink.c b/arch/arm/mach-msm/htc_pwrsink.c new file mode 100644 index 000000000000..6ce6fb473773 --- /dev/null +++ b/arch/arm/mach-msm/htc_pwrsink.c @@ -0,0 +1,147 @@ +/* arch/arm/mach-msm/htc_pwrsink.c + * + * Copyright (C) 2008 HTC Corporation + * Copyright (C) 2008 Google, Inc. + * Author: San Mehat + * Kant Kang + * Eiven Peng + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 "smd_private.h" + +static int initialized = 0; +static struct pwr_sink *sink_array[PWRSINK_LAST + 1]; +static DEFINE_SPINLOCK(sink_lock); +static unsigned long total_sink; +static uint32_t *smem_total_sink; + +int trout_pwrsink_set(pwrsink_id_type id, unsigned percent_utilized) +{ + unsigned long flags; + + if (!smem_total_sink) + smem_total_sink = smem_alloc(SMEM_ID_VENDOR0, sizeof(uint32_t)); + + if (!initialized) + return -EAGAIN; + + if (id < 0 || id > PWRSINK_LAST) + return -EINVAL; + + spin_lock_irqsave(&sink_lock, flags); + + if (!sink_array[id]) { + spin_unlock_irqrestore(&sink_lock, flags); + return -ENOENT; + } + + if (sink_array[id]->percent_util == percent_utilized) { + spin_unlock_irqrestore(&sink_lock, flags); + return 0; + } + + total_sink -= (sink_array[id]->ua_max * + sink_array[id]->percent_util / 100); + sink_array[id]->percent_util = percent_utilized; + total_sink += (sink_array[id]->ua_max * + sink_array[id]->percent_util / 100); + + if (smem_total_sink) + *smem_total_sink = total_sink / 1000; + + pr_debug("trout_pwrsink: ID %d, Util %d%%, Total %lu uA %s\n", + id, percent_utilized, total_sink, + smem_total_sink ? "SET" : ""); + + spin_unlock_irqrestore(&sink_lock, flags); + + return 0; +} +EXPORT_SYMBOL(trout_pwrsink_set); + +void trout_pwrsink_suspend_early(struct early_suspend *h) +{ + trout_pwrsink_set(PWRSINK_SYSTEM_LOAD, 70); +} + +int trout_pwrsink_suspend_late(struct platform_device *pdev, pm_message_t state) +{ + trout_pwrsink_set(PWRSINK_SYSTEM_LOAD, 13); + return 0; +} + +int trout_pwrsink_resume_early(struct platform_device *pdev) +{ + trout_pwrsink_set(PWRSINK_SYSTEM_LOAD, 70); + return 0; +} + +void trout_pwrsink_resume_late(struct early_suspend *h) +{ + trout_pwrsink_set(PWRSINK_SYSTEM_LOAD, 100); +} + +struct early_suspend trout_pwrsink_early_suspend = { + .level = EARLY_SUSPEND_LEVEL_DISABLE_FB + 1, + .suspend = trout_pwrsink_suspend_early, + .resume = trout_pwrsink_resume_late, +}; + +static int __init trout_pwrsink_probe(struct platform_device *pdev) +{ + struct pwr_sink_platform_data *pdata = pdev->dev.platform_data; + int i; + + if (!pdata) + return -EINVAL; + + total_sink = 0; + for (i = 0; i < pdata->num_sinks; i++) { + sink_array[pdata->sinks[i].id] = &pdata->sinks[i]; + total_sink += (pdata->sinks[i].ua_max * pdata->sinks[i].percent_util / 100); + } + + initialized = 1; + + register_early_suspend(&trout_pwrsink_early_suspend); + + return 0; +} + +static struct platform_driver trout_pwrsink_driver = { + .probe = trout_pwrsink_probe, + .suspend_late = trout_pwrsink_suspend_late, + .resume_early = trout_pwrsink_resume_early, + .driver = { + .name = "trout_pwrsink", + .owner = THIS_MODULE, + }, +}; + +static int __init trout_pwrsink_init(void) +{ + initialized = 0; + memset(sink_array, 0, sizeof(sink_array)); + return platform_driver_register(&trout_pwrsink_driver); +} + +module_init(trout_pwrsink_init); + diff --git a/arch/arm/mach-msm/include/mach/trout_pwrsink.h b/arch/arm/mach-msm/include/mach/trout_pwrsink.h new file mode 100644 index 000000000000..265b329ac0cf --- /dev/null +++ b/arch/arm/mach-msm/include/mach/trout_pwrsink.h @@ -0,0 +1,58 @@ +/* include/asm/mach-msm/trout_pwrsink.h + * + * Copyright (C) 2007 Google, Inc. + * Copyright (C) 2008 HTC Corporation. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ +#ifndef _ARCH_ARM_MACH_MSM_TROUT_PWRSINK_H_ +#define _ARCH_ARM_MACH_MSM_TROUT_PWRSINK_H_ + +typedef enum { + PWRSINK_SYSTEM_LOAD = 0, + PWRSINK_AUDIO, + PWRSINK_BACKLIGHT, + PWRSINK_LED_BUTTON, + PWRSINK_LED_KEYBOARD, + PWRSINK_GP_CLK, + PWRSINK_BLUETOOTH, + PWRSINK_CAMERA, + PWRSINK_SDCARD, + PWRSINK_VIDEO, + PWRSINK_WIFI, + + PWRSINK_LAST = PWRSINK_WIFI, + PWRSINK_INVALID +} pwrsink_id_type; + +struct pwr_sink { + pwrsink_id_type id; + unsigned ua_max; + unsigned percent_util; +}; + +struct pwr_sink_platform_data { + unsigned num_sinks; + struct pwr_sink *sinks; +}; + +#ifndef CONFIG_TROUT_PWRSINK +static inline int trout_pwrsink_set(pwrsink_id_type id, unsigned percent) +{ +printk("%s:STUB!\n", __func__); + return 0; +} +#else +extern int trout_pwrsink_set(pwrsink_id_type id, unsigned percent); +#endif + +#endif + -- cgit v1.2.3 From 09f5cd96c22f8b0113942d4d6713140f181b43b4 Mon Sep 17 00:00:00 2001 From: Nick Pelly Date: Mon, 17 Nov 2008 19:16:13 -0800 Subject: [ARM] msm: trout: bluetooth: Use rfkill API to turn bluetooth chipset on/off. --- arch/arm/mach-msm/Makefile | 1 + arch/arm/mach-msm/board-trout-rfkill.c | 93 ++++++++++++++++++++++++++++++++++ arch/arm/mach-msm/board-trout.c | 37 +++----------- 3 files changed, 100 insertions(+), 31 deletions(-) create mode 100644 arch/arm/mach-msm/board-trout-rfkill.c (limited to 'arch') diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 46cac8833724..d8f1a307b0ae 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -8,6 +8,7 @@ obj-y += gpio.o generic_gpio.o obj-y += nand_partitions.o obj-$(CONFIG_MSM_FIQ_SUPPORT) += fiq_glue.o +obj-$(CONFIG_MACH_TROUT) += board-trout-rfkill.o obj-$(CONFIG_MSM_SMD) += smd.o smd_tty.o smd_qmi.o obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter.o obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_device.o diff --git a/arch/arm/mach-msm/board-trout-rfkill.c b/arch/arm/mach-msm/board-trout-rfkill.c new file mode 100644 index 000000000000..5212431dda82 --- /dev/null +++ b/arch/arm/mach-msm/board-trout-rfkill.c @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2008 Google, Inc. + * Author: Nick Pelly + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +/* Control bluetooth power for trout platform */ + +#include +#include +#include +#include +#include +#include + +#include "board-trout.h" + +void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state); + +static struct rfkill *bt_rfk; +static const char bt_name[] = "brf6300"; + +static int bluetooth_set_power(void *data, enum rfkill_state state) +{ + switch (state) { + case RFKILL_STATE_UNBLOCKED: + gpio_set_value(TROUT_GPIO_BT_32K_EN, 1); + udelay(10); + gpio_configure(101, GPIOF_DRIVE_OUTPUT | GPIOF_OUTPUT_HIGH); + break; + case RFKILL_STATE_SOFT_BLOCKED: + gpio_configure(101, GPIOF_DRIVE_OUTPUT | GPIOF_OUTPUT_LOW); + gpio_set_value(TROUT_GPIO_BT_32K_EN, 0); + break; + default: + printk(KERN_ERR "bad bluetooth rfkill state %d\n", state); + } + return 0; +} + +static int __init trout_rfkill_probe(struct platform_device *pdev) +{ + int rc = 0; + + /* default to bluetooth off */ + rfkill_switch_all(RFKILL_TYPE_BLUETOOTH, RFKILL_STATE_SOFT_BLOCKED); + bluetooth_set_power(NULL, RFKILL_STATE_SOFT_BLOCKED); + + bt_rfk = rfkill_allocate(&pdev->dev, RFKILL_TYPE_BLUETOOTH); + if (!bt_rfk) + return -ENOMEM; + + bt_rfk->name = bt_name; + bt_rfk->state = RFKILL_STATE_SOFT_BLOCKED; + /* userspace cannot take exclusive control */ + bt_rfk->user_claim_unsupported = 1; + bt_rfk->user_claim = 0; + bt_rfk->data = NULL; // user data + bt_rfk->toggle_radio = bluetooth_set_power; + + rc = rfkill_register(bt_rfk); + + if (rc) + rfkill_free(bt_rfk); + return rc; +} + +static struct platform_driver trout_rfkill_driver = { + .probe = trout_rfkill_probe, + .driver = { + .name = "trout_rfkill", + .owner = THIS_MODULE, + }, +}; + +static int __init trout_rfkill_init(void) +{ + return platform_driver_register(&trout_rfkill_driver); +} + +module_init(trout_rfkill_init); +MODULE_DESCRIPTION("trout rfkill"); +MODULE_AUTHOR("Nick Pelly "); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-msm/board-trout.c b/arch/arm/mach-msm/board-trout.c index 185b56b4bf84..996046b7d516 100644 --- a/arch/arm/mach-msm/board-trout.c +++ b/arch/arm/mach-msm/board-trout.c @@ -535,6 +535,11 @@ static struct platform_device trout_pwr_sink = { }, }; +static struct platform_device trout_rfkill = { + .name = "trout_rfkill", + .id = -1, +}; + static struct platform_device *devices[] __initdata = { &msm_device_smd, &msm_device_nand, @@ -557,6 +562,7 @@ static struct platform_device *devices[] __initdata = { &android_pmem_gpu1_device, &android_pmem_camera_device, &trout_ram_console_device, + &trout_rfkill, #if defined(CONFIG_TROUT_PWRSINK) &trout_pwr_sink, #endif @@ -580,34 +586,6 @@ module_param_named(charger_en, cpld_charger_en, uint, 0); module_param_named(usb_h2w_sw, cpld_usb_h2w_sw, uint, 0); module_param_named(disable_uart3, opt_disable_uart3, uint, 0); -static int trout_bluetooth_power_on; - -static void bluetooth_set_power(int on) -{ - if (on) { - gpio_set_value(TROUT_GPIO_BT_32K_EN, 1); - udelay(10); - gpio_configure(101, GPIOF_DRIVE_OUTPUT | GPIOF_OUTPUT_HIGH); - trout_pwrsink_set(PWRSINK_BLUETOOTH, 100); - } else { - gpio_configure(101, GPIOF_DRIVE_OUTPUT | GPIOF_OUTPUT_LOW); - gpio_set_value(TROUT_GPIO_BT_32K_EN, 0); - trout_pwrsink_set(PWRSINK_BLUETOOTH, 0); - } -} - -static int bluetooth_set_power_on(const char *val, struct kernel_param *kp) -{ - int ret; - ret = param_set_bool(val, kp); - if (!ret) - bluetooth_set_power(trout_bluetooth_power_on); - return ret; -} - -module_param_call(bluetooth_power_on, bluetooth_set_power_on, param_get_bool, - &trout_bluetooth_power_on, S_IWUSR | S_IRUGO); - static int __init trout_serialno_setup(char *str) { #ifdef CONFIG_USB_FUNCTION @@ -694,9 +672,6 @@ static void __init trout_init(void) gpio_set_value(TROUT_GPIO_H2W_SEL1, 1); #endif - /* Init bluetooth clock and shutdown pin */ - bluetooth_set_power(trout_bluetooth_power_on); - /* put the AF VCM in powerdown mode to avoid noise */ gpio_set_value(TROUT_GPIO_VCM_PWDN, 1); mdelay(100); -- cgit v1.2.3 From f8735d07086148cb610fabccfcbfe8a362f7133c Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Mon, 17 Nov 2008 20:08:23 -0800 Subject: [ARM] msm: trout: Temporarily Disable DMA for SDC1 --- arch/arm/mach-msm/devices.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/devices.c b/arch/arm/mach-msm/devices.c index 3004c2b0a0d1..b39eab0f5ad6 100644 --- a/arch/arm/mach-msm/devices.c +++ b/arch/arm/mach-msm/devices.c @@ -168,11 +168,13 @@ static struct resource resources_sdc1[] = { .end = INT_SDC1_1, .flags = IORESOURCE_IRQ, }, +#if 0 { .start = 8, .end = 8, .flags = IORESOURCE_DMA, }, +#endif }; static struct resource resources_sdc2[] = { -- cgit v1.2.3 From 6e3a1026a98b6a7bcc5c324fd76bebb05e85b1f2 Mon Sep 17 00:00:00 2001 From: Arve Hjønnevåg Date: Tue, 18 Nov 2008 14:58:08 -0800 Subject: [ARM] msm: Add MSM_DEBUG_UART option. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Arve Hjønnevåg --- arch/arm/mach-msm/board-halibut.c | 4 ++++ arch/arm/mach-msm/include/mach/uncompress.h | 1 - 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/board-halibut.c b/arch/arm/mach-msm/board-halibut.c index 8664478dd38f..33e70f07b69a 100644 --- a/arch/arm/mach-msm/board-halibut.c +++ b/arch/arm/mach-msm/board-halibut.c @@ -113,6 +113,10 @@ static void __init halibut_map_io(void) } MACHINE_START(HALIBUT, "Halibut Board (QCT SURF7200A)") +#ifdef CONFIG_MSM_DEBUG_UART + .phys_io = MSM_DEBUG_UART_PHYS, + .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc, +#endif .boot_params = 0x10000100, .fixup = halibut_fixup, .map_io = halibut_map_io, diff --git a/arch/arm/mach-msm/include/mach/uncompress.h b/arch/arm/mach-msm/include/mach/uncompress.h index d94292c29d8e..6d1a2e82fc3f 100644 --- a/arch/arm/mach-msm/include/mach/uncompress.h +++ b/arch/arm/mach-msm/include/mach/uncompress.h @@ -15,7 +15,6 @@ #ifndef __ASM_ARCH_MSM_UNCOMPRESS_H -#include "hardware.h" #include "linux/io.h" #include "mach/msm_iomap.h" -- cgit v1.2.3 From 02e621138aa558d929b9b70818a7642a0b7b4680 Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Tue, 18 Nov 2008 20:48:17 -0500 Subject: trout: Support for msm_serial_hs driver. Signed-off-by: Mike Lockwood --- arch/arm/mach-msm/board-trout.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/board-trout.c b/arch/arm/mach-msm/board-trout.c index 996046b7d516..f252203813bb 100644 --- a/arch/arm/mach-msm/board-trout.c +++ b/arch/arm/mach-msm/board-trout.c @@ -548,6 +548,10 @@ static struct platform_device *devices[] __initdata = { #if !defined(CONFIG_MSM_SERIAL_DEBUGGER) && !defined(CONFIG_TROUT_H2W) &msm_device_uart3, #endif +#ifdef CONFIG_SERIAL_MSM_HS + &msm_device_uart_dm1, + &msm_device_uart_dm2, +#endif #ifdef CONFIG_USB_FUNCTION &msm_device_hsusb, &usb_mass_storage_device, @@ -603,10 +607,17 @@ static void trout_reset(void) static uint32_t gpio_table[] = { /* BLUETOOTH */ +#ifdef CONFIG_SERIAL_MSM_HS + PCOM_GPIO_CFG(43, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* RTS */ + PCOM_GPIO_CFG(44, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* CTS */ + PCOM_GPIO_CFG(45, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* RX */ + PCOM_GPIO_CFG(46, 3, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* TX */ +#else PCOM_GPIO_CFG(43, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* RTS */ PCOM_GPIO_CFG(44, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* CTS */ PCOM_GPIO_CFG(45, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* RX */ PCOM_GPIO_CFG(46, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* TX */ +#endif }; static void config_gpio_table(uint32_t *table, int len) -- cgit v1.2.3 From 236344455008f7384b1d9f0b66ff2cf3eb028dab Mon Sep 17 00:00:00 2001 From: Arve Hjønnevåg Date: Fri, 21 Nov 2008 21:40:42 -0800 Subject: [ARM] msm: trout: Add reset key combo. Reset on SEND-MENU-END if the trackball is not pressed. --- arch/arm/mach-msm/board-trout.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/board-trout.c b/arch/arm/mach-msm/board-trout.c index f252203813bb..90762c66650b 100644 --- a/arch/arm/mach-msm/board-trout.c +++ b/arch/arm/mach-msm/board-trout.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include <../../../drivers/staging/android/timed_gpio.h> @@ -184,6 +185,26 @@ static struct platform_device trout_nav_device = { }, }; +static int trout_reset_keys_up[] = { + BTN_MOUSE, + 0 +}; + +static struct keyreset_platform_data trout_reset_keys_pdata = { + .keys_up = trout_reset_keys_up, + .keys_down = { + KEY_SEND, + KEY_MENU, + KEY_END, + 0 + }, +}; + +struct platform_device trout_reset_keys_device = { + .name = KEYRESET_NAME, + .dev.platform_data = &trout_reset_keys_pdata, +}; + static int trout_ts_power(int on) { int tp_ls_gpio = system_rev < 5 ? TROUT_4_TP_LS_EN : TROUT_5_TP_LS_EN; @@ -557,6 +578,7 @@ static struct platform_device *devices[] __initdata = { &usb_mass_storage_device, #endif &trout_nav_device, + &trout_reset_keys_device, &android_leds, &sd_door_switch, &android_timed_gpios, -- cgit v1.2.3 From 2ae998b1ee4809d4e58140ffcb2a214ec3baf882 Mon Sep 17 00:00:00 2001 From: Arve Hjønnevåg Date: Tue, 2 Dec 2008 19:39:51 -0800 Subject: [ARM] msm: Setup default cpld values before writing them. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes a bug where low level serial debug on uart3 did not work between trout_init_gpio and trout_init. Signed-off-by: Arve Hjønnevåg --- arch/arm/mach-msm/board-trout-gpio.c | 33 ++++++++++++++++++++++++++++----- arch/arm/mach-msm/board-trout.c | 20 -------------------- 2 files changed, 28 insertions(+), 25 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/board-trout-gpio.c b/arch/arm/mach-msm/board-trout-gpio.c index 7d71958e9698..07d371b45ec8 100644 --- a/arch/arm/mach-msm/board-trout-gpio.c +++ b/arch/arm/mach-msm/board-trout-gpio.c @@ -28,8 +28,20 @@ #include "board-trout.h" #include "gpio_chip.h" +#undef MODULE_PARAM_PREFIX +#define MODULE_PARAM_PREFIX "board_trout." + +static uint cpld_usb_h2w_sw; +module_param_named(usb_h2w_sw, cpld_usb_h2w_sw, uint, 0); + static uint8_t trout_cpld_shadow[4] = { +#if defined(CONFIG_MSM_DEBUG_UART1) + /* H2W pins <-> UART1 */ [0] = 0x40, // for serial debug, low current +#else + /* H2W pins <-> UART3, Bluetooth <-> UART1 */ + [0] = 0x80, // for serial debug, low current +#endif [1] = 0x04, // I2C_PULL [3] = 0x04, // mmdi 32k en }; @@ -66,10 +78,20 @@ static void update_pwrsink(unsigned gpio, unsigned on) } } -int trout_gpio_write(struct gpio_chip *chip, unsigned n, unsigned on) +static uint8_t trout_gpio_write_shadow(unsigned n, unsigned on) { uint8_t b = 1U << (n & 7); int reg = (n & 0x78) >> 2; // assumes base is 128 + + if(on) + return trout_cpld_shadow[reg >> 1] |= b; + else + return trout_cpld_shadow[reg >> 1] &= ~b; +} + +static int trout_gpio_write(struct gpio_chip *chip, unsigned n, unsigned on) +{ + int reg = (n & 0x78) >> 2; // assumes base is 128 unsigned long flags; uint8_t reg_val; @@ -80,10 +102,7 @@ int trout_gpio_write(struct gpio_chip *chip, unsigned n, unsigned on) local_irq_save(flags); update_pwrsink(n, on); - if(on) - reg_val = trout_cpld_shadow[reg >> 1] |= b; - else - reg_val = trout_cpld_shadow[reg >> 1] &= ~b; + reg_val = trout_gpio_write_shadow(n, on); writeb(reg_val, TROUT_CPLD_BASE + reg); local_irq_restore(flags); return 0; @@ -258,6 +277,10 @@ static int __init trout_init_gpio(void) if (!machine_is_trout()) return 0; + /* adjust GPIOs based on bootloader request */ + pr_info("trout_init_gpio: cpld_usb_hw2_sw = %d\n", cpld_usb_h2w_sw); + trout_gpio_write_shadow(TROUT_GPIO_USB_H2W_SW, cpld_usb_h2w_sw); + for(i = 0; i < ARRAY_SIZE(trout_cpld_shadow); i++) writeb(trout_cpld_shadow[i], TROUT_CPLD_BASE + i * 2); diff --git a/arch/arm/mach-msm/board-trout.c b/arch/arm/mach-msm/board-trout.c index 90762c66650b..c3fd5fe0eb89 100644 --- a/arch/arm/mach-msm/board-trout.c +++ b/arch/arm/mach-msm/board-trout.c @@ -602,14 +602,8 @@ static void __init trout_init_irq(void) msm_init_irq(); } -static uint cpld_iset; -static uint cpld_charger_en; -static uint cpld_usb_h2w_sw; static uint opt_disable_uart3; -module_param_named(iset, cpld_iset, uint, 0); -module_param_named(charger_en, cpld_charger_en, uint, 0); -module_param_named(usb_h2w_sw, cpld_usb_h2w_sw, uint, 0); module_param_named(disable_uart3, opt_disable_uart3, uint, 0); static int __init trout_serialno_setup(char *str) @@ -683,10 +677,6 @@ static void __init trout_init(void) msm_acpu_clock_init(&trout_clock_data); - /* adjust GPIOs based on bootloader request */ - printk("trout_init: cpld_usb_hw2_sw = %d\n", cpld_usb_h2w_sw); - gpio_set_value(TROUT_GPIO_USB_H2W_SW, cpld_usb_h2w_sw); - #if defined(CONFIG_MSM_SERIAL_DEBUGGER) if (!opt_disable_uart3) msm_serial_debug_init(MSM_UART3_PHYS, INT_UART3, @@ -695,16 +685,6 @@ static void __init trout_init(void) /* gpio_configure(108, IRQF_TRIGGER_LOW); */ -#if defined(CONFIG_LL_DEBUG_UART1) - /* H2W pins <-> UART1 */ - gpio_set_value(TROUT_GPIO_H2W_SEL0, 1); - gpio_set_value(TROUT_GPIO_H2W_SEL1, 0); -#else - /* H2W pins <-> UART3, Bluetooth <-> UART1 */ - gpio_set_value(TROUT_GPIO_H2W_SEL0, 0); - gpio_set_value(TROUT_GPIO_H2W_SEL1, 1); -#endif - /* put the AF VCM in powerdown mode to avoid noise */ gpio_set_value(TROUT_GPIO_VCM_PWDN, 1); mdelay(100); -- cgit v1.2.3 From 929bc38be5747b499055664ee2079fda168d2ef3 Mon Sep 17 00:00:00 2001 From: Nick Pelly Date: Mon, 1 Dec 2008 22:22:13 -0800 Subject: [ARM] msm: Fix bugs preventing modular build Signed-off-by: Nick Pelly --- arch/arm/mach-msm/dma.c | 2 +- arch/arm/mach-msm/io.c | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/dma.c b/arch/arm/mach-msm/dma.c index f5420f9585c5..73c186d14d10 100644 --- a/arch/arm/mach-msm/dma.c +++ b/arch/arm/mach-msm/dma.c @@ -15,6 +15,7 @@ #include #include +#include #include #define MSM_DMOV_CHANNEL_COUNT 16 @@ -243,4 +244,3 @@ static int __init msm_init_datamover(void) } arch_initcall(msm_init_datamover); - diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c index 1c5e7dac086f..59d0ff42600f 100644 --- a/arch/arm/mach-msm/io.c +++ b/arch/arm/mach-msm/io.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -78,3 +79,5 @@ __msm_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype) return __arm_ioremap(phys_addr, size, mtype); } + +EXPORT_SYMBOL(__msm_ioremap); -- cgit v1.2.3 From 5f9d27925120f30052f91fd5c8bf9f3e91aed10b Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Thu, 4 Dec 2008 10:17:50 -0800 Subject: [ARM] msm: Turn ON DMA support for SDC1 Signed-off-by: Brian Swetland --- arch/arm/mach-msm/devices.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/devices.c b/arch/arm/mach-msm/devices.c index b39eab0f5ad6..3004c2b0a0d1 100644 --- a/arch/arm/mach-msm/devices.c +++ b/arch/arm/mach-msm/devices.c @@ -168,13 +168,11 @@ static struct resource resources_sdc1[] = { .end = INT_SDC1_1, .flags = IORESOURCE_IRQ, }, -#if 0 { .start = 8, .end = 8, .flags = IORESOURCE_DMA, }, -#endif }; static struct resource resources_sdc2[] = { -- cgit v1.2.3 From 1617f4574f9c62999f32a93ba98f050f5147adc6 Mon Sep 17 00:00:00 2001 From: Mike Chan Date: Wed, 3 Dec 2008 11:06:41 -0800 Subject: [ARM] msm: clock: Support for freq table in speed selection. Change/disable full range of frequencies from /sys in userspace. Signed-off-by: Mike Chan --- arch/arm/mach-msm/acpuclock.c | 16 +++++++++++++++- arch/arm/mach-msm/cpufreq.c | 36 +++++++++++++++++++----------------- 2 files changed, 34 insertions(+), 18 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/acpuclock.c b/arch/arm/mach-msm/acpuclock.c index c228d365998f..93de418f203b 100644 --- a/arch/arm/mach-msm/acpuclock.c +++ b/arch/arm/mach-msm/acpuclock.c @@ -101,6 +101,18 @@ static struct clkctl_acpu_speed acpu_freq_tbl[] = { }; #endif +#ifdef CONFIG_MSM_CPU_FREQ_ONDEMAND +static struct cpufreq_frequency_table freq_table[] = { + { 0, 19200 }, + { 1, 122880 }, + { 2, 128000 }, + { 3, 245760 }, + { 4, 384000 }, + { 5, 528000 }, + { 6, CPUFREQ_TABLE_END }, +}; +#endif + static int pc_pll_request(unsigned id, unsigned on) { int res; @@ -333,7 +345,6 @@ int acpuclk_set_rate(unsigned long rate, int for_power_collapse) udelay(drv_state.acpu_switch_time_us); } - /* Nothing else to do for power collapse. */ if (for_power_collapse) return 0; @@ -451,4 +462,7 @@ void __init msm_acpu_clock_init(struct msm_acpu_clock_platform_data *clkdata) drv_state.wait_for_irq_khz = clkdata->wait_for_irq_khz; acpuclk_init(); lpj_init(); +#ifdef CONFIG_MSM_CPU_FREQ_ONDEMAND + cpufreq_frequency_table_get_attr(freq_table, smp_processor_id()); +#endif } diff --git a/arch/arm/mach-msm/cpufreq.c b/arch/arm/mach-msm/cpufreq.c index 821d2be89fd3..2e5f119160a0 100644 --- a/arch/arm/mach-msm/cpufreq.c +++ b/arch/arm/mach-msm/cpufreq.c @@ -52,25 +52,21 @@ static int msm_cpufreq_target(struct cpufreq_policy *policy, unsigned int target_freq, unsigned int relation) { - unsigned int freq; - switch(relation) { - /* Lowest value at or above target frequency. */ - case CPUFREQ_RELATION_L: - /* Highest value at or below target frequency. */ - case CPUFREQ_RELATION_H: - if (target_freq < CONFIG_MSM_CPU_FREQ_ONDEMAND_MAX) - freq = CONFIG_MSM_CPU_FREQ_ONDEMAND_MIN; - else - freq = CONFIG_MSM_CPU_FREQ_ONDEMAND_MAX; - break; - default: - return -EINVAL; + int index; + struct cpufreq_frequency_table *table = + cpufreq_frequency_get_table(smp_processor_id()); + + if (cpufreq_frequency_table_target(policy, table, target_freq, relation, + &index)) { + pr_err("cpufreq: invalid target_freq: %d\n", target_freq); + return -EINVAL; } + #ifdef CONFIG_CPU_FREQ_DEBUG printk("msm_cpufreq_target %d r %d (%d-%d) selected %d\n", target_freq, - relation, policy->min, policy->max, freq); + relation, policy->min, policy->max, table[index].frequency); #endif - acpuclk_set_rate(freq * 1000, 0); + acpuclk_set_rate(table[index].frequency * 1000, 0); return 0; } @@ -83,11 +79,17 @@ return 0; static int __init msm_cpufreq_init(struct cpufreq_policy *policy) { + struct cpufreq_frequency_table *table = + cpufreq_frequency_get_table(smp_processor_id()); + policy->cur = acpuclk_get_rate(); + if (cpufreq_frequency_table_cpuinfo(policy, table)) { + policy->cpuinfo.min_freq = CONFIG_MSM_CPU_FREQ_ONDEMAND_MIN; + policy->cpuinfo.max_freq = CONFIG_MSM_CPU_FREQ_ONDEMAND_MAX; + } policy->min = CONFIG_MSM_CPU_FREQ_ONDEMAND_MIN; policy->max = CONFIG_MSM_CPU_FREQ_ONDEMAND_MAX; - policy->cpuinfo.min_freq = CONFIG_MSM_CPU_FREQ_ONDEMAND_MIN; - policy->cpuinfo.max_freq = CONFIG_MSM_CPU_FREQ_ONDEMAND_MAX; + policy->cpuinfo.transition_latency = acpuclk_get_switch_time() * NSEC_PER_USEC; return 0; -- cgit v1.2.3 From 5d8264851d2941f6a60f0312725bf65eca27641e Mon Sep 17 00:00:00 2001 From: Nick Pelly Date: Wed, 3 Dec 2008 20:08:31 -0800 Subject: [ARM] msm: trout: Remove uart2dm from board file (its not in use). Signed-off-by: Nick Pelly --- arch/arm/mach-msm/board-trout.c | 1 - 1 file changed, 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/board-trout.c b/arch/arm/mach-msm/board-trout.c index c3fd5fe0eb89..d4f07dfaa466 100644 --- a/arch/arm/mach-msm/board-trout.c +++ b/arch/arm/mach-msm/board-trout.c @@ -571,7 +571,6 @@ static struct platform_device *devices[] __initdata = { #endif #ifdef CONFIG_SERIAL_MSM_HS &msm_device_uart_dm1, - &msm_device_uart_dm2, #endif #ifdef CONFIG_USB_FUNCTION &msm_device_hsusb, -- cgit v1.2.3 From 6dbb71207aeeb32801d5efdc56304a290ce5bd95 Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Mon, 24 Nov 2008 19:27:15 -0500 Subject: [ARM] msm: trout: Refactor msm_hsusb platform data for msm72k_udc driver. Signed-off-by: Mike Lockwood --- arch/arm/mach-msm/board-trout.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/board-trout.c b/arch/arm/mach-msm/board-trout.c index d4f07dfaa466..b375fc9595ea 100644 --- a/arch/arm/mach-msm/board-trout.c +++ b/arch/arm/mach-msm/board-trout.c @@ -60,9 +60,7 @@ #include "gpio_chip.h" #include -#ifdef CONFIG_USB_FUNCTION #include -#endif #include @@ -415,8 +413,6 @@ static struct platform_device sd_door_switch = { }, }; -#ifdef CONFIG_USB_FUNCTION - /* adjust eye diagram, disable vbusvalid interrupts */ static int trout_phy_init_seq[] = { 0x40, 0x31, 0x1D, 0x0D, 0x1D, 0x10, -1 }; @@ -428,6 +424,7 @@ static void trout_phy_reset(void) mdelay(10); } +#ifdef CONFIG_USB_FUNCTION static char *trout_usb_functions[] = { #if defined(CONFIG_USB_FUNCTION_MASS_STORAGE) || defined(CONFIG_USB_FUNCTION_UMS) "usb_mass_storage", @@ -447,10 +444,12 @@ static struct msm_hsusb_product trout_usb_products[] = { .functions = 0x00000003, /* "usb_mass_storage" and "adb" */ }, }; +#endif static struct msm_hsusb_platform_data msm_hsusb_pdata = { .phy_reset = trout_phy_reset, .phy_init_seq = trout_phy_init_seq, +#ifdef CONFIG_USB_FUNCTION .vendor_id = 0x0bb4, .product_id = 0x0c02, .version = 0x0100, @@ -461,8 +460,10 @@ static struct msm_hsusb_platform_data msm_hsusb_pdata = { .num_functions = ARRAY_SIZE(trout_usb_functions), .products = trout_usb_products, .num_products = ARRAY_SIZE(trout_usb_products), +#endif }; +#ifdef CONFIG_USB_FUNCTION_MASS_STORAGE static struct usb_mass_storage_platform_data mass_storage_pdata = { .nluns = 1, .buf_size = 16384, @@ -572,8 +573,8 @@ static struct platform_device *devices[] __initdata = { #ifdef CONFIG_SERIAL_MSM_HS &msm_device_uart_dm1, #endif -#ifdef CONFIG_USB_FUNCTION &msm_device_hsusb, +#ifdef CONFIG_USB_FUNCTION_MASS_STORAGE &usb_mass_storage_device, #endif &trout_nav_device, -- cgit v1.2.3 From 0c1562e125ef526bf6577d41ff16add11fb8256a Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Fri, 28 Nov 2008 22:15:05 -0500 Subject: [ARM] msm: trout: Support for android_usb composite USB gadget driver. Signed-off-by: Mike Lockwood --- arch/arm/mach-msm/board-trout.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/board-trout.c b/arch/arm/mach-msm/board-trout.c index b375fc9595ea..8c781a73e515 100644 --- a/arch/arm/mach-msm/board-trout.c +++ b/arch/arm/mach-msm/board-trout.c @@ -31,6 +31,9 @@ #ifdef CONFIG_USB_FUNCTION #include #endif +#ifdef CONFIG_USB_ANDROID +#include +#endif #include @@ -481,6 +484,26 @@ static struct platform_device usb_mass_storage_device = { }; #endif +#ifdef CONFIG_USB_ANDROID +static struct android_usb_platform_data android_usb_pdata = { + .vendor_id = 0x0bb4, + .product_id = 0x0c01, + .adb_product_id = 0x0c02, + .version = 0x0100, + .product_name = "Android Phone", + .manufacturer_name = "HTC", + .nluns = 1, +}; + +static struct platform_device android_usb_device = { + .name = "android_usb", + .id = -1, + .dev = { + .platform_data = &android_usb_pdata, + }, +}; +#endif + static struct resource trout_ram_console_resource[] = { { .start = MSM_RAM_CONSOLE_BASE, @@ -576,6 +599,9 @@ static struct platform_device *devices[] __initdata = { &msm_device_hsusb, #ifdef CONFIG_USB_FUNCTION_MASS_STORAGE &usb_mass_storage_device, +#endif +#ifdef CONFIG_USB_ANDROID + &android_usb_device, #endif &trout_nav_device, &trout_reset_keys_device, @@ -610,6 +636,9 @@ static int __init trout_serialno_setup(char *str) { #ifdef CONFIG_USB_FUNCTION msm_hsusb_pdata.serial_number = str; +#endif +#ifdef CONFIG_USB_ANDROID + android_usb_pdata.serial_number = str; #endif return 1; } -- cgit v1.2.3 From 2298b4600375e4b81c42ea27996e63a3e37c2410 Mon Sep 17 00:00:00 2001 From: Mike Chan Date: Fri, 5 Dec 2008 15:56:40 -0800 Subject: [ARM] msm: clock: Fix cpu speed ramping down from 528mhz. Should not jump from 528mhz -> 245mhz this is greater than 256mhz spec. Signed-off-by: Mike Chan --- arch/arm/mach-msm/acpuclock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/acpuclock.c b/arch/arm/mach-msm/acpuclock.c index 93de418f203b..2be1cee79db2 100644 --- a/arch/arm/mach-msm/acpuclock.c +++ b/arch/arm/mach-msm/acpuclock.c @@ -96,7 +96,7 @@ static struct clkctl_acpu_speed acpu_freq_tbl[] = { { 128000, ACPU_PLL_1, 1, 5, 64000, 1, VDD_3, 0, 0, 4 }, { 245760, ACPU_PLL_0, 4, 0, 81920, 2, VDD_4, 0, 0, 4 }, { 384000, ACPU_PLL_1, 1, 1, 128000, 2, VDD_6, 0, 2, -1 }, - { 528000, ACPU_PLL_2, 2, 1, 132000, 3, VDD_7, 0, 3, -1 }, + { 528000, ACPU_PLL_2, 2, 1, 132000, 3, VDD_7, 0, 4, -1 }, { 0, 0, 0, 0, 0, 0, 0}, }; #endif -- cgit v1.2.3 From a9674fc0ff15dc5d53c3450bacdf66bae8539246 Mon Sep 17 00:00:00 2001 From: Arve Hjønnevåg Date: Wed, 10 Dec 2008 19:45:39 -0800 Subject: [ARM] msm: trout-h2w: Don't call request_irq with interrupts disabled. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Arve Hjønnevåg --- arch/arm/mach-msm/board-trout-h2w.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/board-trout-h2w.c b/arch/arm/mach-msm/board-trout-h2w.c index f8282b4e4899..66b82707a3b3 100644 --- a/arch/arm/mach-msm/board-trout-h2w.c +++ b/arch/arm/mach-msm/board-trout-h2w.c @@ -367,7 +367,6 @@ device_initcall(h2w_debug_init); static int trout_h2w_probe(struct platform_device *pdev) { int ret; - unsigned long irq_flags; printk(KERN_INFO "H2W: Registering H2W (headset) driver\n"); hi = kzalloc(sizeof(struct h2w_info), GFP_KERNEL); @@ -431,13 +430,13 @@ static int trout_h2w_probe(struct platform_device *pdev) hrtimer_init(&hi->btn_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); hi->btn_timer.function = button_event_timer_func; - local_irq_save(irq_flags); - ret = request_irq(hi->irq, detect_irq_handler, IRQF_TRIGGER_LOW, "h2w_detect", NULL); if (ret < 0) goto err_request_detect_irq; + /* Disable button until plugged in */ + set_irq_flags(hi->irq_btn, IRQF_VALID | IRQF_NOAUTOEN); ret = request_irq(hi->irq_btn, button_irq_handler, IRQF_TRIGGER_LOW, "h2w_button", NULL); if (ret < 0) @@ -450,10 +449,6 @@ static int trout_h2w_probe(struct platform_device *pdev) if (ret < 0) goto err_request_input_dev; - /* Disable button until plugged in */ - disable_irq(hi->irq_btn); - local_irq_restore(irq_flags); - hi->input = input_allocate_device(); if (!hi->input) { ret = -ENOMEM; @@ -477,7 +472,6 @@ err_request_input_dev: err_request_h2w_headset_button_irq: free_irq(hi->irq, 0); err_request_detect_irq: - local_irq_restore(irq_flags); err_get_button_irq_num_failed: err_get_h2w_detect_irq_num_failed: err_set_button_gpio: -- cgit v1.2.3 From 4962695728a7427f4c7d70f69568b1a027748ea1 Mon Sep 17 00:00:00 2001 From: Arve Hjønnevåg Date: Wed, 10 Dec 2008 19:48:05 -0800 Subject: [ARM] msm: generic_gpio: Don't pass GFP_KERNEL to kmalloc when holding a spinlock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Arve Hjønnevåg --- arch/arm/mach-msm/generic_gpio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/generic_gpio.c b/arch/arm/mach-msm/generic_gpio.c index 86093130f457..fe24d38345d0 100644 --- a/arch/arm/mach-msm/generic_gpio.c +++ b/arch/arm/mach-msm/generic_gpio.c @@ -54,7 +54,7 @@ int register_gpio_chip(struct gpio_chip *new_gpio_chip) struct gpio_chip **new_gpio_chip_array; unsigned long new_gpio_chip_array_size = chip_array_end_index + 1; - new_gpio_chip_array = kmalloc(new_gpio_chip_array_size * sizeof(new_gpio_chip_array[0]), GFP_KERNEL); + new_gpio_chip_array = kmalloc(new_gpio_chip_array_size * sizeof(new_gpio_chip_array[0]), GFP_ATOMIC); if (new_gpio_chip_array == NULL) { printk(KERN_ERR "register_gpio_chip: failed to allocate array\n"); err = -ENOMEM; -- cgit v1.2.3 From f339a24a9e854cd6267a4527a7426c727a23b2b4 Mon Sep 17 00:00:00 2001 From: Arve Hjønnevåg Date: Wed, 10 Dec 2008 19:51:50 -0800 Subject: [ARM] msm: gpio: Don't call generic_handle_irq with interrupts enabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Arve Hjønnevåg --- arch/arm/mach-msm/gpio.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/gpio.c b/arch/arm/mach-msm/gpio.c index 24b510986e70..ba41ee1f7a79 100644 --- a/arch/arm/mach-msm/gpio.c +++ b/arch/arm/mach-msm/gpio.c @@ -422,6 +422,7 @@ static void msm_gpio_sleep_int(unsigned long arg) if (smem_gpio == NULL) return; + local_irq_disable(); for(i = 0; i < GPIO_SMEM_NUM_GROUPS; i++) { int count = smem_gpio->num_fired[i]; for(j = 0; j < count; j++) { @@ -429,6 +430,7 @@ static void msm_gpio_sleep_int(unsigned long arg) generic_handle_irq(MSM_GPIO_TO_INT(smem_gpio->fired[i][j])); } } + local_irq_enable(); } static DECLARE_TASKLET(msm_gpio_sleep_int_tasklet, msm_gpio_sleep_int, 0); -- cgit v1.2.3 From 051b3341c1f0f03110ef108b6618b59955228886 Mon Sep 17 00:00:00 2001 From: Nick Pelly Date: Thu, 11 Dec 2008 16:22:52 -0800 Subject: [ARM] msm: trout: Use low power wakeup on the bluetooth uart. Wakeup on GPIO 45 (UART 1 RX). Send character 0x32 (HCILL wake up indicator). Signed-off-by: Nick Pelly --- arch/arm/mach-msm/board-trout.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/board-trout.c b/arch/arm/mach-msm/board-trout.c index 8c781a73e515..19563c845ae7 100644 --- a/arch/arm/mach-msm/board-trout.c +++ b/arch/arm/mach-msm/board-trout.c @@ -64,7 +64,7 @@ #include #include - +#include #include #include "proc_comm.h" @@ -691,6 +691,14 @@ static struct msm_acpu_clock_platform_data trout_clock_data = { .wait_for_irq_khz = 128000000, }; +#ifdef CONFIG_SERIAL_MSM_HS +static struct msm_serial_hs_platform_data msm_uart_dm1_pdata = { + .wakeup_irq = MSM_GPIO_TO_INT(45), + .inject_rx_on_wakeup = 1, + .rx_to_inject = 0x32, +}; +#endif + static void __init trout_init(void) { int rc; @@ -725,6 +733,10 @@ static void __init trout_init(void) msm_device_hsusb.dev.platform_data = &msm_hsusb_pdata; +#ifdef CONFIG_SERIAL_MSM_HS + msm_device_uart_dm1.dev.platform_data = &msm_uart_dm1_pdata; +#endif + rc = trout_init_mmc(system_rev); if (rc) printk(KERN_CRIT "%s: MMC init failure (%d)\n", __func__, rc); -- cgit v1.2.3 From 0055e8fc0581f32fdc1025e7605e57abf2c6dd7a Mon Sep 17 00:00:00 2001 From: Mike Chan Date: Wed, 10 Dec 2008 13:22:14 -0800 Subject: [ARM]: msm: clock: Adding PLL2 clocks for 528 power collapse stepping. Signed-off-by: Mike Chan --- arch/arm/mach-msm/acpuclock.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/acpuclock.c b/arch/arm/mach-msm/acpuclock.c index 2be1cee79db2..6ea137be23e8 100644 --- a/arch/arm/mach-msm/acpuclock.c +++ b/arch/arm/mach-msm/acpuclock.c @@ -91,12 +91,14 @@ static struct clkctl_acpu_speed acpu_freq_tbl[] = { }; #else /* Table of freq we currently use. */ static struct clkctl_acpu_speed acpu_freq_tbl[] = { - { 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, VDD_0, 0, 0, 3 }, - { 122880, ACPU_PLL_0, 4, 1, 61440, 1, VDD_3, 0, 0, 3 }, - { 128000, ACPU_PLL_1, 1, 5, 64000, 1, VDD_3, 0, 0, 4 }, - { 245760, ACPU_PLL_0, 4, 0, 81920, 2, VDD_4, 0, 0, 4 }, + { 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, VDD_0, 0, 0, 4 }, + { 122880, ACPU_PLL_0, 4, 1, 61440, 1, VDD_3, 0, 0, 4 }, + { 128000, ACPU_PLL_1, 1, 5, 64000, 1, VDD_3, 0, 0, 6 }, + { 176000, ACPU_PLL_2, 2, 5, 88000, 1, VDD_3, 0, 0, 5 }, + { 245760, ACPU_PLL_0, 4, 0, 81920, 2, VDD_4, 0, 0, 5 }, + { 352000, ACPU_PLL_2, 2, 2, 88000, 3, VDD_5, 0, 3, 7 }, { 384000, ACPU_PLL_1, 1, 1, 128000, 2, VDD_6, 0, 2, -1 }, - { 528000, ACPU_PLL_2, 2, 1, 132000, 3, VDD_7, 0, 4, -1 }, + { 528000, ACPU_PLL_2, 2, 1, 132000, 3, VDD_7, 0, 5, -1 }, { 0, 0, 0, 0, 0, 0, 0}, }; #endif -- cgit v1.2.3 From 28057b7f41963cf32cf6ee5558789fa2b7f81eed Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Thu, 18 Dec 2008 12:40:04 -0800 Subject: [ARM] trout: Add abstract wifi control functions support --- arch/arm/mach-msm/Kconfig | 10 +++++ arch/arm/mach-msm/Makefile | 2 +- arch/arm/mach-msm/board-trout-mmc.c | 26 ++++++++----- arch/arm/mach-msm/board-trout-wifi.c | 74 ++++++++++++++++++++++++++++++++++++ arch/arm/mach-msm/board-trout.c | 30 +++++++++++++++ 5 files changed, 132 insertions(+), 10 deletions(-) create mode 100644 arch/arm/mach-msm/board-trout-wifi.c (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index e9abede32c7d..9c09e1ba8b1d 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -277,4 +277,14 @@ config MSM_CPU_FREQ_ONDEMAND_MIN endif # MSM_CPU_FREQ_ONDEMAND +config WIFI_CONTROL_FUNC + bool "Enable WiFi control function abstraction" + help + Enables Power/Reset/Carddetect function abstraction + +config WIFI_MEM_PREALLOC + depends on WIFI_CONTROL_FUNC + bool "Preallocate memory for WiFi buffers" + help + Preallocates memory buffers for WiFi driver endif diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index d8f1a307b0ae..c418bd1495d9 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -22,7 +22,7 @@ obj-$(CONFIG_MSM_CPU_FREQ) += cpufreq.o obj-$(CONFIG_MACH_TROUT) += board-dream.o obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o board-halibut-keypad.o obj-$(CONFIG_MACH_TROUT) += htc_akm_cal.o htc_wifi_nvs.o htc_acoustic.o -obj-$(CONFIG_MACH_TROUT) += board-trout-mmc.o +obj-$(CONFIG_MACH_TROUT) += board-trout-mmc.o board-trout-wifi.o obj-$(CONFIG_TROUT_H2W) += board-trout-h2w.o obj-$(CONFIG_TROUT_BATTCHG) += htc_battery.o obj-$(CONFIG_TROUT_PWRSINK) += htc_pwrsink.o diff --git a/arch/arm/mach-msm/board-trout-mmc.c b/arch/arm/mach-msm/board-trout-mmc.c index a82eb3a42296..ba759293ff03 100644 --- a/arch/arm/mach-msm/board-trout-mmc.c +++ b/arch/arm/mach-msm/board-trout-mmc.c @@ -236,14 +236,7 @@ static unsigned int trout_wifi_status(struct device *dev) return trout_wifi_cd; } -static struct mmc_platform_data trout_wifi_data = { - .ocr_mask = MMC_VDD_28_29, - .status = trout_wifi_status, - .register_status_notify = trout_wifi_status_register, - .embedded_sdio = &trout_wifi_emb_data, -}; - -void trout_wifi_set_carddetect(int val) +int trout_wifi_set_carddetect(int val) { printk("%s: %d\n", __func__, val); trout_wifi_cd = val; @@ -251,8 +244,11 @@ void trout_wifi_set_carddetect(int val) wifi_status_cb(val, wifi_status_cb_devid); } else printk(KERN_WARNING "%s: Nobody to notify\n", __func__); + return 0; } +#ifndef CONFIG_WIFI_CONTROL_FUNC EXPORT_SYMBOL(trout_wifi_set_carddetect); +#endif static int trout_wifi_power_state; @@ -284,17 +280,29 @@ int trout_wifi_power(int on) trout_wifi_power_state = on; return 0; } +#ifndef CONFIG_WIFI_CONTROL_FUNC EXPORT_SYMBOL(trout_wifi_power); +#endif static int trout_wifi_reset_state; -void trout_wifi_reset(int on) +int trout_wifi_reset(int on) { printk("%s: %d\n", __func__, on); gpio_set_value( TROUT_GPIO_WIFI_PA_RESETX, !on ); trout_wifi_reset_state = on; mdelay(50); + return 0; } +#ifndef CONFIG_WIFI_CONTROL_FUNC EXPORT_SYMBOL(trout_wifi_reset); +#endif + +static struct mmc_platform_data trout_wifi_data = { + .ocr_mask = MMC_VDD_28_29, + .status = trout_wifi_status, + .register_status_notify = trout_wifi_status_register, + .embedded_sdio = &trout_wifi_emb_data, +}; int __init trout_init_mmc(unsigned int sys_rev) { diff --git a/arch/arm/mach-msm/board-trout-wifi.c b/arch/arm/mach-msm/board-trout-wifi.c new file mode 100644 index 000000000000..51b26a405369 --- /dev/null +++ b/arch/arm/mach-msm/board-trout-wifi.c @@ -0,0 +1,74 @@ +/* arch/arm/mach-msm/board-trout-wifi.c + * + * Copyright (C) 2008 Google, Inc. + * Author: Dmitry Shmidt + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#ifdef CONFIG_WIFI_CONTROL_FUNC +#include +#include +#include +#include +#include +#include + +extern int trout_wifi_set_carddetect(int val); +extern int trout_wifi_power(int on); +extern int trout_wifi_reset(int on); + +#ifdef CONFIG_WIFI_MEM_PREALLOC +typedef struct wifi_mem_prealloc_struct { + void *mem_ptr; + unsigned long size; +} wifi_mem_prealloc_t; + +static wifi_mem_prealloc_t wifi_mem_array[WMPA_NUMBER_OF_SECTIONS] = { + { NULL, (WMPA_SECTION_SIZE_0 + WMPA_SECTION_HEADER) }, + { NULL, (WMPA_SECTION_SIZE_1 + WMPA_SECTION_HEADER) }, + { NULL, (WMPA_SECTION_SIZE_2 + WMPA_SECTION_HEADER) } +}; + +static void *trout_wifi_mem_prealloc(int section, unsigned long size) +{ + if( (section < 0) || (section >= WMPA_NUMBER_OF_SECTIONS) ) + return NULL; + if( wifi_mem_array[section].size < size ) + return NULL; + return wifi_mem_array[section].mem_ptr; +} + +int __init trout_init_wifi_mem( void ) +{ + int i; + + for(i=0;( i < WMPA_NUMBER_OF_SECTIONS );i++) { + wifi_mem_array[i].mem_ptr = vmalloc(wifi_mem_array[i].size); + if( wifi_mem_array[i].mem_ptr == NULL ) + return -ENOMEM; + } + return 0; +} +#endif + +struct wifi_platform_data trout_wifi_control = { + .set_power = trout_wifi_power, + .set_reset = trout_wifi_reset, + .set_carddetect = trout_wifi_set_carddetect, +#ifdef CONFIG_WIFI_MEM_PREALLOC + .mem_prealloc = trout_wifi_mem_prealloc, +#else + .mem_prealloc = NULL, +#endif +}; + +#endif diff --git a/arch/arm/mach-msm/board-trout.c b/arch/arm/mach-msm/board-trout.c index 19563c845ae7..236f9f739bc0 100644 --- a/arch/arm/mach-msm/board-trout.c +++ b/arch/arm/mach-msm/board-trout.c @@ -66,6 +66,9 @@ #include #include #include +#ifdef CONFIG_WIFI_CONTROL_FUNC +#include +#endif #include "proc_comm.h" #include "devices.h" @@ -74,6 +77,12 @@ void msm_init_irq(void); void msm_init_gpio(void); extern int trout_init_mmc(unsigned int); +#ifdef CONFIG_WIFI_CONTROL_FUNC +#ifdef CONFIG_WIFI_MEM_PREALLOC +extern int trout_init_wifi_mem(void); +#endif +extern struct wifi_platform_data trout_wifi_control; +#endif struct trout_axis_info { struct gpio_event_axis_info info; @@ -585,6 +594,18 @@ static struct platform_device trout_rfkill = { .id = -1, }; +#ifdef CONFIG_WIFI_CONTROL_FUNC +static struct platform_device trout_wifi = { + .name = "msm_wifi", + .id = 1, + .num_resources = 0, + .resource = NULL, + .dev = { + .platform_data = &trout_wifi_control, + }, +}; +#endif + static struct platform_device *devices[] __initdata = { &msm_device_smd, &msm_device_nand, @@ -615,6 +636,9 @@ static struct platform_device *devices[] __initdata = { &android_pmem_camera_device, &trout_ram_console_device, &trout_rfkill, +#ifdef CONFIG_WIFI_CONTROL_FUNC + &trout_wifi, +#endif #if defined(CONFIG_TROUT_PWRSINK) &trout_pwr_sink, #endif @@ -741,6 +765,12 @@ static void __init trout_init(void) if (rc) printk(KERN_CRIT "%s: MMC init failure (%d)\n", __func__, rc); +#ifdef CONFIG_WIFI_MEM_PREALLOC + rc = trout_init_wifi_mem(); + if (rc) + printk(KERN_CRIT "%s: WiFi Memory init failure (%d)\n", __func__, rc); +#endif + platform_add_devices(devices, ARRAY_SIZE(devices)); i2c_register_board_info(0, i2c_devices, ARRAY_SIZE(i2c_devices)); -- cgit v1.2.3 From 2a3cde0cad0927680c6842696d9263fa472330eb Mon Sep 17 00:00:00 2001 From: Iliyan Malchev Date: Fri, 19 Dec 2008 13:30:47 -0800 Subject: [ARM] msm: halibut: add list of SND endpoints Signed-off-by: Iliyan Malchev --- arch/arm/mach-msm/board-halibut.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/board-halibut.c b/arch/arm/mach-msm/board-halibut.c index 33e70f07b69a..4bdf17c4c3f2 100644 --- a/arch/arm/mach-msm/board-halibut.c +++ b/arch/arm/mach-msm/board-halibut.c @@ -67,6 +67,7 @@ static struct platform_device *devices[] __initdata = { &msm_device_hsusb, &msm_device_i2c, &smc91x_device, + &halibut_snd, }; extern struct sys_timer msm_timer; @@ -85,7 +86,7 @@ static struct msm_acpu_clock_platform_data halibut_clock_data = { }; void msm_serial_debug_init(unsigned int base, int irq, - struct device *clk_device, int signal_irq); + struct device *clk_device, int signal_irq); static void __init halibut_init(void) { @@ -100,7 +101,7 @@ static void __init halibut_init(void) static void __init halibut_fixup(struct machine_desc *desc, struct tag *tags, char **cmdline, struct meminfo *mi) { - mi->nr_banks=1; + mi->nr_banks = 1; mi->bank[0].start = PHYS_OFFSET; mi->bank[0].node = PHYS_TO_NID(PHYS_OFFSET); mi->bank[0].size = (101*1024*1024); -- cgit v1.2.3 From 7952b695b64cec5834e3b3e3de1811aefa27b0e5 Mon Sep 17 00:00:00 2001 From: Iliyan Malchev Date: Fri, 19 Dec 2008 13:35:06 -0800 Subject: [ARM] msm: trout: add list of SND endpoints Signed-off-by: Iliyan Malchev --- arch/arm/mach-msm/board-trout.c | 62 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/board-trout.c b/arch/arm/mach-msm/board-trout.c index 236f9f739bc0..2bbcd39dd4e3 100644 --- a/arch/arm/mach-msm/board-trout.c +++ b/arch/arm/mach-msm/board-trout.c @@ -57,6 +57,7 @@ #include #include +#include #include "board-trout.h" @@ -606,6 +607,66 @@ static struct platform_device trout_wifi = { }; #endif +#define SND(desc,num) { .name = #desc, .id = num } +static struct snd_endpoint snd_endpoints_list[] = { + SND(HANDSET, 0), + SND(SPEAKER, 1), + SND(HEADSET, 2), + SND(BT, 3), + SND(HEADSET_AND_SPEAKER, 10), + SND(CURRENT, 256), + + /* Bluetooth accessories. */ + + SND(BH_S100, 12), + SND(BH_M100, 13), + SND(Motorola_H500, 14), + SND(Nokia_HS_36W, 15), + SND(PLT_510vD, 16), + SND(M2500_Plantronics, 17), + SND(Nokia_HDW_3, 18), + SND(HBH_608, 19), + SND(HBH_DS970, 20), + SND(iTech_BlueBAND, 21), + SND(Nokia_BH_800, 22), + SND(Motorola_H700, 23), + SND(HTC_BH_M200, 24), + SND(Jabra_JX10, 25), + SND(Plantronics_320, 26), + SND(Plantronics_640, 27), + SND(Jabra_BT500, 28), + SND(Motorola_HT820, 29), + SND(HBH_IV840, 30), + SND(Plantronics_6XX, 31), + SND(Plantronics_3XX, 32), + SND(HBH_PV710, 33), + SND(Motorola_H670, 34), + SND(HBM_300, 35), + SND(Nokia_BH_208, 36), + SND(Samsung_WEP410, 37), + SND(Jabra_BT8010, 38), + SND(Motorola_S9, 39), + SND(Jabra_BT620s, 40), + SND(Nokia_BH_902, 41), + SND(HBH_DS220, 42), + SND(HBH_DS980, 43), + SND(BT_EC_OFF, 44), +}; +#undef SND + +static struct msm_snd_endpoints trout_snd_endpoints = { + .endpoints = snd_endpoints_list, + .num = ARRAY_SIZE(snd_endpoints_list), +}; + +static struct platform_device trout_snd = { + .name = "msm_snd", + .id = -1, + .dev = { + .platform_data = &trout_snd_endpoints, + }, +}; + static struct platform_device *devices[] __initdata = { &msm_device_smd, &msm_device_nand, @@ -642,6 +703,7 @@ static struct platform_device *devices[] __initdata = { #if defined(CONFIG_TROUT_PWRSINK) &trout_pwr_sink, #endif + &trout_snd, }; extern struct sys_timer msm_timer; -- cgit v1.2.3 From fc83ede17f5b6327ef5fbd93c460173bdf07f7f6 Mon Sep 17 00:00:00 2001 From: Iliyan Malchev Date: Tue, 23 Dec 2008 16:05:31 -0800 Subject: [ARM] msm: trout: amend the names of Bluetooth devices Signed-off-by: Iliyan Malchev --- arch/arm/mach-msm/board-trout.c | 80 ++++++++++++++++++++--------------------- 1 file changed, 40 insertions(+), 40 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/board-trout.c b/arch/arm/mach-msm/board-trout.c index 2bbcd39dd4e3..781fa3c42ccd 100644 --- a/arch/arm/mach-msm/board-trout.c +++ b/arch/arm/mach-msm/board-trout.c @@ -607,50 +607,50 @@ static struct platform_device trout_wifi = { }; #endif -#define SND(desc,num) { .name = #desc, .id = num } +#define SND(num, desc) { .name = desc, .id = num } static struct snd_endpoint snd_endpoints_list[] = { - SND(HANDSET, 0), - SND(SPEAKER, 1), - SND(HEADSET, 2), - SND(BT, 3), - SND(HEADSET_AND_SPEAKER, 10), - SND(CURRENT, 256), + SND(0, "HANDSET"), + SND(1, "SPEAKER"), + SND(2, "HEADSET"), + SND(3, "BT"), + SND(44, "BT_EC_OFF"), + SND(10, "HEADSET_AND_SPEAKER"), + SND(256, "CURRENT"), /* Bluetooth accessories. */ - SND(BH_S100, 12), - SND(BH_M100, 13), - SND(Motorola_H500, 14), - SND(Nokia_HS_36W, 15), - SND(PLT_510vD, 16), - SND(M2500_Plantronics, 17), - SND(Nokia_HDW_3, 18), - SND(HBH_608, 19), - SND(HBH_DS970, 20), - SND(iTech_BlueBAND, 21), - SND(Nokia_BH_800, 22), - SND(Motorola_H700, 23), - SND(HTC_BH_M200, 24), - SND(Jabra_JX10, 25), - SND(Plantronics_320, 26), - SND(Plantronics_640, 27), - SND(Jabra_BT500, 28), - SND(Motorola_HT820, 29), - SND(HBH_IV840, 30), - SND(Plantronics_6XX, 31), - SND(Plantronics_3XX, 32), - SND(HBH_PV710, 33), - SND(Motorola_H670, 34), - SND(HBM_300, 35), - SND(Nokia_BH_208, 36), - SND(Samsung_WEP410, 37), - SND(Jabra_BT8010, 38), - SND(Motorola_S9, 39), - SND(Jabra_BT620s, 40), - SND(Nokia_BH_902, 41), - SND(HBH_DS220, 42), - SND(HBH_DS980, 43), - SND(BT_EC_OFF, 44), + SND(12, "HTC BH S100"), + SND(13, "HTC BH M100"), + SND(14, "Motorola H500"), + SND(15, "Nokia HS-36W"), + SND(16, "PLT 510v.D"), + SND(17, "M2500 by Plantronics"), + SND(18, "Nokia HDW-3"), + SND(19, "HBH-608"), + SND(20, "HBH-DS970"), + SND(21, "i.Tech BlueBAND"), + SND(22, "Nokia BH-800"), + SND(23, "Motorola H700"), + SND(24, "HTC BH M200"), + SND(25, "Jabra JX10"), + SND(26, "320Plantronics"), + SND(27, "640Plantronics"), + SND(28, "Jabra BT500"), + SND(29, "Motorola HT820"), + SND(30, "HBH-IV840"), + SND(31, "6XXPlantronics"), + SND(32, "3XXPlantronics"), + SND(33, "HBH-PV710"), + SND(34, "Motorola H670"), + SND(35, "HBM-300"), + SND(36, "Nokia BH-208"), + SND(37, "Samsung WEP410"), + SND(38, "Jabra BT8010"), + SND(39, "Motorola S9"), + SND(40, "Jabra BT620s"), + SND(41, "Nokia BH-902"), + SND(42, "HBH-DS220"), + SND(43, "HBH-DS980"), }; #undef SND -- cgit v1.2.3 From e7359626f22c0a27d999a12ae70343317551b7b9 Mon Sep 17 00:00:00 2001 From: Rebecca Schultz Zavin Date: Fri, 23 Jan 2009 14:00:46 -0800 Subject: [ARM] msm: trout: Add panel width and height to board file for dpi calculation Signed-off-by: Rebecca Schultz Zavin --- arch/arm/mach-msm/board-trout-panel.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/board-trout-panel.c b/arch/arm/mach-msm/board-trout-panel.c index e81374c30875..8b350d1a382c 100644 --- a/arch/arm/mach-msm/board-trout-panel.c +++ b/arch/arm/mach-msm/board-trout-panel.c @@ -572,6 +572,8 @@ struct msm_mddi_toshiba_client_data toshiba_client_data = { .fb_data = { .xres = 320, .yres = 480, + .width = 45, + .height = 67, .output_format = 0, }, }; -- cgit v1.2.3 From 0433c6a25f368ff17827f2341bd7ea02f37169b2 Mon Sep 17 00:00:00 2001 From: Saravana Kannan Date: Thu, 29 Jan 2009 19:22:50 -0800 Subject: [ARM] msm: acpuclock: Fix conditional compile symbol in acpuclock.h. --- arch/arm/mach-msm/acpuclock.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/acpuclock.h b/arch/arm/mach-msm/acpuclock.h index 0ce5e07e10b3..ab9c3e535747 100644 --- a/arch/arm/mach-msm/acpuclock.h +++ b/arch/arm/mach-msm/acpuclock.h @@ -17,8 +17,8 @@ * */ -#ifndef __ARCH_ARM_MACH_MSM_CLOCK_H -#define __ARCH_ARM_MACH_MSM_CLOCK_H +#ifndef __ARCH_ARM_MACH_MSM_ACPUCLOCK_H +#define __ARCH_ARM_MACH_MSM_ACPUCLOCK_H #include -- cgit v1.2.3 From 19124f08f45f450362eae6afa990bcb33ae4e696 Mon Sep 17 00:00:00 2001 From: Arve Hjønnevåg Date: Thu, 11 Dec 2008 20:10:39 -0800 Subject: [ARM] msm: timer: Don't call ktime_get from msm_timer_sync_smem_clock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Arve Hjønnevåg --- arch/arm/mach-msm/timer.c | 47 ++++++++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 19 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c index 915b26f225fa..e3356bbacae7 100644 --- a/arch/arm/mach-msm/timer.c +++ b/arch/arm/mach-msm/timer.c @@ -183,13 +183,19 @@ static void msm_timer_set_mode(enum clock_event_mode mode, } } +static inline int check_timeout(struct msm_clock *clock, uint32_t timeout) +{ + return (int32_t)(msm_read_timer_count(clock) - timeout) <= 0; +} + static uint32_t msm_timer_sync_smem_clock(int exit_sleep) { struct msm_clock *clock = &msm_clocks[MSM_CLOCK_GPT]; uint32_t *smem_clock; uint32_t smem_clock_val; - s64 timeout; - s64 entry_time; + uint32_t timeout; + uint32_t entry_time; + uint32_t timeout_delta; uint32_t last_state; uint32_t state; uint32_t new_offset; @@ -205,25 +211,27 @@ static uint32_t msm_timer_sync_smem_clock(int exit_sleep) if (!exit_sleep && clock->smem_in_sync) return 0; + timeout_delta = (clock->freq >> (7 - clock->shift)); /* 7.8ms */ + last_state = state = smsm_get_state(); if (*smem_clock) { printk(KERN_INFO "get_smem_clock: invalid start state %x " "clock %u\n", state, *smem_clock); smsm_change_state(SMSM_TIMEWAIT, SMSM_TIMEINIT); - entry_time = ktime_to_ns(ktime_get()); - timeout = ktime_to_ns(ktime_get()) + NSEC_PER_MSEC * 10; - while (*smem_clock != 0 && ktime_to_ns(ktime_get()) < timeout) + entry_time = msm_read_timer_count(clock); + timeout = entry_time + timeout_delta; + while (*smem_clock != 0 && check_timeout(clock, timeout)) ; if (*smem_clock) { printk(KERN_INFO "get_smem_clock: timeout still " - "invalid state %x clock %u in %lld ns\n", + "invalid state %x clock %u in %d ticks\n", state, *smem_clock, - ktime_to_ns(ktime_get()) - entry_time); + msm_read_timer_count(clock) - entry_time); return 0; } } - entry_time = ktime_to_ns(ktime_get()); - timeout = ktime_to_ns(ktime_get()) + NSEC_PER_MSEC * 10; + entry_time = msm_read_timer_count(clock); + timeout = entry_time + timeout_delta; smsm_change_state(SMSM_TIMEINIT, SMSM_TIMEWAIT); do { smem_clock_val = *smem_clock; @@ -233,10 +241,9 @@ static uint32_t msm_timer_sync_smem_clock(int exit_sleep) printk(KERN_INFO "get_smem_clock: state %x clock %u\n", state, smem_clock_val); } - } while (smem_clock_val == 0 && ktime_to_ns(ktime_get()) < timeout); + } while (smem_clock_val == 0 && check_timeout(clock, timeout)); if (smem_clock_val) { new_offset = smem_clock_val - msm_read_timer_count(clock); - writel(TIMER_ENABLE_EN, MSM_GPT_BASE + TIMER_ENABLE); if (clock->offset + clock->smem_offset != new_offset) { if (exit_sleep) clock->offset = new_offset - clock->smem_offset; @@ -251,18 +258,18 @@ static uint32_t msm_timer_sync_smem_clock(int exit_sleep) } } else { printk(KERN_INFO "get_smem_clock: timeout state %x clock %u " - "in %lld ns\n", state, *smem_clock, - ktime_to_ns(ktime_get()) - entry_time); + "in %d ticks\n", state, *smem_clock, + msm_read_timer_count(clock) - entry_time); } smsm_change_state(SMSM_TIMEWAIT, SMSM_TIMEINIT); - entry_time = ktime_to_ns(ktime_get()); - timeout = ktime_to_ns(ktime_get()) + NSEC_PER_MSEC * 10; - while (*smem_clock != 0 && ktime_to_ns(ktime_get()) < timeout) + entry_time = msm_read_timer_count(clock); + timeout = entry_time + timeout_delta; + while (*smem_clock != 0 && check_timeout(clock, timeout)) ; if (*smem_clock) printk(KERN_INFO "get_smem_clock: exit timeout state %x " - "clock %u in %lld ns\n", state, *smem_clock, - ktime_to_ns(ktime_get()) - entry_time); + "clock %u in %d ticks\n", state, *smem_clock, + msm_read_timer_count(clock) - entry_time); return smem_clock_val; } @@ -310,8 +317,10 @@ void msm_timer_exit_idle(int low_power) if (!low_power || clock != &msm_clocks[MSM_CLOCK_GPT]) return; - if (!(readl(clock->regbase + TIMER_ENABLE) & TIMER_ENABLE_EN)) + if (!(readl(clock->regbase + TIMER_ENABLE) & TIMER_ENABLE_EN)) { + writel(TIMER_ENABLE_EN, clock->regbase + TIMER_ENABLE); smem_clock = msm_timer_sync_smem_clock(1); + } msm_timer_reactivate_alarm(clock); } -- cgit v1.2.3 From 4e5a79dc634e951a390b13182e9dde9cc3164f16 Mon Sep 17 00:00:00 2001 From: Arve Hjønnevåg Date: Thu, 11 Dec 2008 19:34:10 -0800 Subject: [ARM] msm: Prevent clocksource read from jumping back after power collapse. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the clock events device is shut down or we are idle, don't read from the hardware, but return a cached value. It would be better to trigger this from the clocksource api, but there is no hook to enable or disable a clocksource. Signed-off-by: Arve Hjønnevåg --- arch/arm/mach-msm/timer.c | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c index e3356bbacae7..ce9af73ad379 100644 --- a/arch/arm/mach-msm/timer.c +++ b/arch/arm/mach-msm/timer.c @@ -71,6 +71,8 @@ struct msm_clock { uint32_t alarm_vtime; uint32_t smem_offset; uint32_t smem_in_sync; + cycle_t stopped_tick; + int stopped; }; enum { MSM_CLOCK_GPT, @@ -111,12 +113,17 @@ static uint32_t msm_read_timer_count(struct msm_clock *clock) static cycle_t msm_gpt_read(struct clocksource *cs) { struct msm_clock *clock = &msm_clocks[MSM_CLOCK_GPT]; - return msm_read_timer_count(clock) + clock->offset; + if (clock->stopped) + return clock->stopped_tick; + else + return msm_read_timer_count(clock) + clock->offset; } static cycle_t msm_dgt_read(struct clocksource *cs) { struct msm_clock *clock = &msm_clocks[MSM_CLOCK_DGT]; + if (clock->stopped) + return clock->stopped_tick; return (msm_read_timer_count(clock) + clock->offset) >> MSM_DGT_SHIFT; } @@ -165,12 +172,18 @@ static void msm_timer_set_mode(enum clock_event_mode mode, struct clock_event_device *evt) { struct msm_clock *clock; + unsigned long irq_flags; + clock = container_of(evt, struct msm_clock, clockevent); + local_irq_save(irq_flags); + switch (mode) { case CLOCK_EVT_MODE_RESUME: case CLOCK_EVT_MODE_PERIODIC: break; case CLOCK_EVT_MODE_ONESHOT: + clock->stopped = 0; + clock->offset = -msm_read_timer_count(clock) + clock->stopped_tick; msm_active_clock = clock; writel(TIMER_ENABLE_EN, clock->regbase + TIMER_ENABLE); break; @@ -178,9 +191,13 @@ static void msm_timer_set_mode(enum clock_event_mode mode, case CLOCK_EVT_MODE_SHUTDOWN: msm_active_clock = NULL; clock->smem_in_sync = 0; + clock->stopped = 1; + clock->stopped_tick = (msm_read_timer_count(clock) + + clock->offset) >> clock->shift; writel(0, clock->regbase + TIMER_ENABLE); break; } + local_irq_restore(irq_flags); } static inline int check_timeout(struct msm_clock *clock, uint32_t timeout) @@ -296,6 +313,8 @@ int64_t msm_timer_enter_idle(void) msm_timer_sync_smem_clock(0); count = msm_read_timer_count(clock); + if (clock->stopped++ == 0) + clock->stopped_tick = (count + clock->offset) >> clock->shift; alarm = readl(clock->regbase + TIMER_MATCH_VAL); delta = alarm - count; if (delta <= -(int32_t)((clock->freq << clock->shift) >> 10)) { @@ -314,14 +333,17 @@ void msm_timer_exit_idle(int low_power) struct msm_clock *clock = msm_active_clock; uint32_t smem_clock; - if (!low_power || clock != &msm_clocks[MSM_CLOCK_GPT]) + if (clock != &msm_clocks[MSM_CLOCK_GPT]) return; - if (!(readl(clock->regbase + TIMER_ENABLE) & TIMER_ENABLE_EN)) { - writel(TIMER_ENABLE_EN, clock->regbase + TIMER_ENABLE); - smem_clock = msm_timer_sync_smem_clock(1); + if (low_power) { + if (!(readl(clock->regbase + TIMER_ENABLE) & TIMER_ENABLE_EN)) { + writel(TIMER_ENABLE_EN, clock->regbase + TIMER_ENABLE); + smem_clock = msm_timer_sync_smem_clock(1); + } + msm_timer_reactivate_alarm(clock); } - msm_timer_reactivate_alarm(clock); + clock->stopped--; } unsigned long long sched_clock(void) -- cgit v1.2.3 From 9644b17341747a1ad80bdbf34a0e90df29097c50 Mon Sep 17 00:00:00 2001 From: Arve Hjønnevåg Date: Wed, 10 Dec 2008 16:01:22 -0800 Subject: [ARM] msm: Don't call ktime_get from sched_clock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With some kernel debug options sched_clock gets called with xtime_lock locked for write resulting in a deadlock. Signed-off-by: Arve Hjønnevåg --- arch/arm/mach-msm/timer.c | 41 ++++++++++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 7 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c index ce9af73ad379..a78e7484cb8b 100644 --- a/arch/arm/mach-msm/timer.c +++ b/arch/arm/mach-msm/timer.c @@ -49,8 +49,6 @@ module_param_named(debug_mask, msm_timer_debug_mask, int, S_IRUGO | S_IWUSR | S_ #define GPT_HZ 32768 #define DGT_HZ 19200000 /* 19.2 MHz or 600 KHz after shift */ -static int msm_timer_ready; - enum { MSM_CLOCK_FLAGS_UNSTABLE_COUNT = 1U << 0, MSM_CLOCK_FLAGS_ODD_MATCH_WRITE = 1U << 1, @@ -348,10 +346,40 @@ void msm_timer_exit_idle(int low_power) unsigned long long sched_clock(void) { - if (msm_timer_ready) - return ktime_to_ns(ktime_get()); - else - return 0; + static cycle_t saved_ticks; + static int saved_ticks_valid; + static unsigned long long base; + static unsigned long long last_result; + + unsigned long irq_flags; + static cycle_t last_ticks; + cycle_t ticks; + static unsigned long long result; + struct clocksource *cs; + struct msm_clock *clock = msm_active_clock; + + local_irq_save(irq_flags); + if (clock) { + cs = &clock->clocksource; + + last_ticks = saved_ticks; + saved_ticks = ticks = cs->read(); + if (!saved_ticks_valid) { + saved_ticks_valid = 1; + last_ticks = ticks; + base -= cyc2ns(cs, ticks); + } + if (ticks < last_ticks) { + base += cyc2ns(cs, cs->mask); + base += cyc2ns(cs, 1); + } + last_result = result = cyc2ns(cs, ticks) + base; + } else { + base = result = last_result; + saved_ticks_valid = 0; + } + local_irq_restore(irq_flags); + return result; } #ifdef CONFIG_MSM7X00A_USE_GP_TIMER @@ -460,7 +488,6 @@ static void __init msm_timer_init(void) "failed for %s\n", cs->name); clockevents_register_device(ce); - msm_timer_ready = 1; } } -- cgit v1.2.3 From 2748088f7ac8dd3e720b62f2cd6e8bde412897b0 Mon Sep 17 00:00:00 2001 From: Ben Cheng Date: Fri, 6 Feb 2009 16:10:34 -0800 Subject: [ARM] msm: oprofile: Enable OProfile and preserve performance counters. Signed-off-by: Ben Cheng --- arch/arm/mach-msm/idle.S | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/idle.S b/arch/arm/mach-msm/idle.S index 588eb072da82..d4c3e8174731 100644 --- a/arch/arm/mach-msm/idle.S +++ b/arch/arm/mach-msm/idle.S @@ -27,6 +27,13 @@ ENTRY(msm_pm_collapse) mrc p15, 0, r3, c3, c0, 0 /* dacr */ mrc p15, 0, ip, c13, c0, 1 /* context ID */ stmia r0!, {r1-r3, ip} +#if defined(CONFIG_OPROFILE) + mrc p15, 0, r1, c15, c12, 0 /* pmnc */ + mrc p15, 0, r2, c15, c12, 1 /* ccnt */ + mrc p15, 0, r3, c15, c12, 2 /* pmn0 */ + mrc p15, 0, ip, c15, c12, 3 /* pmn1 */ + stmia r0!, {r1-r3, ip} +#endif /* fall though */ ENTRY(msm_arch_idle) #if defined(CONFIG_MSM_FIQ_SUPPORT) @@ -63,6 +70,13 @@ ENTRY(msm_pm_collapse_exit) adr r3, msm_pm_collapse_exit add r1, r1, r3 sub r1, r1, r2 +#if defined(CONFIG_OPROFILE) + ldmdb r1!, {r2-r5} + mcr p15, 0, r3, c15, c12, 1 /* ccnt */ + mcr p15, 0, r4, c15, c12, 2 /* pmn0 */ + mcr p15, 0, r5, c15, c12, 3 /* pmn1 */ + mcr p15, 0, r2, c15, c12, 0 /* pmnc */ +#endif ldmdb r1!, {r2-r5} mcr p15, 0, r4, c3, c0, 0 /* dacr */ mcr p15, 0, r3, c2, c0, 0 /* ttb */ @@ -84,6 +98,9 @@ ENTRY(msm_pm_collapse_exit) saved_state: .space 4 * 11 /* r4-14 */ - .space 4 * 4 /* cp15 */ + .space 4 * 4 /* cp15 - MMU control, ttb, dacr, context ID */ +#if defined(CONFIG_OPROFILE) + .space 4 * 4 /* more cp15 - pmnc, ccnt, pmn0, pmn1 */ +#endif saved_state_end: -- cgit v1.2.3 From 17881f13a17fb5268b322d648240a8149bf85485 Mon Sep 17 00:00:00 2001 From: Mike Chan Date: Thu, 12 Feb 2009 18:24:11 -0800 Subject: [ARM] msm: trout: Fix touchscreen power on/off sequence. Level shifter gpio was not set to be an output. Signed-off-by: Mike Chan --- arch/arm/mach-msm/board-trout.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/board-trout.c b/arch/arm/mach-msm/board-trout.c index 781fa3c42ccd..1b0e8b908672 100644 --- a/arch/arm/mach-msm/board-trout.c +++ b/arch/arm/mach-msm/board-trout.c @@ -230,6 +230,7 @@ static int trout_ts_power(int on) } else { gpio_set_value(tp_ls_gpio, 0); + udelay(50); gpio_set_value(TROUT_GPIO_TP_EN, 0); gpio_set_value(TROUT_GPIO_TP_I2C_PULL, 0); } @@ -798,6 +799,9 @@ static void __init trout_init(void) msm_hw_reset_hook = trout_reset; + gpio_direction_output(system_rev < 5 ? + TROUT_4_TP_LS_EN : TROUT_5_TP_LS_EN, 0); + msm_acpu_clock_init(&trout_clock_data); #if defined(CONFIG_MSM_SERIAL_DEBUGGER) -- cgit v1.2.3 From d2d5ca256b9660bfac75bb5b9f219413ddd91766 Mon Sep 17 00:00:00 2001 From: Thomas Tsai Date: Tue, 17 Feb 2009 14:00:09 -0800 Subject: [ARM] msm: htc_headset: Import new headset driver from HTC Signed-off-by: San Mehat --- arch/arm/mach-msm/htc_headset.c | 1246 ++++++++++++++++++++++++++ arch/arm/mach-msm/include/mach/htc_headset.h | 173 ++++ 2 files changed, 1419 insertions(+) create mode 100644 arch/arm/mach-msm/htc_headset.c create mode 100644 arch/arm/mach-msm/include/mach/htc_headset.h (limited to 'arch') diff --git a/arch/arm/mach-msm/htc_headset.c b/arch/arm/mach-msm/htc_headset.c new file mode 100644 index 000000000000..a69a2e1ca5f8 --- /dev/null +++ b/arch/arm/mach-msm/htc_headset.c @@ -0,0 +1,1246 @@ +/* + * H2W device detection driver. + * + * Copyright (C) 2008 Google, Inc. + * Copyright (C) 2008 HTC, Inc. + * + * Authors: + * Laurence Chen + * Nick Pelly + * Thomas Tsai + * Farmer Tseng + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + */ + +/* For detecting HTC 2 Wire devices, such as wired headset. + + Logically, the H2W driver is always present, and H2W state (hi->state) + indicates what is currently plugged into the H2W interface. + + When the headset is plugged in, CABLE_IN1 is pulled low. When the headset + button is pressed, CABLE_IN2 is pulled low. These two lines are shared with + the TX and RX (respectively) of UART3 - used for serial debugging. + + This headset driver keeps the CPLD configured as UART3 for as long as + possible, so that we can do serial FIQ debugging even when the kernel is + locked and this driver no longer runs. So it only configures the CPLD to + GPIO while the headset is plugged in, and for 10ms during detection work. + + Unfortunately we can't leave the CPLD as UART3 while a headset is plugged + in, UART3 is pullup on TX but the headset is pull-down, causing a 55 mA + drain on trout. + + The headset detection work involves setting CPLD to GPIO, and then pulling + CABLE_IN1 high with a stronger pullup than usual. A H2W headset will still + pull this line low, whereas other attachments such as a serial console + would get pulled up by this stronger pullup. + + Headset insertion/removal causes UEvent's to be sent, and + /sys/class/switch/h2w/state to be updated. + + Button presses are interpreted as input event (KEY_MEDIA). Button presses + are ignored if the headset is plugged in, so the buttons on 11 pin -> 3.5mm + jack adapters do not work until a headset is plugged into the adapter. This + is to avoid serial RX traffic causing spurious button press events. + + We tend to check the status of CABLE_IN1 a few more times than strictly + necessary during headset detection, to avoid spurious headset insertion + events caused by serial debugger TX traffic. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define H2WI(fmt, arg...) \ + printk(KERN_INFO "[H2W] %s " fmt "\r\n", __func__, ## arg) +#define H2WE(fmt, arg...) \ + printk(KERN_ERR "[H2W] %s " fmt "\r\n", __func__, ## arg) + +#ifdef CONFIG_DEBUG_H2W +#define H2W_DBG(fmt, arg...) printk(KERN_INFO "[H2W] %s " fmt "\r\n", __func__, ## arg) +#else +#define H2W_DBG(fmt, arg...) do {} while (0) +#endif + +static struct workqueue_struct *g_detection_work_queue; +static void detection_work(struct work_struct *work); +static DECLARE_WORK(g_detection_work, detection_work); + +struct h2w_info { + struct switch_dev sdev; + struct input_dev *input; + struct mutex mutex_lock; + + atomic_t btn_state; + int ignore_btn; + + unsigned int irq; + unsigned int irq_btn; + + int cable_in1; + int cable_in2; + int h2w_clk; + int h2w_data; + int debug_uart; + + void (*config_cpld) (int); + void (*init_cpld) (void); + /* for h2w */ + void (*set_dat)(int); + void (*set_clk)(int); + void (*set_dat_dir)(int); + void (*set_clk_dir)(int); + int (*get_dat)(void); + int (*get_clk)(void); + + int htc_headset_flag; + + struct hrtimer timer; + ktime_t debounce_time; + + struct hrtimer btn_timer; + ktime_t btn_debounce_time; + + H2W_INFO h2w_info; + H2W_SPEED speed; + struct vreg *vreg_h2w; +}; +static struct h2w_info *hi; + +static ssize_t h2w_print_name(struct switch_dev *sdev, char *buf) +{ + switch (switch_get_state(&hi->sdev)) { + case H2W_NO_DEVICE: + return sprintf(buf, "No Device\n"); + case H2W_HTC_HEADSET: + return sprintf(buf, "Headset\n"); + } + return -EINVAL; +} + +static void button_pressed(void) +{ + H2W_DBG("button_pressed \n"); + atomic_set(&hi->btn_state, 1); + input_report_key(hi->input, KEY_MEDIA, 1); + input_sync(hi->input); +} + +static void button_released(void) +{ + H2W_DBG("button_released \n"); + atomic_set(&hi->btn_state, 0); + input_report_key(hi->input, KEY_MEDIA, 0); + input_sync(hi->input); +} + +/***************** + * H2W proctocol * + *****************/ +static inline void h2w_begin_command(void) +{ + /* Disable H2W interrupt */ + set_irq_type(hi->irq_btn, IRQF_TRIGGER_HIGH); + disable_irq(hi->irq); + disable_irq(hi->irq_btn); + + /* Set H2W_CLK as output low */ + hi->set_clk(0); + hi->set_clk_dir(1); +} + +static inline void h2w_end_command(void) +{ + /* Set H2W_CLK as input */ + hi->set_clk_dir(0); + + /* Enable H2W interrupt */ + enable_irq(hi->irq); + enable_irq(hi->irq_btn); + set_irq_type(hi->irq_btn, IRQF_TRIGGER_RISING); +} + +/* + * One bit write data + * ________ + * SCLK O ______| |______O(L) + * + * + * SDAT I + */ +static inline void one_clock_write(unsigned short flag) +{ + if (flag) + hi->set_dat(1); + else + hi->set_dat(0); + + udelay(hi->speed); + hi->set_clk(1); + udelay(hi->speed); + hi->set_clk(0); +} + +/* + * One bit write data R/W bit + * ________ + * SCLK ______| |______O(L) + * 1----> 1-----> + * 2-------> ______ + * SDAT I + * O(H/L) + */ +static inline void one_clock_write_RWbit(unsigned short flag) +{ + if (flag) + hi->set_dat(1); + else + hi->set_dat(0); + + udelay(hi->speed); + hi->set_clk(1); + udelay(hi->speed); + hi->set_clk(0); + hi->set_dat_dir(0); + udelay(hi->speed); +} + +/* + * H2W Reset + * ___________ + * SCLK O(L)______| |___O(L) + * 1----> + * 4-->1-->1-->1us--> + * ____ + * SDAT O(L)________ | |_______O(L) + * + * H2w reset command needs to be issued before every access + */ +static inline void h2w_reset(void) +{ + /* Set H2W_DAT as output low */ + hi->set_dat(0); + hi->set_dat_dir(1); + + udelay(hi->speed); + hi->set_clk(1); + udelay(4 * hi->speed); + hi->set_dat(1); + udelay(hi->speed); + hi->set_dat(0); + udelay(hi->speed); + hi->set_clk(0); + udelay(hi->speed); +} + +/* + * H2W Start + * ___________ + * SCLK O(L)______| |___O(L) + * 1----> + * 2----------->1--> + * + * SDAT O(L)______________________O(L) + */ +static inline void h2w_start(void) +{ + udelay(hi->speed); + hi->set_clk(1); + udelay(2 * hi->speed); + hi->set_clk(0); + udelay(hi->speed); +} + +/* + * H2W Ack + * __________ + * SCLK _____| |_______O(L) + * 1----> 1------> + * 2---------> + * ________________________ + * SDAT become Input mode here I + */ +static inline int h2w_ack(void) +{ + int retry_times = 0; + +ack_resend: + if (retry_times == MAX_ACK_RESEND_TIMES) + return -1; + + udelay(hi->speed); + hi->set_clk(1); + udelay(2 * hi->speed); + + if (!hi->get_dat()) { + retry_times++; + hi->set_clk(0); + udelay(hi->speed); + goto ack_resend; + } + + hi->set_clk(0); + udelay(hi->speed); + return 0; +} + +/* + * One bit read data + * ________ + * SCLK ______| |______O(L) + * 2----> 2-----> + * 2-------> + * SDAT I + */ +static unsigned char h2w_readc(void) +{ + unsigned char h2w_read_data = 0x0; + int index; + + for (index = 0; index < 8; index++) { + hi->set_clk(0); + udelay(hi->speed); + hi->set_clk(1); + udelay(hi->speed); + if (hi->get_dat()) + h2w_read_data |= (1 << (7 - index)); + } + hi->set_clk(0); + udelay(hi->speed); + + return h2w_read_data; +} + +static int h2w_readc_cmd(H2W_ADDR address) +{ + int ret = -1, retry_times = 0; + unsigned char read_data; + +read_resend: + if (retry_times == MAX_HOST_RESEND_TIMES) + goto err_read; + + h2w_reset(); + h2w_start(); + /* Write address */ + one_clock_write(address & 0x1000); + one_clock_write(address & 0x0800); + one_clock_write(address & 0x0400); + one_clock_write(address & 0x0200); + one_clock_write(address & 0x0100); + one_clock_write(address & 0x0080); + one_clock_write(address & 0x0040); + one_clock_write(address & 0x0020); + one_clock_write(address & 0x0010); + one_clock_write(address & 0x0008); + one_clock_write(address & 0x0004); + one_clock_write(address & 0x0002); + one_clock_write(address & 0x0001); + one_clock_write_RWbit(1); + if (h2w_ack() < 0) { + H2W_DBG("Addr NO ACK(%d).\n", retry_times); + retry_times++; + hi->set_clk(0); + mdelay(RESEND_DELAY); + goto read_resend; + } + + read_data = h2w_readc(); + + if (h2w_ack() < 0) { + H2W_DBG("Data NO ACK(%d).\n", retry_times); + retry_times++; + hi->set_clk(0); + mdelay(RESEND_DELAY); + goto read_resend; + } + ret = (int)read_data; + +err_read: + if (ret < 0) + H2WE("NO ACK.\n"); + + return ret; +} + +static int h2w_writec_cmd(H2W_ADDR address, unsigned char data) +{ + int ret = -1; + int retry_times = 0; + +write_resend: + if (retry_times == MAX_HOST_RESEND_TIMES) + goto err_write; + + h2w_reset(); + h2w_start(); + + /* Write address */ + one_clock_write(address & 0x1000); + one_clock_write(address & 0x0800); + one_clock_write(address & 0x0400); + one_clock_write(address & 0x0200); + one_clock_write(address & 0x0100); + one_clock_write(address & 0x0080); + one_clock_write(address & 0x0040); + one_clock_write(address & 0x0020); + one_clock_write(address & 0x0010); + one_clock_write(address & 0x0008); + one_clock_write(address & 0x0004); + one_clock_write(address & 0x0002); + one_clock_write(address & 0x0001); + one_clock_write_RWbit(0); + if (h2w_ack() < 0) { + H2W_DBG("Addr NO ACK(%d).\n", retry_times); + retry_times++; + hi->set_clk(0); + mdelay(RESEND_DELAY); + goto write_resend; + } + + /* Write data */ + hi->set_dat_dir(1); + one_clock_write(data & 0x0080); + one_clock_write(data & 0x0040); + one_clock_write(data & 0x0020); + one_clock_write(data & 0x0010); + one_clock_write(data & 0x0008); + one_clock_write(data & 0x0004); + one_clock_write(data & 0x0002); + one_clock_write_RWbit(data & 0x0001); + if (h2w_ack() < 0) { + H2W_DBG("Data NO ACK(%d).\n", retry_times); + retry_times++; + hi->set_clk(0); + mdelay(RESEND_DELAY); + goto write_resend; + } + ret = 0; + +err_write: + if (ret < 0) + H2WE("NO ACK.\n"); + + return ret; +} + +static int h2w_get_fnkey(void) +{ + int ret; + h2w_begin_command(); + ret = h2w_readc_cmd(H2W_FNKEY_UPDOWN); + h2w_end_command(); + return ret; +} + +static int h2w_dev_init(H2W_INFO *ph2w_info) +{ + int ret = -1; + unsigned char ascr0 = 0; + int h2w_sys = 0, maxgpadd = 0, maxadd = 0, key = 0; + + hi->speed = H2W_50KHz; + h2w_begin_command(); + + /* read H2W_SYSTEM */ + h2w_sys = h2w_readc_cmd(H2W_SYSTEM); + if (h2w_sys == -1) { + H2WE("read H2W_SYSTEM(0x0000) failed.\n"); + goto err_plugin; + } + ph2w_info->ACC_CLASS = (h2w_sys & 0x03); + ph2w_info->AUDIO_DEVICE = (h2w_sys & 0x04) > 0 ? 1 : 0; + ph2w_info->HW_REV = (h2w_sys & 0x18) >> 3; + ph2w_info->SLEEP_PR = (h2w_sys & 0x20) >> 5; + ph2w_info->CLK_SP = (h2w_sys & 0xC0) >> 6; + + /* enter init mode */ + if (h2w_writec_cmd(H2W_ASCR0, H2W_ASCR_DEVICE_INI) < 0) { + H2WE("write H2W_ASCR0(0x0002) failed.\n"); + goto err_plugin; + } + udelay(10); + + /* read H2W_MAX_GP_ADD */ + maxgpadd = h2w_readc_cmd(H2W_MAX_GP_ADD); + if (maxgpadd == -1) { + H2WE("write H2W_MAX_GP_ADD(0x0001) failed.\n"); + goto err_plugin; + } + ph2w_info->CLK_SP += (maxgpadd & 0x60) >> 3; + ph2w_info->MAX_GP_ADD = (maxgpadd & 0x1F); + + /* read key group */ + if (ph2w_info->MAX_GP_ADD >= 1) { + ph2w_info->KEY_MAXADD = h2w_readc_cmd(H2W_KEY_MAXADD); + if (ph2w_info->KEY_MAXADD == -1) + goto err_plugin; + if (ph2w_info->KEY_MAXADD >= 1) { + key = h2w_readc_cmd(H2W_ASCII_DOWN); + if (key < 0) + goto err_plugin; + ph2w_info->ASCII_DOWN = (key == 0xFF) ? 1 : 0; + } + if (ph2w_info->KEY_MAXADD >= 2) { + key = h2w_readc_cmd(H2W_ASCII_UP); + if (key == -1) + goto err_plugin; + ph2w_info->ASCII_UP = (key == 0xFF) ? 1 : 0; + } + if (ph2w_info->KEY_MAXADD >= 3) { + key = h2w_readc_cmd(H2W_FNKEY_UPDOWN); + if (key == -1) + goto err_plugin; + ph2w_info->FNKEY_UPDOWN = (key == 0xFF) ? 1 : 0; + } + if (ph2w_info->KEY_MAXADD >= 4) { + key = h2w_readc_cmd(H2W_KD_STATUS); + if (key == -1) + goto err_plugin; + ph2w_info->KD_STATUS = (key == 0x01) ? 1 : 0; + } + } + + /* read led group */ + if (ph2w_info->MAX_GP_ADD >= 2) { + ph2w_info->LED_MAXADD = h2w_readc_cmd(H2W_LED_MAXADD); + if (ph2w_info->LED_MAXADD == -1) + goto err_plugin; + if (ph2w_info->LED_MAXADD >= 1) { + key = h2w_readc_cmd(H2W_LEDCT0); + if (key == -1) + goto err_plugin; + ph2w_info->LEDCT0 = (key == 0x02) ? 1 : 0; + } + } + + /* read group 3, 4, 5 */ + if (ph2w_info->MAX_GP_ADD >= 3) { + maxadd = h2w_readc_cmd(H2W_CRDL_MAXADD); + if (maxadd == -1) + goto err_plugin; + } + if (ph2w_info->MAX_GP_ADD >= 4) { + maxadd = h2w_readc_cmd(H2W_CARKIT_MAXADD); + if (maxadd == -1) + goto err_plugin; + } + if (ph2w_info->MAX_GP_ADD >= 5) { + maxadd = h2w_readc_cmd(H2W_USBHOST_MAXADD); + if (maxadd == -1) + goto err_plugin; + } + + /* read medical group */ + if (ph2w_info->MAX_GP_ADD >= 6) { + ph2w_info->MED_MAXADD = h2w_readc_cmd(H2W_MED_MAXADD); + if (ph2w_info->MED_MAXADD == -1) + goto err_plugin; + if (ph2w_info->MED_MAXADD >= 1) { + key = h2w_readc_cmd(H2W_MED_CONTROL); + if (key == -1) + goto err_plugin; + ph2w_info->DATA_EN = (key & 0x01); + ph2w_info->AP_EN = (key & 0x02) >> 1; + ph2w_info->AP_ID = (key & 0x1c) >> 2; + } + if (ph2w_info->MED_MAXADD >= 2) { + key = h2w_readc_cmd(H2W_MED_IN_DATA); + if (key == -1) + goto err_plugin; + } + } + + if (ph2w_info->AUDIO_DEVICE) + ascr0 = H2W_ASCR_AUDIO_IN | H2W_ASCR_ACT_EN; + else + ascr0 = H2W_ASCR_ACT_EN; + + if (h2w_writec_cmd(H2W_ASCR0, ascr0) < 0) + goto err_plugin; + udelay(10); + + ret = 0; + + /* adjust speed */ + if (ph2w_info->MAX_GP_ADD == 2) { + /* Remote control */ + hi->speed = H2W_250KHz; + } else if (ph2w_info->MAX_GP_ADD == 6) { + if (ph2w_info->MED_MAXADD >= 1) { + key = h2w_readc_cmd(H2W_MED_CONTROL); + if (key == -1) + goto err_plugin; + ph2w_info->DATA_EN = (key & 0x01); + ph2w_info->AP_EN = (key & 0x02) >> 1; + ph2w_info->AP_ID = (key & 0x1c) >> 2; + } + } + +err_plugin: + h2w_end_command(); + + return ret; +} + +static inline void h2w_dev_power_on(int on) +{ + if (!hi->vreg_h2w) + return; + + if (on) + vreg_enable(hi->vreg_h2w); + else + vreg_disable(hi->vreg_h2w); +} + +static int h2w_dev_detect(void) +{ + int ret = -1; + int retry_times; + + for (retry_times = 5; retry_times; retry_times--) { + /* Enable H2W Power */ + h2w_dev_power_on(1); + msleep(100); + memset(&hi->h2w_info, 0, sizeof(H2W_INFO)); + if (h2w_dev_init(&hi->h2w_info) < 0) { + h2w_dev_power_on(0); + msleep(100); + } else if (hi->h2w_info.MAX_GP_ADD == 2) { + ret = 0; + break; + } else { + printk(KERN_INFO "h2w_detect: detect error(%d)\n" + , hi->h2w_info.MAX_GP_ADD); + h2w_dev_power_on(0); + msleep(100); + } + printk(KERN_INFO "h2w_detect(%d)\n" + , hi->h2w_info.MAX_GP_ADD); + } + H2W_DBG("h2w_detect:(%d)\n", retry_times); + return ret; +} + +static void remove_headset(void) +{ + unsigned long irq_flags; + + H2W_DBG(""); + + mutex_lock(&hi->mutex_lock); + switch_set_state(&hi->sdev, switch_get_state(&hi->sdev) & + ~(BIT_HEADSET | BIT_HEADSET_NO_MIC)); + mutex_unlock(&hi->mutex_lock); + hi->init_cpld(); + + /* Disable button */ + switch (hi->htc_headset_flag) { + case H2W_HTC_HEADSET: + local_irq_save(irq_flags); + disable_irq(hi->irq_btn); + local_irq_restore(irq_flags); + + if (atomic_read(&hi->btn_state)) + button_released(); + break; + case H2W_DEVICE: + h2w_dev_power_on(0); + set_irq_type(hi->irq_btn, IRQF_TRIGGER_LOW); + disable_irq(hi->irq_btn); + /* 10ms (5-15 with 10ms tick) */ + hi->btn_debounce_time = ktime_set(0, 10000000); + hi->set_clk_dir(0); + hi->set_dat_dir(0); + break; + } + + hi->htc_headset_flag = 0; + hi->debounce_time = ktime_set(0, 100000000); /* 100 ms */ + +} + +#ifdef CONFIG_MSM_SERIAL_DEBUGGER +extern void msm_serial_debug_enable(int); +#endif + +static void insert_headset(int type) +{ + unsigned long irq_flags; + int state; + + H2W_DBG(""); + + hi->htc_headset_flag = type; + state = BIT_HEADSET | BIT_HEADSET_NO_MIC; + + state = switch_get_state(&hi->sdev); + state &= ~(BIT_HEADSET_NO_MIC | BIT_HEADSET); + switch (type) { + case H2W_HTC_HEADSET: + printk(KERN_INFO "insert_headset H2W_HTC_HEADSET\n"); + state |= BIT_HEADSET; + hi->ignore_btn = !gpio_get_value(hi->cable_in2); + /* Enable button irq */ + local_irq_save(irq_flags); + enable_irq(hi->irq_btn); + local_irq_restore(irq_flags); + hi->debounce_time = ktime_set(0, 200000000); /* 20 ms */ + break; + case H2W_DEVICE: + if (h2w_dev_detect() < 0) { + printk(KERN_INFO "H2W_DEVICE -- Non detect\n"); + remove_headset(); + } else { + printk(KERN_INFO "H2W_DEVICE -- detect\n"); + hi->btn_debounce_time = ktime_set(0, 0); + local_irq_save(irq_flags); + enable_irq(hi->irq_btn); + set_irq_type(hi->irq_btn, IRQF_TRIGGER_RISING); + local_irq_restore(irq_flags); + state |= BIT_HEADSET; + } + break; + case H2W_USB_CRADLE: + state |= BIT_HEADSET_NO_MIC; + break; + case H2W_UART_DEBUG: + hi->config_cpld(hi->debug_uart); + printk(KERN_INFO "switch to H2W_UART_DEBUG\n"); + default: + return; + } + mutex_lock(&hi->mutex_lock); + switch_set_state(&hi->sdev, state); + mutex_unlock(&hi->mutex_lock); + +#ifdef CONFIG_MSM_SERIAL_DEBUGGER + msm_serial_debug_enable(false); +#endif + +} +#if 0 +static void remove_headset(void) +{ + unsigned long irq_flags; + + H2W_DBG(""); + + switch_set_state(&hi->sdev, H2W_NO_DEVICE); + + hi->init_cpld(); + + /* Disable button */ + local_irq_save(irq_flags); + disable_irq(hi->irq_btn); + local_irq_restore(irq_flags); + + if (atomic_read(&hi->btn_state)) + button_released(); + + hi->debounce_time = ktime_set(0, 100000000); /* 100 ms */ +} +#endif +static int is_accessary_pluged_in(void) +{ + int type = 0; + int clk1 = 0, dat1 = 0, clk2 = 0, dat2 = 0, clk3 = 0, dat3 = 0; + + /* Step1: save H2W_CLK and H2W_DAT */ + /* Delay 10ms for pin stable. */ + msleep(10); + clk1 = gpio_get_value(hi->h2w_clk); + dat1 = gpio_get_value(hi->h2w_data); + + /* + * Step2: set GPIO_CABLE_IN1 as output high and GPIO_CABLE_IN2 as + * input + */ + gpio_direction_output(hi->cable_in1, 1); + gpio_direction_input(hi->cable_in2); + /* Delay 10ms for pin stable. */ + msleep(10); + /* Step 3: save H2W_CLK and H2W_DAT */ + clk2 = gpio_get_value(hi->h2w_clk); + dat2 = gpio_get_value(hi->h2w_data); + + /* + * Step 4: set GPIO_CABLE_IN1 as input and GPIO_CABLE_IN2 as output + * high + */ + gpio_direction_input(hi->cable_in1); + gpio_direction_output(hi->cable_in2, 1); + /* Delay 10ms for pin stable. */ + msleep(10); + /* Step 5: save H2W_CLK and H2W_DAT */ + clk3 = gpio_get_value(hi->h2w_clk); + dat3 = gpio_get_value(hi->h2w_data); + + /* Step 6: set both GPIO_CABLE_IN1 and GPIO_CABLE_IN2 as input */ + gpio_direction_input(hi->cable_in1); + gpio_direction_input(hi->cable_in2); + + H2W_DBG("(%d,%d) (%d,%d) (%d,%d)\n", + clk1, dat1, clk2, dat2, clk3, dat3); + + if ((clk1 == 0) && (dat1 == 1) && + (clk2 == 0) && (dat2 == 1) && + (clk3 == 0) && (dat3 == 1)) + type = H2W_HTC_HEADSET; + else if ((clk1 == 0) && (dat1 == 0) && + (clk2 == 0) && (dat2 == 0) && + (clk3 == 0) && (dat3 == 0)) + type = NORMAL_HEARPHONE; + else if ((clk1 == 0) && (dat1 == 0) && + (clk2 == 1) && (dat2 == 0) && + (clk3 == 0) && (dat3 == 1)) + type = H2W_DEVICE; + else if ((clk1 == 0) && (dat1 == 0) && + (clk2 == 1) && (dat2 == 1) && + (clk3 == 1) && (dat3 == 1)) + type = H2W_USB_CRADLE; + else if ((clk1 == 0) && (dat1 == 1) && + (clk2 == 1) && (dat2 == 1) && + (clk3 == 0) && (dat3 == 1)) + type = H2W_UART_DEBUG; + else + type = H2W_NO_DEVICE; + + return type; +} + + +static void detection_work(struct work_struct *work) +{ + unsigned long irq_flags; + int type; + + H2W_DBG(""); + + if (gpio_get_value(hi->cable_in1) != 0) { + /* Headset not plugged in */ + if (switch_get_state(&hi->sdev) != H2W_NO_DEVICE) + remove_headset(); + return; + } + + /* Something plugged in, lets make sure its a headset */ + + /* Switch CPLD to GPIO to do detection */ + hi->config_cpld(H2W_GPIO); + + /* Disable headset interrupt while detecting.*/ + local_irq_save(irq_flags); + disable_irq(hi->irq); + local_irq_restore(irq_flags); + + /* Something plugged in, lets make sure its a headset */ + type = is_accessary_pluged_in(); + + /* Restore IRQs */ + local_irq_save(irq_flags); + enable_irq(hi->irq); + local_irq_restore(irq_flags); + + insert_headset(type); +} + +static enum hrtimer_restart button_event_timer_func(struct hrtimer *data) +{ + int key, press, keyname, h2w_key = 1; + + H2W_DBG(""); + + if (switch_get_state(&hi->sdev) == H2W_HTC_HEADSET) { + switch (hi->htc_headset_flag) { + case H2W_HTC_HEADSET: + if (gpio_get_value(hi->cable_in2)) { + if (hi->ignore_btn) + hi->ignore_btn = 0; + else if (atomic_read(&hi->btn_state)) + button_released(); + } else { + if (!hi->ignore_btn && + !atomic_read(&hi->btn_state)) + button_pressed(); + } + break; + case H2W_DEVICE: + if ((hi->get_dat() == 1) && (hi->get_clk() == 1)) { + /* Don't do anything because H2W pull out. */ + H2WE("Remote Control pull out.\n"); + } else { + key = h2w_get_fnkey(); + press = (key > 0x7F) ? 0 : 1; + keyname = key & 0x7F; + /* H2WI("key = %d, press = %d, + keyname = %d \n", + key, press, keyname); */ + switch (keyname) { + case H2W_KEY_PLAY: + H2WI("H2W_KEY_PLAY"); + key = KEY_PLAYPAUSE; + break; + case H2W_KEY_FORWARD: + H2WI("H2W_KEY_FORWARD"); + key = KEY_NEXTSONG; + break; + case H2W_KEY_BACKWARD: + H2WI("H2W_KEY_BACKWARD"); + key = KEY_PREVIOUSSONG; + break; + case H2W_KEY_VOLUP: + H2WI("H2W_KEY_VOLUP"); + key = KEY_VOLUMEUP; + break; + case H2W_KEY_VOLDOWN: + H2WI("H2W_KEY_VOLDOWN"); + key = KEY_VOLUMEDOWN; + break; + case H2W_KEY_PICKUP: + H2WI("H2W_KEY_PICKUP"); + key = KEY_SEND; + break; + case H2W_KEY_HANGUP: + H2WI("H2W_KEY_HANGUP"); + key = KEY_END; + break; + case H2W_KEY_MUTE: + H2WI("H2W_KEY_MUTE"); + key = KEY_MUTE; + break; + case H2W_KEY_HOLD: + H2WI("H2W_KEY_HOLD"); + break; + default: + H2WI("default"); + h2w_key = 0; + } + if (h2w_key) { + if (press) + H2WI("Press\n"); + else + H2WI("Release\n"); + input_report_key(hi->input, key, press); + } + } + break; + } /* end switch */ + } + + return HRTIMER_NORESTART; +} + +static enum hrtimer_restart detect_event_timer_func(struct hrtimer *data) +{ + H2W_DBG(""); + + queue_work(g_detection_work_queue, &g_detection_work); + return HRTIMER_NORESTART; +} + +static irqreturn_t detect_irq_handler(int irq, void *dev_id) +{ + int value1, value2; + int retry_limit = 10; + + H2W_DBG(""); + set_irq_type(hi->irq_btn, IRQF_TRIGGER_LOW); + do { + value1 = gpio_get_value(hi->cable_in1); + set_irq_type(hi->irq, value1 ? + IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH); + value2 = gpio_get_value(hi->cable_in1); + } while (value1 != value2 && retry_limit-- > 0); + + H2W_DBG("value2 = %d (%d retries), device=%d", + value2, (10-retry_limit), switch_get_state(&hi->sdev)); + + if ((switch_get_state(&hi->sdev) == H2W_NO_DEVICE) ^ value2) { + if (switch_get_state(&hi->sdev) == H2W_HTC_HEADSET) + hi->ignore_btn = 1; + /* Do the rest of the work in timer context */ + hrtimer_start(&hi->timer, hi->debounce_time, HRTIMER_MODE_REL); + } + + return IRQ_HANDLED; +} + +static irqreturn_t button_irq_handler(int irq, void *dev_id) +{ + int value1, value2; + int retry_limit = 10; + + H2W_DBG(""); + do { + value1 = gpio_get_value(hi->cable_in2); + if (hi->htc_headset_flag != H2W_DEVICE) + set_irq_type(hi->irq_btn, value1 ? + IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH); + value2 = gpio_get_value(hi->cable_in2); + } while (value1 != value2 && retry_limit-- > 0); + + H2W_DBG("value2 = %d (%d retries)", value2, (10-retry_limit)); + + hrtimer_start(&hi->btn_timer, hi->btn_debounce_time, HRTIMER_MODE_REL); + + return IRQ_HANDLED; +} + +#if defined(CONFIG_DEBUG_FS) +static int h2w_debug_set(void *data, u64 val) +{ + mutex_lock(&hi->mutex_lock); + switch_set_state(&hi->sdev, (int)val); + mutex_unlock(&hi->mutex_lock); + return 0; +} + +static int h2w_debug_get(void *data, u64 *val) +{ + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(h2w_debug_fops, h2w_debug_get, h2w_debug_set, "%llu\n"); +static int __init h2w_debug_init(void) +{ + struct dentry *dent; + + dent = debugfs_create_dir("h2w", 0); + if (IS_ERR(dent)) + return PTR_ERR(dent); + + debugfs_create_file("state", 0644, dent, NULL, &h2w_debug_fops); + + return 0; +} + +device_initcall(h2w_debug_init); +#endif + +static int h2w_probe(struct platform_device *pdev) +{ + int ret; + struct h2w_platform_data *pdata = pdev->dev.platform_data; + + printk(KERN_INFO "H2W: Registering H2W (headset) driver\n"); + hi = kzalloc(sizeof(struct h2w_info), GFP_KERNEL); + if (!hi) + return -ENOMEM; + + atomic_set(&hi->btn_state, 0); + hi->ignore_btn = 0; + + hi->debounce_time = ktime_set(0, 100000000); /* 100 ms */ + hi->btn_debounce_time = ktime_set(0, 10000000); /* 10 ms */ + + hi->htc_headset_flag = 0; + hi->cable_in1 = pdata->cable_in1; + hi->cable_in2 = pdata->cable_in2; + hi->h2w_clk = pdata->h2w_clk; + hi->h2w_data = pdata->h2w_data; + hi->debug_uart = pdata->debug_uart; + hi->config_cpld = pdata->config_cpld; + hi->init_cpld = pdata->init_cpld; + hi->set_dat = pdata->set_dat; + hi->set_clk = pdata->set_clk; + hi->set_dat_dir = pdata->set_dat_dir; + hi->set_clk_dir = pdata->set_clk_dir; + hi->get_dat = pdata->get_dat; + hi->get_clk = pdata->get_clk; + hi->speed = H2W_50KHz; + /* obtain needed VREGs */ + if (pdata->power_name) + hi->vreg_h2w = vreg_get(0, pdata->power_name); + + mutex_init(&hi->mutex_lock); + + hi->sdev.name = "h2w"; + hi->sdev.print_name = h2w_print_name; + + ret = switch_dev_register(&hi->sdev); + if (ret < 0) + goto err_switch_dev_register; + + g_detection_work_queue = create_workqueue("detection"); + if (g_detection_work_queue == NULL) { + ret = -ENOMEM; + goto err_create_work_queue; + } + + ret = gpio_request(hi->cable_in1, "h2w_detect"); + if (ret < 0) + goto err_request_detect_gpio; + + ret = gpio_request(hi->cable_in2, "h2w_button"); + if (ret < 0) + goto err_request_button_gpio; + + ret = gpio_direction_input(hi->cable_in1); + if (ret < 0) + goto err_set_detect_gpio; + + ret = gpio_direction_input(hi->cable_in2); + if (ret < 0) + goto err_set_button_gpio; + + hi->irq = gpio_to_irq(hi->cable_in1); + if (hi->irq < 0) { + ret = hi->irq; + goto err_get_h2w_detect_irq_num_failed; + } + + hi->irq_btn = gpio_to_irq(hi->cable_in2); + if (hi->irq_btn < 0) { + ret = hi->irq_btn; + goto err_get_button_irq_num_failed; + } + + /* Set CPLD MUX to H2W <-> CPLD GPIO */ + hi->init_cpld(); + + hrtimer_init(&hi->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + hi->timer.function = detect_event_timer_func; + hrtimer_init(&hi->btn_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + hi->btn_timer.function = button_event_timer_func; + + ret = request_irq(hi->irq, detect_irq_handler, + IRQF_TRIGGER_LOW, "h2w_detect", NULL); + if (ret < 0) + goto err_request_detect_irq; + + /* Disable button until plugged in */ + set_irq_flags(hi->irq_btn, IRQF_VALID | IRQF_NOAUTOEN); + ret = request_irq(hi->irq_btn, button_irq_handler, + IRQF_TRIGGER_LOW, "h2w_button", NULL); + if (ret < 0) + goto err_request_h2w_headset_button_irq; + + ret = set_irq_wake(hi->irq, 1); + if (ret < 0) + goto err_request_input_dev; + + ret = set_irq_wake(hi->irq_btn, 1); + if (ret < 0) + goto err_request_input_dev; + + + + hi->input = input_allocate_device(); + if (!hi->input) { + ret = -ENOMEM; + goto err_request_input_dev; + } + + hi->input->name = "h2w headset"; + set_bit(EV_SYN, hi->input->evbit); + set_bit(EV_KEY, hi->input->evbit); + set_bit(KEY_MEDIA, hi->input->keybit); + set_bit(KEY_NEXTSONG, hi->input->keybit); + set_bit(KEY_PLAYPAUSE, hi->input->keybit); + set_bit(KEY_PREVIOUSSONG, hi->input->keybit); + set_bit(KEY_MUTE, hi->input->keybit); + set_bit(KEY_VOLUMEUP, hi->input->keybit); + set_bit(KEY_VOLUMEDOWN, hi->input->keybit); + set_bit(KEY_END, hi->input->keybit); + set_bit(KEY_SEND, hi->input->keybit); + + ret = input_register_device(hi->input); + if (ret < 0) + goto err_register_input_dev; + + return 0; + +err_register_input_dev: + input_free_device(hi->input); +err_request_input_dev: + free_irq(hi->irq_btn, 0); +err_request_h2w_headset_button_irq: + free_irq(hi->irq, 0); +err_request_detect_irq: +err_get_button_irq_num_failed: +err_get_h2w_detect_irq_num_failed: +err_set_button_gpio: +err_set_detect_gpio: + gpio_free(hi->cable_in2); +err_request_button_gpio: + gpio_free(hi->cable_in1); +err_request_detect_gpio: + destroy_workqueue(g_detection_work_queue); +err_create_work_queue: + switch_dev_unregister(&hi->sdev); +err_switch_dev_register: + printk(KERN_ERR "H2W: Failed to register driver\n"); + + return ret; +} + +static int h2w_remove(struct platform_device *pdev) +{ + H2W_DBG(""); + if (switch_get_state(&hi->sdev)) + remove_headset(); + input_unregister_device(hi->input); + gpio_free(hi->cable_in2); + gpio_free(hi->cable_in1); + free_irq(hi->irq_btn, 0); + free_irq(hi->irq, 0); + destroy_workqueue(g_detection_work_queue); + switch_dev_unregister(&hi->sdev); + + return 0; +} + + +static struct platform_driver h2w_driver = { + .probe = h2w_probe, + .remove = h2w_remove, + .driver = { + .name = "h2w", + .owner = THIS_MODULE, + }, +}; + +static int __init h2w_init(void) +{ + H2W_DBG(""); + return platform_driver_register(&h2w_driver); +} + +static void __exit h2w_exit(void) +{ + platform_driver_unregister(&h2w_driver); +} + +module_init(h2w_init); +module_exit(h2w_exit); + +MODULE_AUTHOR("Laurence Chen "); +MODULE_DESCRIPTION("HTC 2 Wire detection driver"); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-msm/include/mach/htc_headset.h b/arch/arm/mach-msm/include/mach/htc_headset.h new file mode 100644 index 000000000000..2f4c18db2625 --- /dev/null +++ b/arch/arm/mach-msm/include/mach/htc_headset.h @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2008 HTC, Inc. + * Copyright (C) 2008 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#ifndef __ASM_ARCH_HTC_HEADSET_H +#define __ASM_ARCH_HTC_HEADSET_H + +struct h2w_platform_data { + char *power_name; + int cable_in1; + int cable_in2; + int h2w_clk; + int h2w_data; + int debug_uart; + void (*config_cpld)(int); + void (*init_cpld)(void); + void (*set_dat)(int); + void (*set_clk)(int); + void (*set_dat_dir)(int); + void (*set_clk_dir)(int); + int (*get_dat)(void); + int (*get_clk)(void); +}; + +#define BIT_HEADSET (1 << 0) +#define BIT_HEADSET_NO_MIC (1 << 1) +#define BIT_TTY (1 << 2) +#define BIT_FM_HEADSET (1 << 3) +#define BIT_FM_SPEAKER (1 << 4) + +enum { + H2W_NO_DEVICE = 0, + H2W_HTC_HEADSET = 1, +/* H2W_TTY_DEVICE = 2,*/ + NORMAL_HEARPHONE= 2, + H2W_DEVICE = 3, + H2W_USB_CRADLE = 4, + H2W_UART_DEBUG = 5, +}; + +enum { + H2W_GPIO = 0, + H2W_UART1 = 1, + H2W_UART3 = 2, + H2W_BT = 3 +}; + +#define RESEND_DELAY (3) /* ms */ +#define MAX_ACK_RESEND_TIMES (6) /* follow spec */ +#define MAX_HOST_RESEND_TIMES (3) /* follow spec */ +#define MAX_HYGEIA_RESEND_TIMES (5) + +#define H2W_ASCR_DEVICE_INI (0x01) +#define H2W_ASCR_ACT_EN (0x02) +#define H2W_ASCR_PHONE_IN (0x04) +#define H2W_ASCR_RESET (0x08) +#define H2W_ASCR_AUDIO_IN (0x10) + +#define H2W_LED_OFF (0x0) +#define H2W_LED_BKL (0x1) +#define H2W_LED_MTL (0x2) + +typedef enum { + /* === system group 0x0000~0x00FF === */ + /* (R) Accessory type register */ + H2W_SYSTEM = 0x0000, + /* (R) Maximum group address */ + H2W_MAX_GP_ADD = 0x0001, + /* (R/W) Accessory system control register0 */ + H2W_ASCR0 = 0x0002, + + /* === key group 0x0100~0x01FF === */ + /* (R) Key group maximum sub address */ + H2W_KEY_MAXADD = 0x0100, + /* (R) ASCII key press down flag */ + H2W_ASCII_DOWN = 0x0101, + /* (R) ASCII key release up flag */ + H2W_ASCII_UP = 0x0102, + /* (R) Function key status flag */ + H2W_FNKEY_UPDOWN = 0x0103, + /* (R/W) Key device status */ + H2W_KD_STATUS = 0x0104, + + /* === led group 0x0200~0x02FF === */ + /* (R) LED group maximum sub address */ + H2W_LED_MAXADD = 0x0200, + /* (R/W) LED control register0 */ + H2W_LEDCT0 = 0x0201, + + /* === crdl group 0x0300~0x03FF === */ + /* (R) Cardle group maximum sub address */ + H2W_CRDL_MAXADD = 0x0300, + /* (R/W) Cardle group function control register0 */ + H2W_CRDLCT0 = 0x0301, + + /* === car kit group 0x0400~0x04FF === */ + H2W_CARKIT_MAXADD = 0x0400, + + /* === usb host group 0x0500~0x05FF === */ + H2W_USBHOST_MAXADD = 0x0500, + + /* === medical group 0x0600~0x06FF === */ + H2W_MED_MAXADD = 0x0600, + H2W_MED_CONTROL = 0x0601, + H2W_MED_IN_DATA = 0x0602, +} H2W_ADDR; + + +typedef struct H2W_INFO { + /* system group */ + unsigned char CLK_SP; + int SLEEP_PR; + unsigned char HW_REV; + int AUDIO_DEVICE; + unsigned char ACC_CLASS; + unsigned char MAX_GP_ADD; + + /* key group */ + int KEY_MAXADD; + int ASCII_DOWN; + int ASCII_UP; + int FNKEY_UPDOWN; + int KD_STATUS; + + /* led group */ + int LED_MAXADD; + int LEDCT0; + + /* medical group */ + int MED_MAXADD; + unsigned char AP_ID; + unsigned char AP_EN; + unsigned char DATA_EN; +} H2W_INFO; + +typedef enum { + H2W_500KHz = 1, + H2W_250KHz = 2, + H2W_166KHz = 3, + H2W_125KHz = 4, + H2W_100KHz = 5, + H2W_83KHz = 6, + H2W_71KHz = 7, + H2W_62KHz = 8, + H2W_55KHz = 9, + H2W_50KHz = 10, +} H2W_SPEED; + +typedef enum { + H2W_KEY_INVALID = -1, + H2W_KEY_PLAY = 0, + H2W_KEY_FORWARD = 1, + H2W_KEY_BACKWARD = 2, + H2W_KEY_VOLUP = 3, + H2W_KEY_VOLDOWN = 4, + H2W_KEY_PICKUP = 5, + H2W_KEY_HANGUP = 6, + H2W_KEY_MUTE = 7, + H2W_KEY_HOLD = 8, + H2W_NUM_KEYFUNC = 9, +} KEYFUNC; +#endif -- cgit v1.2.3 From d9cced0ec3acf254abfcc646f266470d44d3f439 Mon Sep 17 00:00:00 2001 From: San Mehat Date: Tue, 17 Feb 2009 14:03:22 -0800 Subject: [ARM] msm: trout: Switch to new headset driver in trout Signed-off-by: San Mehat --- arch/arm/mach-msm/Kconfig | 2 +- arch/arm/mach-msm/Makefile | 2 +- arch/arm/mach-msm/board-trout-h2w.c | 542 ------------------------------------ arch/arm/mach-msm/board-trout.c | 47 ++++ 4 files changed, 49 insertions(+), 544 deletions(-) delete mode 100644 arch/arm/mach-msm/board-trout-h2w.c (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index 9c09e1ba8b1d..7ad1d8f92c78 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -63,7 +63,7 @@ config MACH_TROUT help Support for the HTC Dream, T-Mobile G1, Android ADP1 devices. -config TROUT_H2W +config HTC_HEADSET tristate "HTC 2 Wire detection driver" default n help diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index c418bd1495d9..6de6a2d457ba 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -23,6 +23,6 @@ obj-$(CONFIG_MACH_TROUT) += board-dream.o obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o board-halibut-keypad.o obj-$(CONFIG_MACH_TROUT) += htc_akm_cal.o htc_wifi_nvs.o htc_acoustic.o obj-$(CONFIG_MACH_TROUT) += board-trout-mmc.o board-trout-wifi.o -obj-$(CONFIG_TROUT_H2W) += board-trout-h2w.o obj-$(CONFIG_TROUT_BATTCHG) += htc_battery.o obj-$(CONFIG_TROUT_PWRSINK) += htc_pwrsink.o +obj-$(CONFIG_HTC_HEADSET) += htc_headset.o diff --git a/arch/arm/mach-msm/board-trout-h2w.c b/arch/arm/mach-msm/board-trout-h2w.c deleted file mode 100644 index 66b82707a3b3..000000000000 --- a/arch/arm/mach-msm/board-trout-h2w.c +++ /dev/null @@ -1,542 +0,0 @@ -/* - * H2W device detection driver. - * - * Copyright (C) 2008 HTC Corporation. - * Copyright (C) 2008 Google, Inc. - * - * Authors: - * Laurence Chen - * Nick Pelly - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * 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. - * - */ - -/* For detecting HTC 2 Wire devices, such as wired headset. - - Logically, the H2W driver is always present, and H2W state (hi->state) - indicates what is currently plugged into the H2W interface. - - When the headset is plugged in, CABLE_IN1 is pulled low. When the headset - button is pressed, CABLE_IN2 is pulled low. These two lines are shared with - the TX and RX (respectively) of UART3 - used for serial debugging. - - This headset driver keeps the CPLD configured as UART3 for as long as - possible, so that we can do serial FIQ debugging even when the kernel is - locked and this driver no longer runs. So it only configures the CPLD to - GPIO while the headset is plugged in, and for 10ms during detection work. - - Unfortunately we can't leave the CPLD as UART3 while a headset is plugged - in, UART3 is pullup on TX but the headset is pull-down, causing a 55 mA - drain on trout. - - The headset detection work involves setting CPLD to GPIO, and then pulling - CABLE_IN1 high with a stronger pullup than usual. A H2W headset will still - pull this line low, whereas other attachments such as a serial console - would get pulled up by this stronger pullup. - - Headset insertion/removal causes UEvent's to be sent, and - /sys/class/switch/h2w/state to be updated. - - Button presses are interpreted as input event (KEY_MEDIA). Button presses - are ignored if the headset is plugged in, so the buttons on 11 pin -> 3.5mm - jack adapters do not work until a headset is plugged into the adapter. This - is to avoid serial RX traffic causing spurious button press events. - - We tend to check the status of CABLE_IN1 a few more times than strictly - necessary during headset detection, to avoid spurious headset insertion - events caused by serial debugger TX traffic. -*/ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "board-trout.h" - -#ifdef CONFIG_DEBUG_TROUT_H2W -#define H2W_DBG(fmt, arg...) printk(KERN_INFO "[H2W] %s " fmt "\n", __FUNCTION__, ## arg) -#else -#define H2W_DBG(fmt, arg...) do {} while (0) -#endif - -static struct workqueue_struct *g_detection_work_queue; -static void detection_work(struct work_struct *work); -static DECLARE_WORK(g_detection_work, detection_work); -enum { - NO_DEVICE = 0, - HTC_HEADSET = 1, -}; - -enum { - UART3 = 0, - GPIO = 1, -}; - -struct h2w_info { - struct switch_dev sdev; - struct input_dev *input; - - atomic_t btn_state; - int ignore_btn; - - unsigned int irq; - unsigned int irq_btn; - - struct hrtimer timer; - ktime_t debounce_time; - - struct hrtimer btn_timer; - ktime_t btn_debounce_time; -}; -static struct h2w_info *hi; - -static ssize_t trout_h2w_print_name(struct switch_dev *sdev, char *buf) -{ - switch (switch_get_state(&hi->sdev)) { - case NO_DEVICE: - return sprintf(buf, "No Device\n"); - case HTC_HEADSET: - return sprintf(buf, "Headset\n"); - } - return -EINVAL; -} - -static void configure_cpld(int route) -{ - H2W_DBG(" route = %s", route == UART3 ? "UART3" : "GPIO"); - switch (route) { - case UART3: - gpio_set_value(TROUT_GPIO_H2W_SEL0, 0); - gpio_set_value(TROUT_GPIO_H2W_SEL1, 1); - break; - case GPIO: - gpio_set_value(TROUT_GPIO_H2W_SEL0, 0); - gpio_set_value(TROUT_GPIO_H2W_SEL1, 0); - break; - } -} - -static void button_pressed(void) -{ - H2W_DBG(""); - atomic_set(&hi->btn_state, 1); - input_report_key(hi->input, KEY_MEDIA, 1); - input_sync(hi->input); -} - -static void button_released(void) -{ - H2W_DBG(""); - atomic_set(&hi->btn_state, 0); - input_report_key(hi->input, KEY_MEDIA, 0); - input_sync(hi->input); -} - -#ifdef CONFIG_MSM_SERIAL_DEBUGGER -extern void msm_serial_debug_enable(int); -#endif - -static void insert_headset(void) -{ - unsigned long irq_flags; - - H2W_DBG(""); - - switch_set_state(&hi->sdev, HTC_HEADSET); - configure_cpld(GPIO); - -#ifdef CONFIG_MSM_SERIAL_DEBUGGER - msm_serial_debug_enable(false); -#endif - - - /* On some non-standard headset adapters (usually those without a - * button) the btn line is pulled down at the same time as the detect - * line. We can check here by sampling the button line, if it is - * low then it is probably a bad adapter so ignore the button. - * If the button is released then we stop ignoring the button, so that - * the user can recover from the situation where a headset is plugged - * in with button held down. - */ - hi->ignore_btn = !gpio_get_value(TROUT_GPIO_CABLE_IN2); - - /* Enable button irq */ - local_irq_save(irq_flags); - enable_irq(hi->irq_btn); - local_irq_restore(irq_flags); - - hi->debounce_time = ktime_set(0, 20000000); /* 20 ms */ -} - -static void remove_headset(void) -{ - unsigned long irq_flags; - - H2W_DBG(""); - - switch_set_state(&hi->sdev, NO_DEVICE); - configure_cpld(UART3); - - /* Disable button */ - local_irq_save(irq_flags); - disable_irq(hi->irq_btn); - local_irq_restore(irq_flags); - - if (atomic_read(&hi->btn_state)) - button_released(); - - hi->debounce_time = ktime_set(0, 100000000); /* 100 ms */ -} - -static void detection_work(struct work_struct *work) -{ - unsigned long irq_flags; - int clk, cable_in1; - - H2W_DBG(""); - - if (gpio_get_value(TROUT_GPIO_CABLE_IN1) != 0) { - /* Headset not plugged in */ - if (switch_get_state(&hi->sdev) == HTC_HEADSET) - remove_headset(); - return; - } - - /* Something plugged in, lets make sure its a headset */ - - /* Switch CPLD to GPIO to do detection */ - configure_cpld(GPIO); - /* Disable headset interrupt while detecting.*/ - local_irq_save(irq_flags); - disable_irq(hi->irq); - local_irq_restore(irq_flags); - - /* Set GPIO_CABLE_IN1 as output high */ - gpio_direction_output(TROUT_GPIO_CABLE_IN1, 1); - /* Delay 10ms for pin stable. */ - msleep(10); - /* Save H2W_CLK */ - clk = gpio_get_value(TROUT_GPIO_H2W_CLK_GPI); - /* Set GPIO_CABLE_IN1 as input */ - gpio_direction_input(TROUT_GPIO_CABLE_IN1); - - /* Restore IRQs */ - local_irq_save(irq_flags); - enable_irq(hi->irq); - local_irq_restore(irq_flags); - - cable_in1 = gpio_get_value(TROUT_GPIO_CABLE_IN1); - - if (cable_in1 == 0 && clk == 0) { - if (switch_get_state(&hi->sdev) == NO_DEVICE) - insert_headset(); - } else { - configure_cpld(UART3); - H2W_DBG("CABLE_IN1 was low, but not a headset " - "(recent cable_in1 = %d, clk = %d)", cable_in1, clk); - } -} - -static enum hrtimer_restart button_event_timer_func(struct hrtimer *data) -{ - H2W_DBG(""); - - if (switch_get_state(&hi->sdev) == HTC_HEADSET) { - if (gpio_get_value(TROUT_GPIO_CABLE_IN2)) { - if (hi->ignore_btn) - hi->ignore_btn = 0; - else if (atomic_read(&hi->btn_state)) - button_released(); - } else { - if (!hi->ignore_btn && !atomic_read(&hi->btn_state)) - button_pressed(); - } - } - - return HRTIMER_NORESTART; -} - -static enum hrtimer_restart detect_event_timer_func(struct hrtimer *data) -{ - H2W_DBG(""); - - queue_work(g_detection_work_queue, &g_detection_work); - return HRTIMER_NORESTART; -} - -static irqreturn_t detect_irq_handler(int irq, void *dev_id) -{ - int value1, value2; - int retry_limit = 10; - - H2W_DBG(""); - do { - value1 = gpio_get_value(TROUT_GPIO_CABLE_IN1); - set_irq_type(hi->irq, value1 ? - IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH); - value2 = gpio_get_value(TROUT_GPIO_CABLE_IN1); - } while (value1 != value2 && retry_limit-- > 0); - - H2W_DBG("value2 = %d (%d retries)", value2, (10-retry_limit)); - - if ((switch_get_state(&hi->sdev) == NO_DEVICE) ^ value2) { - if (switch_get_state(&hi->sdev) == HTC_HEADSET) - hi->ignore_btn = 1; - /* Do the rest of the work in timer context */ - hrtimer_start(&hi->timer, hi->debounce_time, HRTIMER_MODE_REL); - } - - return IRQ_HANDLED; -} - -static irqreturn_t button_irq_handler(int irq, void *dev_id) -{ - int value1, value2; - int retry_limit = 10; - - H2W_DBG(""); - do { - value1 = gpio_get_value(TROUT_GPIO_CABLE_IN2); - set_irq_type(hi->irq_btn, value1 ? - IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH); - value2 = gpio_get_value(TROUT_GPIO_CABLE_IN2); - } while (value1 != value2 && retry_limit-- > 0); - - H2W_DBG("value2 = %d (%d retries)", value2, (10-retry_limit)); - - hrtimer_start(&hi->btn_timer, hi->btn_debounce_time, HRTIMER_MODE_REL); - - return IRQ_HANDLED; -} - -#if defined(CONFIG_DEBUG_FS) -static void h2w_debug_set(void *data, u64 val) -{ - switch_set_state(&hi->sdev, (int)val); -} - -static u64 h2w_debug_get(void *data) -{ - return 0; -} - -DEFINE_SIMPLE_ATTRIBUTE(h2w_debug_fops, h2w_debug_get, h2w_debug_set, "%llu\n"); -static int __init h2w_debug_init(void) -{ - struct dentry *dent; - - dent = debugfs_create_dir("h2w", 0); - if (IS_ERR(dent)) - return PTR_ERR(dent); - - debugfs_create_file("state", 0644, dent, NULL, &h2w_debug_fops); - - return 0; -} - -device_initcall(h2w_debug_init); -#endif - -static int trout_h2w_probe(struct platform_device *pdev) -{ - int ret; - - printk(KERN_INFO "H2W: Registering H2W (headset) driver\n"); - hi = kzalloc(sizeof(struct h2w_info), GFP_KERNEL); - if (!hi) - return -ENOMEM; - - atomic_set(&hi->btn_state, 0); - hi->ignore_btn = 0; - - hi->debounce_time = ktime_set(0, 100000000); /* 100 ms */ - hi->btn_debounce_time = ktime_set(0, 10000000); /* 10 ms */ - hi->sdev.name = "h2w"; - hi->sdev.print_name = trout_h2w_print_name; - - ret = switch_dev_register(&hi->sdev); - if (ret < 0) - goto err_switch_dev_register; - - g_detection_work_queue = create_workqueue("detection"); - if (g_detection_work_queue == NULL) { - ret = -ENOMEM; - goto err_create_work_queue; - } - - ret = gpio_request(TROUT_GPIO_CABLE_IN1, "h2w_detect"); - if (ret < 0) - goto err_request_detect_gpio; - - ret = gpio_request(TROUT_GPIO_CABLE_IN2, "h2w_button"); - if (ret < 0) - goto err_request_button_gpio; - - ret = gpio_direction_input(TROUT_GPIO_CABLE_IN1); - if (ret < 0) - goto err_set_detect_gpio; - - ret = gpio_direction_input(TROUT_GPIO_CABLE_IN2); - if (ret < 0) - goto err_set_button_gpio; - - hi->irq = gpio_to_irq(TROUT_GPIO_CABLE_IN1); - if (hi->irq < 0) { - ret = hi->irq; - goto err_get_h2w_detect_irq_num_failed; - } - - hi->irq_btn = gpio_to_irq(TROUT_GPIO_CABLE_IN2); - if (hi->irq_btn < 0) { - ret = hi->irq_btn; - goto err_get_button_irq_num_failed; - } - - /* Set CPLD MUX to H2W <-> CPLD GPIO */ - configure_cpld(UART3); - /* Set the CPLD connected H2W GPIO's to input */ - gpio_set_value(TROUT_GPIO_H2W_CLK_DIR, 0); - gpio_set_value(TROUT_GPIO_H2W_DAT_DIR, 0); - - hrtimer_init(&hi->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - hi->timer.function = detect_event_timer_func; - hrtimer_init(&hi->btn_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - hi->btn_timer.function = button_event_timer_func; - - ret = request_irq(hi->irq, detect_irq_handler, - IRQF_TRIGGER_LOW, "h2w_detect", NULL); - if (ret < 0) - goto err_request_detect_irq; - - /* Disable button until plugged in */ - set_irq_flags(hi->irq_btn, IRQF_VALID | IRQF_NOAUTOEN); - ret = request_irq(hi->irq_btn, button_irq_handler, - IRQF_TRIGGER_LOW, "h2w_button", NULL); - if (ret < 0) - goto err_request_h2w_headset_button_irq; - - ret = set_irq_wake(hi->irq, 1); - if (ret < 0) - goto err_request_input_dev; - ret = set_irq_wake(hi->irq_btn, 1); - if (ret < 0) - goto err_request_input_dev; - - hi->input = input_allocate_device(); - if (!hi->input) { - ret = -ENOMEM; - goto err_request_input_dev; - } - - hi->input->name = "h2w headset"; - hi->input->evbit[0] = BIT_MASK(EV_KEY); - hi->input->keybit[BIT_WORD(KEY_MEDIA)] = BIT_MASK(KEY_MEDIA); - - ret = input_register_device(hi->input); - if (ret < 0) - goto err_register_input_dev; - - return 0; - -err_register_input_dev: - input_free_device(hi->input); -err_request_input_dev: - free_irq(hi->irq_btn, 0); -err_request_h2w_headset_button_irq: - free_irq(hi->irq, 0); -err_request_detect_irq: -err_get_button_irq_num_failed: -err_get_h2w_detect_irq_num_failed: -err_set_button_gpio: -err_set_detect_gpio: - gpio_free(TROUT_GPIO_CABLE_IN2); -err_request_button_gpio: - gpio_free(TROUT_GPIO_CABLE_IN1); -err_request_detect_gpio: - destroy_workqueue(g_detection_work_queue); -err_create_work_queue: - switch_dev_unregister(&hi->sdev); -err_switch_dev_register: - printk(KERN_ERR "H2W: Failed to register driver\n"); - - return ret; -} - -static int trout_h2w_remove(struct platform_device *pdev) -{ - H2W_DBG(""); - if (switch_get_state(&hi->sdev)) - remove_headset(); - input_unregister_device(hi->input); - gpio_free(TROUT_GPIO_CABLE_IN2); - gpio_free(TROUT_GPIO_CABLE_IN1); - free_irq(hi->irq_btn, 0); - free_irq(hi->irq, 0); - destroy_workqueue(g_detection_work_queue); - switch_dev_unregister(&hi->sdev); - - return 0; -} - -static struct platform_device trout_h2w_device = { - .name = "trout-h2w", -}; - -static struct platform_driver trout_h2w_driver = { - .probe = trout_h2w_probe, - .remove = trout_h2w_remove, - .driver = { - .name = "trout-h2w", - .owner = THIS_MODULE, - }, -}; - -static int __init trout_h2w_init(void) -{ - int ret; - H2W_DBG(""); - ret = platform_driver_register(&trout_h2w_driver); - if (ret) - return ret; - return platform_device_register(&trout_h2w_device); -} - -static void __exit trout_h2w_exit(void) -{ - platform_device_unregister(&trout_h2w_device); - platform_driver_unregister(&trout_h2w_driver); -} - -module_init(trout_h2w_init); -module_exit(trout_h2w_exit); - -MODULE_AUTHOR("Laurence Chen "); -MODULE_DESCRIPTION("HTC 2 Wire detection driver for trout"); -MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-msm/board-trout.c b/arch/arm/mach-msm/board-trout.c index 1b0e8b908672..ed8023cfae38 100644 --- a/arch/arm/mach-msm/board-trout.c +++ b/arch/arm/mach-msm/board-trout.c @@ -67,6 +67,9 @@ #include #include #include +#ifdef CONFIG_HTC_HEADSET +#include +#endif #ifdef CONFIG_WIFI_CONTROL_FUNC #include #endif @@ -427,6 +430,47 @@ static struct platform_device sd_door_switch = { }, }; +#ifdef CONFIG_HTC_HEADSET +static void h2w_config_cpld(int route) +{ + switch (route) { + case H2W_UART3: + gpio_set_value(TROUT_GPIO_H2W_SEL0, 0); + gpio_set_value(TROUT_GPIO_H2W_SEL1, 1); + break; + case H2W_GPIO: + gpio_set_value(TROUT_GPIO_H2W_SEL0, 0); + gpio_set_value(TROUT_GPIO_H2W_SEL1, 0); + break; + } +} + +static void h2w_init_cpld(void) +{ + h2w_config_cpld(H2W_UART3); + gpio_set_value(TROUT_GPIO_H2W_CLK_DIR, 0); + gpio_set_value(TROUT_GPIO_H2W_DAT_DIR, 0); +} + +static struct h2w_platform_data trout_h2w_data = { + .cable_in1 = TROUT_GPIO_CABLE_IN1, + .cable_in2 = TROUT_GPIO_CABLE_IN2, + .h2w_clk = TROUT_GPIO_H2W_CLK_GPI, + .h2w_data = TROUT_GPIO_H2W_DAT_GPI, + .debug_uart = H2W_UART3, + .config_cpld = h2w_config_cpld, + .init_cpld = h2w_init_cpld, +}; + +static struct platform_device trout_h2w = { + .name = "h2w", + .id = -1, + .dev = { + .platform_data = &trout_h2w_data, + }, +}; +#endif + /* adjust eye diagram, disable vbusvalid interrupts */ static int trout_phy_init_seq[] = { 0x40, 0x31, 0x1D, 0x0D, 0x1D, 0x10, -1 }; @@ -701,6 +745,9 @@ static struct platform_device *devices[] __initdata = { #ifdef CONFIG_WIFI_CONTROL_FUNC &trout_wifi, #endif +#ifdef CONFIG_HTC_HEADSET + &trout_h2w, +#endif #if defined(CONFIG_TROUT_PWRSINK) &trout_pwr_sink, #endif -- cgit v1.2.3 From 01811ff65f245a3850496a2c75187ce533ed6a87 Mon Sep 17 00:00:00 2001 From: Dima Zavin Date: Fri, 6 Feb 2009 16:43:24 -0800 Subject: [ARM] msm: move clock definitions to devices.c Also, add the begininngs for having a master list of clocks, and a bitmask for which sub-arch's they are used by. Signed-off-by: Dima Zavin --- arch/arm/mach-msm/Makefile | 2 +- arch/arm/mach-msm/clock-7x01a.c | 126 ---------------------------------------- arch/arm/mach-msm/clock.c | 7 ++- arch/arm/mach-msm/clock.h | 59 ++++++++++++++++--- arch/arm/mach-msm/devices.c | 66 ++++++++++++++++++++- 5 files changed, 120 insertions(+), 140 deletions(-) delete mode 100644 arch/arm/mach-msm/clock-7x01a.c (limited to 'arch') diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 6de6a2d457ba..8491964fb860 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -3,7 +3,7 @@ obj-y += devices.o obj-y += proc_comm.o obj-y += vreg.o obj-y += acpuclock.o -obj-y += clock.o clock-7x01a.o +obj-y += clock.o obj-y += gpio.o generic_gpio.o obj-y += nand_partitions.o diff --git a/arch/arm/mach-msm/clock-7x01a.c b/arch/arm/mach-msm/clock-7x01a.c deleted file mode 100644 index 62230a3428ee..000000000000 --- a/arch/arm/mach-msm/clock-7x01a.c +++ /dev/null @@ -1,126 +0,0 @@ -/* arch/arm/mach-msm/clock-7x01a.c - * - * Clock tables for MSM7X01A - * - * Copyright (C) 2007 Google, Inc. - * Copyright (c) 2007 QUALCOMM Incorporated - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * 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 "clock.h" -#include "devices.h" - -/* clock IDs used by the modem processor */ - -#define ACPU_CLK 0 /* Applications processor clock */ -#define ADM_CLK 1 /* Applications data mover clock */ -#define ADSP_CLK 2 /* ADSP clock */ -#define EBI1_CLK 3 /* External bus interface 1 clock */ -#define EBI2_CLK 4 /* External bus interface 2 clock */ -#define ECODEC_CLK 5 /* External CODEC clock */ -#define EMDH_CLK 6 /* External MDDI host clock */ -#define GP_CLK 7 /* General purpose clock */ -#define GRP_CLK 8 /* Graphics clock */ -#define I2C_CLK 9 /* I2C clock */ -#define ICODEC_RX_CLK 10 /* Internal CODEX RX clock */ -#define ICODEC_TX_CLK 11 /* Internal CODEX TX clock */ -#define IMEM_CLK 12 /* Internal graphics memory clock */ -#define MDC_CLK 13 /* MDDI client clock */ -#define MDP_CLK 14 /* Mobile display processor clock */ -#define PBUS_CLK 15 /* Peripheral bus clock */ -#define PCM_CLK 16 /* PCM clock */ -#define PMDH_CLK 17 /* Primary MDDI host clock */ -#define SDAC_CLK 18 /* Stereo DAC clock */ -#define SDC1_CLK 19 /* Secure Digital Card clocks */ -#define SDC1_PCLK 20 -#define SDC2_CLK 21 -#define SDC2_PCLK 22 -#define SDC3_CLK 23 -#define SDC3_PCLK 24 -#define SDC4_CLK 25 -#define SDC4_PCLK 26 -#define TSIF_CLK 27 /* Transport Stream Interface clocks */ -#define TSIF_REF_CLK 28 -#define TV_DAC_CLK 29 /* TV clocks */ -#define TV_ENC_CLK 30 -#define UART1_CLK 31 /* UART clocks */ -#define UART2_CLK 32 -#define UART3_CLK 33 -#define UART1DM_CLK 34 -#define UART2DM_CLK 35 -#define USB_HS_CLK 36 /* High speed USB core clock */ -#define USB_HS_PCLK 37 /* High speed USB pbus clock */ -#define USB_OTG_CLK 38 /* Full speed USB clock */ -#define VDC_CLK 39 /* Video controller clock */ -#define VFE_CLK 40 /* Camera / Video Front End clock */ -#define VFE_MDC_CLK 41 /* VFE MDDI client clock */ - -#define NR_CLKS 42 - -#define CLOCK(clk_name, clk_id, clk_dev, clk_flags) { \ - .name = clk_name, \ - .id = clk_id, \ - .flags = clk_flags, \ - .dev = clk_dev, \ - } - -#define OFF CLKFLAG_AUTO_OFF -#define MINMAX CLKFLAG_USE_MIN_MAX_TO_SET - -struct clk msm_clocks[] = { - CLOCK("adm_clk", ADM_CLK, NULL, 0), - CLOCK("adsp_clk", ADSP_CLK, NULL, 0), - CLOCK("ebi1_clk", EBI1_CLK, NULL, 0), - CLOCK("ebi2_clk", EBI2_CLK, NULL, 0), - CLOCK("ecodec_clk", ECODEC_CLK, NULL, 0), - CLOCK("emdh_clk", EMDH_CLK, NULL, OFF), - CLOCK("gp_clk", GP_CLK, NULL, 0), - CLOCK("grp_clk", GRP_CLK, NULL, OFF), - CLOCK("i2c_clk", I2C_CLK, &msm_device_i2c.dev, 0), - CLOCK("icodec_rx_clk", ICODEC_RX_CLK, NULL, 0), - CLOCK("icodec_tx_clk", ICODEC_TX_CLK, NULL, 0), - CLOCK("imem_clk", IMEM_CLK, NULL, OFF), - CLOCK("mdc_clk", MDC_CLK, NULL, 0), - CLOCK("mdp_clk", MDP_CLK, NULL, OFF), - CLOCK("pbus_clk", PBUS_CLK, NULL, 0), - CLOCK("pcm_clk", PCM_CLK, NULL, 0), - CLOCK("pmdh_clk", PMDH_CLK, NULL, OFF | MINMAX), - CLOCK("sdac_clk", SDAC_CLK, NULL, OFF), - CLOCK("sdc_clk", SDC1_CLK, &msm_device_sdc1.dev, OFF), - CLOCK("sdc_pclk", SDC1_PCLK, &msm_device_sdc1.dev, OFF), - CLOCK("sdc_clk", SDC2_CLK, &msm_device_sdc2.dev, OFF), - CLOCK("sdc_pclk", SDC2_PCLK, &msm_device_sdc2.dev, OFF), - CLOCK("sdc_clk", SDC3_CLK, &msm_device_sdc3.dev, OFF), - CLOCK("sdc_pclk", SDC3_PCLK, &msm_device_sdc3.dev, OFF), - CLOCK("sdc_clk", SDC4_CLK, &msm_device_sdc4.dev, OFF), - CLOCK("sdc_pclk", SDC4_PCLK, &msm_device_sdc4.dev, OFF), - CLOCK("tsif_clk", TSIF_CLK, NULL, 0), - CLOCK("tsif_ref_clk", TSIF_REF_CLK, NULL, 0), - CLOCK("tv_dac_clk", TV_DAC_CLK, NULL, 0), - CLOCK("tv_enc_clk", TV_ENC_CLK, NULL, 0), - CLOCK("uart_clk", UART1_CLK, &msm_device_uart1.dev, OFF), - CLOCK("uart_clk", UART2_CLK, &msm_device_uart2.dev, 0), - CLOCK("uart_clk", UART3_CLK, &msm_device_uart3.dev, OFF), - CLOCK("uart1dm_clk", UART1DM_CLK, NULL, OFF), - CLOCK("uart2dm_clk", UART2DM_CLK, NULL, 0), - CLOCK("usb_hs_clk", USB_HS_CLK, &msm_device_hsusb.dev, OFF), - CLOCK("usb_hs_pclk", USB_HS_PCLK, &msm_device_hsusb.dev, OFF), - CLOCK("usb_otg_clk", USB_OTG_CLK, NULL, 0), - CLOCK("vdc_clk", VDC_CLK, NULL, OFF | MINMAX), - CLOCK("vfe_clk", VFE_CLK, NULL, OFF), - CLOCK("vfe_mdc_clk", VFE_MDC_CLK, NULL, OFF), -}; - -unsigned msm_num_clocks = ARRAY_SIZE(msm_clocks); diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c index 3b1ce36f1032..fbfb0fd4b76e 100644 --- a/arch/arm/mach-msm/clock.c +++ b/arch/arm/mach-msm/clock.c @@ -180,12 +180,13 @@ EXPORT_SYMBOL(clk_set_flags); void __init msm_clock_init(void) { - unsigned n; + struct clk *clk; spin_lock_init(&clocks_lock); mutex_lock(&clocks_mutex); - for (n = 0; n < msm_num_clocks; n++) - list_add_tail(&msm_clocks[n].list, &clocks); + for (clk = msm_clocks; clk && clk->name; clk++) { + list_add_tail(&clk->list, &clocks); + } mutex_unlock(&clocks_mutex); } diff --git a/arch/arm/mach-msm/clock.h b/arch/arm/mach-msm/clock.h index f875e1544e5f..51e7ed7bdc1a 100644 --- a/arch/arm/mach-msm/clock.h +++ b/arch/arm/mach-msm/clock.h @@ -19,14 +19,11 @@ #include -#define CLKFLAG_INVERT 0x00000001 -#define CLKFLAG_NOINVERT 0x00000002 -#define CLKFLAG_NONEST 0x00000004 -#define CLKFLAG_NORESET 0x00000008 +#define CLKFLAG_USE_MIN_MAX_TO_SET (0x00000001) +#define CLKFLAG_AUTO_OFF (0x00000002) -#define CLK_FIRST_AVAILABLE_FLAG 0x00000100 -#define CLKFLAG_USE_MIN_MAX_TO_SET 0x00000200 -#define CLKFLAG_AUTO_OFF 0x00000400 +#define CLKFLAG_ARCH_MSM7X00A (0x00010000) +#define CLKFLAG_ARCH_ALL (0xffff0000) struct clk { uint32_t id; @@ -41,8 +38,54 @@ struct clk { #define A11S_CLK_SEL_ADDR (MSM_CSR_BASE + 0x104) #define A11S_VDD_SVS_PLEVEL_ADDR (MSM_CSR_BASE + 0x124) +/* clock IDs used by the modem processor */ + +#define ACPU_CLK 0 /* Applications processor clock */ +#define ADM_CLK 1 /* Applications data mover clock */ +#define ADSP_CLK 2 /* ADSP clock */ +#define EBI1_CLK 3 /* External bus interface 1 clock */ +#define EBI2_CLK 4 /* External bus interface 2 clock */ +#define ECODEC_CLK 5 /* External CODEC clock */ +#define EMDH_CLK 6 /* External MDDI host clock */ +#define GP_CLK 7 /* General purpose clock */ +#define GRP_CLK 8 /* Graphics clock */ +#define I2C_CLK 9 /* I2C clock */ +#define ICODEC_RX_CLK 10 /* Internal CODEX RX clock */ +#define ICODEC_TX_CLK 11 /* Internal CODEX TX clock */ +#define IMEM_CLK 12 /* Internal graphics memory clock */ +#define MDC_CLK 13 /* MDDI client clock */ +#define MDP_CLK 14 /* Mobile display processor clock */ +#define PBUS_CLK 15 /* Peripheral bus clock */ +#define PCM_CLK 16 /* PCM clock */ +#define PMDH_CLK 17 /* Primary MDDI host clock */ +#define SDAC_CLK 18 /* Stereo DAC clock */ +#define SDC1_CLK 19 /* Secure Digital Card clocks */ +#define SDC1_PCLK 20 +#define SDC2_CLK 21 +#define SDC2_PCLK 22 +#define SDC3_CLK 23 +#define SDC3_PCLK 24 +#define SDC4_CLK 25 +#define SDC4_PCLK 26 +#define TSIF_CLK 27 /* Transport Stream Interface clocks */ +#define TSIF_REF_CLK 28 +#define TV_DAC_CLK 29 /* TV clocks */ +#define TV_ENC_CLK 30 +#define UART1_CLK 31 /* UART clocks */ +#define UART2_CLK 32 +#define UART3_CLK 33 +#define UART1DM_CLK 34 +#define UART2DM_CLK 35 +#define USB_HS_CLK 36 /* High speed USB core clock */ +#define USB_HS_PCLK 37 /* High speed USB pbus clock */ +#define USB_OTG_CLK 38 /* Full speed USB clock */ +#define VDC_CLK 39 /* Video controller clock */ +#define VFE_CLK 40 /* Camera / Video Front End clock */ +#define VFE_MDC_CLK 41 /* VFE MDDI client clock */ + +#define NR_CLKS 42 + extern struct clk msm_clocks[]; -extern unsigned msm_num_clocks; #endif diff --git a/arch/arm/mach-msm/devices.c b/arch/arm/mach-msm/devices.c index 3004c2b0a0d1..42ca4a6ed0c3 100644 --- a/arch/arm/mach-msm/devices.c +++ b/arch/arm/mach-msm/devices.c @@ -18,14 +18,16 @@ #include #include -#include "devices.h" +#include #include #include #include - #include +#include "devices.h" +#include "clock.h" + static struct resource resources_uart1[] = { { .start = INT_UART1, @@ -287,3 +289,63 @@ int __init msm_add_sdcc(unsigned int controller, struct mmc_platform_data *plat) pdev->dev.platform_data = plat; return platform_device_register(pdev); } +#define CLOCK(clk_name, clk_id, clk_dev, clk_flags, clk_arch) { \ + .name = clk_name, \ + .id = clk_id, \ + .flags = (clk_flags) | ((clk_arch) & CLKFLAG_ARCH_ALL), \ + .dev = clk_dev, \ + } + +#define CLK_ALL(name, id, dev, flags) \ + CLOCK(name, id, dev, flags, CLKFLAG_ARCH_ALL) +#define CLK_7X00A(name, id, dev, flags) \ + CLOCK(name, id, dev, flags, CLKFLAG_ARCH_MSM7X00A) + +#define OFF CLKFLAG_AUTO_OFF +#define MINMAX CLKFLAG_USE_MIN_MAX_TO_SET + +struct clk msm_clocks[] = { + CLK_ALL("adm_clk", ADM_CLK, NULL, 0), + CLK_ALL("adsp_clk", ADSP_CLK, NULL, 0), + CLK_ALL("ebi1_clk", EBI1_CLK, NULL, 0), + CLK_ALL("ebi2_clk", EBI2_CLK, NULL, 0), + CLK_ALL("ecodec_clk", ECODEC_CLK, NULL, 0), + CLK_ALL("mddi_clk", EMDH_CLK, &msm_device_mddi1.dev, OFF), + CLK_ALL("gp_clk", GP_CLK, NULL, 0), + CLK_ALL("grp_clk", GRP_CLK, NULL, OFF), + CLK_ALL("i2c_clk", I2C_CLK, &msm_device_i2c.dev, 0), + CLK_ALL("icodec_rx_clk", ICODEC_RX_CLK, NULL, 0), + CLK_ALL("icodec_tx_clk", ICODEC_TX_CLK, NULL, 0), + CLK_ALL("imem_clk", IMEM_CLK, NULL, OFF), + CLK_ALL("mdc_clk", MDC_CLK, NULL, 0), + CLK_ALL("mdp_clk", MDP_CLK, &msm_device_mdp.dev, OFF), + CLK_ALL("pbus_clk", PBUS_CLK, NULL, 0), + CLK_ALL("pcm_clk", PCM_CLK, NULL, 0), + CLK_ALL("mddi_clk", PMDH_CLK, &msm_device_mddi0.dev, OFF | MINMAX), + CLK_ALL("sdac_clk", SDAC_CLK, NULL, OFF), + CLK_ALL("sdc_clk", SDC1_CLK, &msm_device_sdc1.dev, OFF), + CLK_ALL("sdc_pclk", SDC1_PCLK, &msm_device_sdc1.dev, OFF), + CLK_ALL("sdc_clk", SDC2_CLK, &msm_device_sdc2.dev, OFF), + CLK_ALL("sdc_pclk", SDC2_PCLK, &msm_device_sdc2.dev, OFF), + CLK_ALL("sdc_clk", SDC3_CLK, &msm_device_sdc3.dev, OFF), + CLK_ALL("sdc_pclk", SDC3_PCLK, &msm_device_sdc3.dev, OFF), + CLK_ALL("sdc_clk", SDC4_CLK, &msm_device_sdc4.dev, OFF), + CLK_ALL("sdc_pclk", SDC4_PCLK, &msm_device_sdc4.dev, OFF), + CLK_ALL("tsif_clk", TSIF_CLK, NULL, 0), + CLK_ALL("tsif_ref_clk", TSIF_REF_CLK, NULL, 0), + CLK_ALL("tv_dac_clk", TV_DAC_CLK, NULL, 0), + CLK_ALL("tv_enc_clk", TV_ENC_CLK, NULL, 0), + CLK_ALL("uart_clk", UART1_CLK, &msm_device_uart1.dev, OFF), + CLK_ALL("uart_clk", UART2_CLK, &msm_device_uart2.dev, 0), + CLK_ALL("uart_clk", UART3_CLK, &msm_device_uart3.dev, OFF), + CLK_ALL("uartdm_clk", UART1DM_CLK, &msm_device_uart_dm1.dev, OFF), + CLK_ALL("uartdm_clk", UART2DM_CLK, &msm_device_uart_dm2.dev, 0), + CLK_ALL("usb_hs_clk", USB_HS_CLK, &msm_device_hsusb.dev, OFF), + CLK_ALL("usb_hs_pclk", USB_HS_PCLK, &msm_device_hsusb.dev, OFF), + CLK_ALL("usb_otg_clk", USB_OTG_CLK, NULL, 0), + CLK_ALL("vdc_clk", VDC_CLK, NULL, OFF | MINMAX), + CLK_ALL("vfe_clk", VFE_CLK, NULL, OFF), + CLK_ALL("vfe_mdc_clk", VFE_MDC_CLK, NULL, OFF), + + CLOCK(NULL, 0, NULL, 0, 0), +}; -- cgit v1.2.3 From c25618477340fcca62103e68cc176766ff50f99e Mon Sep 17 00:00:00 2001 From: Iliyan Malchev Date: Sat, 14 Feb 2009 13:33:24 -0800 Subject: [ARM] msm: htc_acoustic: use smem and rpc to write acoustic table Signed-off-by: Iliyan Malchev --- arch/arm/mach-msm/htc_acoustic.c | 212 ++++++++++++++++++++++++++++++++------- 1 file changed, 176 insertions(+), 36 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/htc_acoustic.c b/arch/arm/mach-msm/htc_acoustic.c index 9fb92f588c0b..3de71dddb589 100644 --- a/arch/arm/mach-msm/htc_acoustic.c +++ b/arch/arm/mach-msm/htc_acoustic.c @@ -13,54 +13,205 @@ * GNU General Public License for more details. * */ - +#include #include #include #include #include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "smd_private.h" + +#define ACOUSTIC_IOCTL_MAGIC 'p' +#define ACOUSTIC_ARM11_DONE _IOW(ACOUSTIC_IOCTL_MAGIC, 22, unsigned int) + +#define HTCRPOG 0x30100002 +#define HTCVERS 0 +#define ONCRPC_SET_MIC_BIAS_PROC (1) +#define ONCRPC_ACOUSTIC_INIT_PROC (5) +#define ONCRPC_ALLOC_ACOUSTIC_MEM_PROC (6) + +#define HTC_ACOUSTIC_TABLE_SIZE (0x10000) + +#define D(fmt, args...) printk(KERN_INFO "htc-acoustic: "fmt, ##args) +#define E(fmt, args...) printk(KERN_ERR "htc-acoustic: "fmt, ##args) + +struct set_smem_req { + struct rpc_request_hdr hdr; + uint32_t size; +}; + +struct set_smem_rep { + struct rpc_reply_hdr hdr; + int n; +}; + +struct set_acoustic_req { + struct rpc_request_hdr hdr; +}; -#define HTC_ACOUSTIC_TABLE_BASE_PHY_ADDR_START (0x01FE0000) -#define HTC_ACOUSTIC_TABLE_SIZE (0x10000) +struct set_acoustic_rep { + struct rpc_reply_hdr hdr; + int n; +}; -#define ACOUSTICE(x...) printk(KERN_ERR "[ACOUSTIC] " x) +static uint32_t htc_acoustic_vir_addr; +static struct msm_rpc_endpoint *endpoint; +static struct mutex api_lock; static int acoustic_mmap(struct file *file, struct vm_area_struct *vma) { - unsigned long pgoff; - size_t size = vma->vm_end - vma->vm_start; - - if (vma->vm_pgoff != 0) - return -EINVAL; - - if (size <= HTC_ACOUSTIC_TABLE_SIZE) - pgoff = HTC_ACOUSTIC_TABLE_BASE_PHY_ADDR_START >> PAGE_SHIFT; - else - return -EINVAL; + unsigned long pgoff, delta; + int rc = -EINVAL; + size_t size; + + D("mmap\n"); + + mutex_lock(&api_lock); + + size = vma->vm_end - vma->vm_start; + if (vma->vm_pgoff != 0) { + E("mmap failed: page offset %lx\n", vma->vm_pgoff); + goto done; + } + + if (!htc_acoustic_vir_addr) { + E("mmap failed: smem region not allocated\n"); + rc = -EIO; + goto done; + } + + pgoff = MSM_SHARED_RAM_PHYS + + (htc_acoustic_vir_addr - (uint32_t)MSM_SHARED_RAM_BASE); + delta = PAGE_ALIGN(pgoff) - pgoff; + + if (size + delta > HTC_ACOUSTIC_TABLE_SIZE) { + E("mmap failed: size %d\n", size); + goto done; + } + + pgoff += delta; vma->vm_flags |= VM_IO | VM_RESERVED; - if (io_remap_pfn_range(vma, vma->vm_start, pgoff, - size, vma->vm_page_prot)) - return -EAGAIN; - - return 0; + rc = io_remap_pfn_range(vma, vma->vm_start, pgoff >> PAGE_SHIFT, + size, vma->vm_page_prot); + + if (rc < 0) + E("mmap failed: remap error %d\n", rc); + +done: mutex_unlock(&api_lock); + return rc; } static int acoustic_open(struct inode *inode, struct file *file) { - return 0; + int rc = -EIO; + struct set_smem_req req_smem; + struct set_smem_rep rep_smem; + + D("open\n"); + + mutex_lock(&api_lock); + + if (!htc_acoustic_vir_addr) { + if (endpoint == NULL) { + endpoint = msm_rpc_connect(HTCRPOG, HTCVERS, 0); + if (IS_ERR(endpoint)) { + E("init rpc failed! rc = %ld\n", + PTR_ERR(endpoint)); + endpoint = NULL; + goto done; + } + } + + req_smem.size = cpu_to_be32(HTC_ACOUSTIC_TABLE_SIZE); + rc = msm_rpc_call_reply(endpoint, + ONCRPC_ALLOC_ACOUSTIC_MEM_PROC, + &req_smem, sizeof(req_smem), + &rep_smem, sizeof(rep_smem), + 5 * HZ); + + if (rep_smem.n != 0 || rc < 0) { + E("open failed: ALLOC_ACOUSTIC_MEM_PROC error %d.\n", + rc); + goto done; + } + htc_acoustic_vir_addr = + (uint32_t)smem_alloc(SMEM_ID_VENDOR1, + HTC_ACOUSTIC_TABLE_SIZE); + if (!htc_acoustic_vir_addr) { + E("open failed: smem_alloc error\n"); + goto done; + } + } + + rc = 0; +done: + mutex_unlock(&api_lock); + return rc; } static int acoustic_release(struct inode *inode, struct file *file) { + D("release\n"); + return 0; +} + +static long acoustic_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + int rc, reply_value; + struct set_acoustic_req req; + struct set_acoustic_rep rep; + + D("ioctl\n"); + + mutex_lock(&api_lock); + + switch (cmd) { + case ACOUSTIC_ARM11_DONE: + D("ioctl: ACOUSTIC_ARM11_DONE called %d.\n", current->pid); + rc = msm_rpc_call_reply(endpoint, + ONCRPC_ACOUSTIC_INIT_PROC, &req, + sizeof(req), &rep, sizeof(rep), + 5 * HZ); + + reply_value = be32_to_cpu(rep.n); + if (reply_value != 0 || rc < 0) { + E("ioctl failed: ONCRPC_ACOUSTIC_INIT_PROC "\ + "error %d.\n", rc); + if (rc >= 0) + rc = -EIO; + break; + } + D("ioctl: ONCRPC_ACOUSTIC_INIT_PROC success.\n"); + break; + default: + E("ioctl: invalid command\n"); + rc = -EINVAL; + } + + mutex_unlock(&api_lock); return 0; } - + + static struct file_operations acoustic_fops = { .owner = THIS_MODULE, .open = acoustic_open, .release = acoustic_release, .mmap = acoustic_mmap, + .unlocked_ioctl = acoustic_ioctl, }; static struct miscdevice acoustic_misc = { @@ -71,29 +222,18 @@ static struct miscdevice acoustic_misc = { static int __init acoustic_init(void) { - int ret; - - ret = misc_register(&acoustic_misc); - if (ret < 0) { - ACOUSTICE("failed to register misc device!\n"); - return ret; - } - - return 0; + mutex_init(&api_lock); + return misc_register(&acoustic_misc); } static void __exit acoustic_exit(void) { - int ret; - - ret = misc_deregister(&acoustic_misc); - if (ret < 0) - ACOUSTICE("failed to unregister misc device!\n"); + misc_deregister(&acoustic_misc); } module_init(acoustic_init); module_exit(acoustic_exit); - + MODULE_AUTHOR("Laurence Chen "); MODULE_DESCRIPTION("HTC acoustic driver"); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From e0329438b0d67e512bab75b4840e8e867ea8413d Mon Sep 17 00:00:00 2001 From: Saravana Kannan Date: Fri, 14 Nov 2008 19:33:36 -0800 Subject: [ARM] msm: acpuclock: Remove VDD check during init. The VDD register reflects the status of the PMIC only after the application processor has written to it. This is not the case after a reset or power collapse since it is the modem processor that sets up the PMIC. Hence, the VDD register is no longer used to verify the current VDD level during init (boot up). Acked-by: Steve Muckle --- arch/arm/mach-msm/acpuclock.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/acpuclock.c b/arch/arm/mach-msm/acpuclock.c index 6ea137be23e8..59c91f7150c1 100644 --- a/arch/arm/mach-msm/acpuclock.c +++ b/arch/arm/mach-msm/acpuclock.c @@ -380,7 +380,7 @@ out: static void __init acpuclk_init(void) { struct clkctl_acpu_speed *speed; - uint32_t div, sel, current_vdd; + uint32_t div, sel; /* * Determine the rate of ACPU clock @@ -411,14 +411,6 @@ static void __init acpuclk_init(void) drv_state.current_speed = speed; printk(KERN_INFO "ACPU running at %d KHz\n", speed->a11clk_khz); - /* - * Ensure that the current freq is okay at this VDD. Earlier - * versions of the bootloader would not update VDD properly. - */ - current_vdd = readl(A11S_VDD_SVS_PLEVEL_ADDR) & 0x07; - if (speed->vdd != current_vdd) - printk(KERN_WARNING "WARNING - Bad VDD (%d != %d) for this freq\n", - current_vdd, speed->vdd); } unsigned long acpuclk_get_rate(void) -- cgit v1.2.3 From a5239d6260820a05ca148b43c1ca0fa655795775 Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Tue, 17 Feb 2009 14:35:27 -0800 Subject: [ARM] msm: htc_pwrsink: Generify driver Signed-off-by: San Mehat --- arch/arm/mach-msm/Kconfig | 4 +- arch/arm/mach-msm/Makefile | 3 +- arch/arm/mach-msm/htc_pwrsink.c | 194 +++++++++++++++++++++---- arch/arm/mach-msm/include/mach/htc_pwrsink.h | 88 +++++++++++ arch/arm/mach-msm/include/mach/trout_pwrsink.h | 58 -------- 5 files changed, 256 insertions(+), 91 deletions(-) create mode 100644 arch/arm/mach-msm/include/mach/htc_pwrsink.h delete mode 100644 arch/arm/mach-msm/include/mach/trout_pwrsink.h (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index 7ad1d8f92c78..e080df74cdbd 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -76,10 +76,10 @@ config TROUT_BATTCHG default y bool "Trout battery / charger driver" -config TROUT_PWRSINK +config HTC_PWRSINK depends on MSM_SMD default y - bool "Trout Power Sink Driver" + bool "HTC Power Sink Driver" choice prompt "Default Timer" diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 8491964fb860..72c8d5c1de60 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -24,5 +24,6 @@ obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o board-halibut-keypad.o obj-$(CONFIG_MACH_TROUT) += htc_akm_cal.o htc_wifi_nvs.o htc_acoustic.o obj-$(CONFIG_MACH_TROUT) += board-trout-mmc.o board-trout-wifi.o obj-$(CONFIG_TROUT_BATTCHG) += htc_battery.o -obj-$(CONFIG_TROUT_PWRSINK) += htc_pwrsink.o + +obj-$(CONFIG_HTC_PWRSINK) += htc_pwrsink.o obj-$(CONFIG_HTC_HEADSET) += htc_headset.o diff --git a/arch/arm/mach-msm/htc_pwrsink.c b/arch/arm/mach-msm/htc_pwrsink.c index 6ce6fb473773..2ec2c7f4bb1b 100644 --- a/arch/arm/mach-msm/htc_pwrsink.c +++ b/arch/arm/mach-msm/htc_pwrsink.c @@ -23,17 +23,28 @@ #include #include #include -#include +#include #include "smd_private.h" -static int initialized = 0; +enum { + PWRSINK_DEBUG_CURR_CHANGE = 1U << 0, + PWRSINK_DEBUG_CURR_CHANGE_AUDIO = 1U << 1, +}; +static int pwrsink_debug_mask; +module_param_named(debug_mask, pwrsink_debug_mask, int, + S_IRUGO | S_IWUSR | S_IWGRP); + +static int initialized; +static unsigned audio_path = 1; /* HTC_SND_DEVICE_SPEAKER = 1 */ +static struct pwr_sink_audio audio_sink_array[PWRSINK_AUDIO_LAST + 1]; static struct pwr_sink *sink_array[PWRSINK_LAST + 1]; static DEFINE_SPINLOCK(sink_lock); +static DEFINE_SPINLOCK(audio_sink_lock); static unsigned long total_sink; static uint32_t *smem_total_sink; -int trout_pwrsink_set(pwrsink_id_type id, unsigned percent_utilized) +int htc_pwrsink_set(pwrsink_id_type id, unsigned percent_utilized) { unsigned long flags; @@ -67,7 +78,7 @@ int trout_pwrsink_set(pwrsink_id_type id, unsigned percent_utilized) if (smem_total_sink) *smem_total_sink = total_sink / 1000; - pr_debug("trout_pwrsink: ID %d, Util %d%%, Total %lu uA %s\n", + pr_debug("htc_pwrsink: ID %d, Util %d%%, Total %lu uA %s\n", id, percent_utilized, total_sink, smem_total_sink ? "SET" : ""); @@ -75,73 +86,196 @@ int trout_pwrsink_set(pwrsink_id_type id, unsigned percent_utilized) return 0; } -EXPORT_SYMBOL(trout_pwrsink_set); +EXPORT_SYMBOL(htc_pwrsink_set); -void trout_pwrsink_suspend_early(struct early_suspend *h) +static void compute_audio_current(void) { - trout_pwrsink_set(PWRSINK_SYSTEM_LOAD, 70); + /* unsigned long flags; */ + unsigned max_percent = 0; + int i, active_audio_sinks = 0; + pwrsink_audio_id_type last_active_audio_sink = 0; + + /* Make sure this segment will be spinlocked + before computing by calling function. */ + /* spin_lock_irqsave(&audio_sink_lock, flags); */ + for (i = 0; i <= PWRSINK_AUDIO_LAST; ++i) { + max_percent = (audio_sink_array[i].percent > max_percent) ? + audio_sink_array[i].percent : max_percent; + if (audio_sink_array[i].percent > 0) { + active_audio_sinks++; + last_active_audio_sink = i; + } + } + if (active_audio_sinks == 0) + htc_pwrsink_set(PWRSINK_AUDIO, 0); + else if (active_audio_sinks == 1) { + pwrsink_audio_id_type laas = last_active_audio_sink; + /* TODO: add volume and routing path current. */ + if (audio_path == 1) /* Speaker */ + htc_pwrsink_set(PWRSINK_AUDIO, + audio_sink_array[laas].percent); + else + htc_pwrsink_set(PWRSINK_AUDIO, + audio_sink_array[laas].percent * 9 / 10); + } else if (active_audio_sinks > 1) { + /* TODO: add volume and routing path current. */ + if (audio_path == 1) /* Speaker */ + htc_pwrsink_set(PWRSINK_AUDIO, max_percent); + else + htc_pwrsink_set(PWRSINK_AUDIO, max_percent * 9 / 10); + } + /* spin_unlock_irqrestore(&audio_sink_lock, flags); */ + + if (pwrsink_debug_mask & PWRSINK_DEBUG_CURR_CHANGE_AUDIO) + pr_info("%s: active_audio_sinks=%d, audio_path=%d\n", __func__, + active_audio_sinks, audio_path); } -int trout_pwrsink_suspend_late(struct platform_device *pdev, pm_message_t state) +int htc_pwrsink_audio_set(pwrsink_audio_id_type id, unsigned percent_utilized) { - trout_pwrsink_set(PWRSINK_SYSTEM_LOAD, 13); + unsigned long flags; + + if (id < 0 || id > PWRSINK_AUDIO_LAST) + return -EINVAL; + + if (pwrsink_debug_mask & PWRSINK_DEBUG_CURR_CHANGE_AUDIO) + pr_info("%s: id=%d, percent=%d, percent_old=%d\n", __func__, + id, percent_utilized, audio_sink_array[id].percent); + + spin_lock_irqsave(&audio_sink_lock, flags); + if (audio_sink_array[id].percent == percent_utilized) { + spin_unlock_irqrestore(&audio_sink_lock, flags); + return 0; + } + audio_sink_array[id].percent = percent_utilized; + spin_unlock_irqrestore(&audio_sink_lock, flags); + compute_audio_current(); return 0; } +EXPORT_SYMBOL(htc_pwrsink_audio_set); -int trout_pwrsink_resume_early(struct platform_device *pdev) +int htc_pwrsink_audio_volume_set(pwrsink_audio_id_type id, unsigned volume) { - trout_pwrsink_set(PWRSINK_SYSTEM_LOAD, 70); + unsigned long flags; + + if (id < 0 || id > PWRSINK_AUDIO_LAST) + return -EINVAL; + + if (pwrsink_debug_mask & PWRSINK_DEBUG_CURR_CHANGE_AUDIO) + pr_info("%s: id=%d, volume=%d, volume_old=%d\n", __func__, + id, volume, audio_sink_array[id].volume); + + spin_lock_irqsave(&audio_sink_lock, flags); + if (audio_sink_array[id].volume == volume) { + spin_unlock_irqrestore(&audio_sink_lock, flags); + return 0; + } + audio_sink_array[id].volume = volume; + spin_unlock_irqrestore(&audio_sink_lock, flags); + compute_audio_current(); return 0; } +EXPORT_SYMBOL(htc_pwrsink_audio_volume_set); -void trout_pwrsink_resume_late(struct early_suspend *h) +int htc_pwrsink_audio_path_set(unsigned path) { - trout_pwrsink_set(PWRSINK_SYSTEM_LOAD, 100); + unsigned long flags; + + if (pwrsink_debug_mask & PWRSINK_DEBUG_CURR_CHANGE_AUDIO) + pr_info("%s: path=%d, path_old=%d\n", + __func__, path, audio_path); + + spin_lock_irqsave(&audio_sink_lock, flags); + if (audio_path == path) { + spin_unlock_irqrestore(&audio_sink_lock, flags); + return 0; + } + audio_path = path; + spin_unlock_irqrestore(&audio_sink_lock, flags); + compute_audio_current(); + return 0; +} +EXPORT_SYMBOL(htc_pwrsink_audio_path_set); + +void htc_pwrsink_suspend_early(struct early_suspend *h) +{ + htc_pwrsink_set(PWRSINK_SYSTEM_LOAD, 70); +} + +int htc_pwrsink_suspend_late(struct platform_device *pdev, pm_message_t state) +{ + struct pwr_sink_platform_data *pdata = pdev->dev.platform_data; + + if (pdata && pdata->suspend_late) + pdata->suspend_late(pdev, state); + else + htc_pwrsink_set(PWRSINK_SYSTEM_LOAD, 13); + return 0; } -struct early_suspend trout_pwrsink_early_suspend = { +int htc_pwrsink_resume_early(struct platform_device *pdev) +{ + struct pwr_sink_platform_data *pdata = pdev->dev.platform_data; + + if (pdata && pdata->resume_early) + pdata->resume_early(pdev); + else + htc_pwrsink_set(PWRSINK_SYSTEM_LOAD, 70); + return 0; +} + +void htc_pwrsink_resume_late(struct early_suspend *h) +{ + htc_pwrsink_set(PWRSINK_SYSTEM_LOAD, 100); +} + +struct early_suspend htc_pwrsink_early_suspend = { .level = EARLY_SUSPEND_LEVEL_DISABLE_FB + 1, - .suspend = trout_pwrsink_suspend_early, - .resume = trout_pwrsink_resume_late, + .suspend = htc_pwrsink_suspend_early, + .resume = htc_pwrsink_resume_late, }; -static int __init trout_pwrsink_probe(struct platform_device *pdev) +static int __init htc_pwrsink_probe(struct platform_device *pdev) { struct pwr_sink_platform_data *pdata = pdev->dev.platform_data; int i; - + if (!pdata) return -EINVAL; total_sink = 0; for (i = 0; i < pdata->num_sinks; i++) { sink_array[pdata->sinks[i].id] = &pdata->sinks[i]; - total_sink += (pdata->sinks[i].ua_max * pdata->sinks[i].percent_util / 100); + total_sink += (pdata->sinks[i].ua_max * + pdata->sinks[i].percent_util / 100); } initialized = 1; - register_early_suspend(&trout_pwrsink_early_suspend); - + if (pdata->suspend_early) + htc_pwrsink_early_suspend.suspend = pdata->suspend_early; + if (pdata->resume_late) + htc_pwrsink_early_suspend.resume = pdata->resume_late; + register_early_suspend(&htc_pwrsink_early_suspend); + return 0; } -static struct platform_driver trout_pwrsink_driver = { - .probe = trout_pwrsink_probe, - .suspend_late = trout_pwrsink_suspend_late, - .resume_early = trout_pwrsink_resume_early, +static struct platform_driver htc_pwrsink_driver = { + .probe = htc_pwrsink_probe, + .suspend_late = htc_pwrsink_suspend_late, + .resume_early = htc_pwrsink_resume_early, .driver = { - .name = "trout_pwrsink", + .name = "htc_pwrsink", .owner = THIS_MODULE, }, }; -static int __init trout_pwrsink_init(void) +static int __init htc_pwrsink_init(void) { initialized = 0; memset(sink_array, 0, sizeof(sink_array)); - return platform_driver_register(&trout_pwrsink_driver); + return platform_driver_register(&htc_pwrsink_driver); } -module_init(trout_pwrsink_init); - +module_init(htc_pwrsink_init); diff --git a/arch/arm/mach-msm/include/mach/htc_pwrsink.h b/arch/arm/mach-msm/include/mach/htc_pwrsink.h new file mode 100644 index 000000000000..d82c21273a45 --- /dev/null +++ b/arch/arm/mach-msm/include/mach/htc_pwrsink.h @@ -0,0 +1,88 @@ +/* include/asm/mach-msm/htc_pwrsink.h + * + * Copyright (C) 2007 Google, Inc. + * Copyright (C) 2008 HTC Corporation. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ +#ifndef _ARCH_ARM_MACH_MSM_HTC_PWRSINK_H_ +#define _ARCH_ARM_MACH_MSM_HTC_PWRSINK_H_ + +#include +#include + +typedef enum { + PWRSINK_AUDIO_PCM = 0, + PWRSINK_AUDIO_MP3, + PWRSINK_AUDIO_AAC, + + PWRSINK_AUDIO_LAST = PWRSINK_AUDIO_AAC, + PWRSINK_AUDIO_INVALID +} pwrsink_audio_id_type; + +struct pwr_sink_audio { + unsigned volume; + unsigned percent; +}; + +typedef enum { + PWRSINK_SYSTEM_LOAD = 0, + PWRSINK_AUDIO, + PWRSINK_BACKLIGHT, + PWRSINK_LED_BUTTON, + PWRSINK_LED_KEYBOARD, + PWRSINK_GP_CLK, + PWRSINK_BLUETOOTH, + PWRSINK_CAMERA, + PWRSINK_SDCARD, + PWRSINK_VIDEO, + PWRSINK_WIFI, + + PWRSINK_LAST = PWRSINK_WIFI, + PWRSINK_INVALID +} pwrsink_id_type; + +struct pwr_sink { + pwrsink_id_type id; + unsigned ua_max; + unsigned percent_util; +}; + +struct pwr_sink_platform_data { + unsigned num_sinks; + struct pwr_sink *sinks; + int (*suspend_late)(struct platform_device *, pm_message_t state); + int (*resume_early)(struct platform_device *); + void (*suspend_early)(struct early_suspend *); + void (*resume_late)(struct early_suspend *); +}; + +#ifndef CONFIG_HTC_PWRSINK +static inline int htc_pwrsink_set(pwrsink_id_type id, unsigned percent) +{ + printk(KERN_DEBUG "%s:STUB!\n", __func__); + return 0; +} +static inline int htc_pwrsink_audio_set(pwrsink_audio_id_type id, + unsigned percent_utilized) { return 0; } +static inline int htc_pwrsink_audio_volume_set( + pwrsink_audio_id_type id, unsigned volume) { return 0; } +static inline int htc_pwrsink_audio_path_set(unsigned path) { return 0; } +#else +extern int htc_pwrsink_set(pwrsink_id_type id, unsigned percent); +extern int htc_pwrsink_audio_set(pwrsink_audio_id_type id, + unsigned percent_utilized); +extern int htc_pwrsink_audio_volume_set(pwrsink_audio_id_type id, + unsigned volume); +extern int htc_pwrsink_audio_path_set(unsigned path); +#endif + +#endif diff --git a/arch/arm/mach-msm/include/mach/trout_pwrsink.h b/arch/arm/mach-msm/include/mach/trout_pwrsink.h deleted file mode 100644 index 265b329ac0cf..000000000000 --- a/arch/arm/mach-msm/include/mach/trout_pwrsink.h +++ /dev/null @@ -1,58 +0,0 @@ -/* include/asm/mach-msm/trout_pwrsink.h - * - * Copyright (C) 2007 Google, Inc. - * Copyright (C) 2008 HTC Corporation. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * 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. - * - */ -#ifndef _ARCH_ARM_MACH_MSM_TROUT_PWRSINK_H_ -#define _ARCH_ARM_MACH_MSM_TROUT_PWRSINK_H_ - -typedef enum { - PWRSINK_SYSTEM_LOAD = 0, - PWRSINK_AUDIO, - PWRSINK_BACKLIGHT, - PWRSINK_LED_BUTTON, - PWRSINK_LED_KEYBOARD, - PWRSINK_GP_CLK, - PWRSINK_BLUETOOTH, - PWRSINK_CAMERA, - PWRSINK_SDCARD, - PWRSINK_VIDEO, - PWRSINK_WIFI, - - PWRSINK_LAST = PWRSINK_WIFI, - PWRSINK_INVALID -} pwrsink_id_type; - -struct pwr_sink { - pwrsink_id_type id; - unsigned ua_max; - unsigned percent_util; -}; - -struct pwr_sink_platform_data { - unsigned num_sinks; - struct pwr_sink *sinks; -}; - -#ifndef CONFIG_TROUT_PWRSINK -static inline int trout_pwrsink_set(pwrsink_id_type id, unsigned percent) -{ -printk("%s:STUB!\n", __func__); - return 0; -} -#else -extern int trout_pwrsink_set(pwrsink_id_type id, unsigned percent); -#endif - -#endif - -- cgit v1.2.3 From 753bb9126a4a3bcae46b7e686e991a6a91bb1f89 Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Tue, 17 Feb 2009 14:42:56 -0800 Subject: [ARM]: trout: Switch from trout_pwrsink -> htc_pwrsink Signed-off-by: San Mehat --- arch/arm/mach-msm/board-trout-gpio.c | 6 +++--- arch/arm/mach-msm/board-trout-mmc.c | 6 +++--- arch/arm/mach-msm/board-trout-panel.c | 10 ++-------- arch/arm/mach-msm/board-trout.c | 12 ++++++++---- 4 files changed, 16 insertions(+), 18 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/board-trout-gpio.c b/arch/arm/mach-msm/board-trout-gpio.c index 07d371b45ec8..527379ec3597 100644 --- a/arch/arm/mach-msm/board-trout-gpio.c +++ b/arch/arm/mach-msm/board-trout-gpio.c @@ -23,7 +23,7 @@ #include #include -#include +#include #include "board-trout.h" #include "gpio_chip.h" @@ -70,10 +70,10 @@ static void update_pwrsink(unsigned gpio, unsigned on) { switch(gpio) { case TROUT_GPIO_UI_LED_EN: - trout_pwrsink_set(PWRSINK_LED_BUTTON, on ? 100 : 0); + htc_pwrsink_set(PWRSINK_LED_BUTTON, on ? 100 : 0); break; case TROUT_GPIO_QTKEY_LED_EN: - trout_pwrsink_set(PWRSINK_LED_KEYBOARD, on ? 100 : 0); + htc_pwrsink_set(PWRSINK_LED_KEYBOARD, on ? 100 : 0); break; } } diff --git a/arch/arm/mach-msm/board-trout-mmc.c b/arch/arm/mach-msm/board-trout-mmc.c index ba759293ff03..f417fa4f4152 100644 --- a/arch/arm/mach-msm/board-trout-mmc.c +++ b/arch/arm/mach-msm/board-trout-mmc.c @@ -15,7 +15,7 @@ #include #include -#include +#include #include @@ -264,11 +264,11 @@ int trout_wifi_power(int on) rc = vreg_enable(vreg_wifi_osc); if (rc) return rc; - trout_pwrsink_set(PWRSINK_WIFI, 70); + htc_pwrsink_set(PWRSINK_WIFI, 70); } else { config_gpio_table(wifi_off_gpio_table, ARRAY_SIZE(wifi_off_gpio_table)); - trout_pwrsink_set(PWRSINK_WIFI, 0); + htc_pwrsink_set(PWRSINK_WIFI, 0); } gpio_set_value( TROUT_GPIO_MAC_32K_EN, on); mdelay(100); diff --git a/arch/arm/mach-msm/board-trout-panel.c b/arch/arm/mach-msm/board-trout-panel.c index 8b350d1a382c..900b8b1a6f76 100644 --- a/arch/arm/mach-msm/board-trout-panel.c +++ b/arch/arm/mach-msm/board-trout-panel.c @@ -16,9 +16,7 @@ #include #include -#ifdef CONFIG_TROUT_PWRSINK -#include -#endif +#include #include "board-trout.h" #include "proc_comm.h" @@ -35,9 +33,7 @@ static DEFINE_MUTEX(trout_backlight_lock); static void trout_set_backlight_level(uint8_t level) { -#ifdef CONFIG_TROUT_PWRSINK unsigned percent = ((int)level * 100) / 255; -#endif if (trout_new_backlight) { unsigned long flags; @@ -87,9 +83,7 @@ static void trout_set_backlight_level(uint8_t level) clk_disable(gp_clk); } } -#ifdef CONFIG_TROUT_PWRSINK - trout_pwrsink_set(PWRSINK_BACKLIGHT, percent); -#endif + htc_pwrsink_set(PWRSINK_BACKLIGHT, percent); } #define MDDI_CLIENT_CORE_BASE 0x108000 diff --git a/arch/arm/mach-msm/board-trout.c b/arch/arm/mach-msm/board-trout.c index ed8023cfae38..986a6ec5b0d6 100644 --- a/arch/arm/mach-msm/board-trout.c +++ b/arch/arm/mach-msm/board-trout.c @@ -66,7 +66,7 @@ #include #include #include -#include +#include #ifdef CONFIG_HTC_HEADSET #include #endif @@ -625,12 +625,16 @@ static struct pwr_sink trout_pwrsink_table[] = { static struct pwr_sink_platform_data trout_pwrsink_data = { .num_sinks = ARRAY_SIZE(trout_pwrsink_table), .sinks = trout_pwrsink_table, + .suspend_late = NULL, + .resume_early = NULL, + .suspend_early = NULL, + .resume_late = NULL, }; static struct platform_device trout_pwr_sink = { - .name = "trout_pwrsink", + .name = "htc_pwrsink", .id = -1, - .dev = { + .dev = { .platform_data = &trout_pwrsink_data, }, }; @@ -748,7 +752,7 @@ static struct platform_device *devices[] __initdata = { #ifdef CONFIG_HTC_HEADSET &trout_h2w, #endif -#if defined(CONFIG_TROUT_PWRSINK) +#ifdef CONFIG_HTC_PWRSINK &trout_pwr_sink, #endif &trout_snd, -- cgit v1.2.3 From e41d82cca4321dbdb7ada1267cc7b0c202892372 Mon Sep 17 00:00:00 2001 From: Thomas Tsai Date: Tue, 17 Feb 2009 15:16:30 -0800 Subject: [ARM] msm: vibrator: Initial support for MSM PMIC vibrator Signed-off-by: San Mehat --- arch/arm/mach-msm/msm_vibrator.c | 137 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 arch/arm/mach-msm/msm_vibrator.c (limited to 'arch') diff --git a/arch/arm/mach-msm/msm_vibrator.c b/arch/arm/mach-msm/msm_vibrator.c new file mode 100644 index 000000000000..f4da4363aa98 --- /dev/null +++ b/arch/arm/mach-msm/msm_vibrator.c @@ -0,0 +1,137 @@ +/* include/asm/mach-msm/htc_pwrsink.h + * + * Copyright (C) 2008 HTC Corporation. + * Copyright (C) 2007 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 <../../../drivers/staging/android/timed_output.h> +#include + +#include + +#define PM_LIBPROG 0x30000061 +#if (CONFIG_MSM_AMSS_VERSION == 6220) || (CONFIG_MSM_AMSS_VERSION == 6225) +#define PM_LIBVERS 0xfb837d0b +#else +#define PM_LIBVERS 0x10001 +#endif + +#define HTC_PROCEDURE_SET_VIB_ON_OFF 21 +#define PMIC_VIBRATOR_LEVEL (3000) + +static struct work_struct work_vibrator_on; +static struct work_struct work_vibrator_off; +static struct hrtimer vibe_timer; + +static void set_pmic_vibrator(int on) +{ + static struct msm_rpc_endpoint *vib_endpoint; + struct set_vib_on_off_req { + struct rpc_request_hdr hdr; + uint32_t data; + } req; + + if (!vib_endpoint) { + vib_endpoint = msm_rpc_connect(PM_LIBPROG, PM_LIBVERS, 0); + if (IS_ERR(vib_endpoint)) { + printk(KERN_ERR "init vib rpc failed!\n"); + vib_endpoint = 0; + return; + } + } + + + if (on) + req.data = cpu_to_be32(PMIC_VIBRATOR_LEVEL); + else + req.data = cpu_to_be32(0); + + msm_rpc_call(vib_endpoint, HTC_PROCEDURE_SET_VIB_ON_OFF, &req, + sizeof(req), 5 * HZ); +} + +static void pmic_vibrator_on(struct work_struct *work) +{ + set_pmic_vibrator(1); +} + +static void pmic_vibrator_off(struct work_struct *work) +{ + set_pmic_vibrator(0); +} + +static void timed_vibrator_on(struct timed_output_dev *sdev) +{ + schedule_work(&work_vibrator_on); +} + +static void timed_vibrator_off(struct timed_output_dev *sdev) +{ + schedule_work(&work_vibrator_off); +} + +static void vibrator_enable(struct timed_output_dev *dev, int value) +{ + hrtimer_cancel(&vibe_timer); + + if (value == 0) + timed_vibrator_off(dev); + else { + value = (value > 15000 ? 15000 : value); + + timed_vibrator_on(dev); + + hrtimer_start(&vibe_timer, + ktime_set(value / 1000, (value % 1000) * 1000000), + HRTIMER_MODE_REL); + } +} + +static int vibrator_get_time(struct timed_output_dev *dev) +{ + if (hrtimer_active(&vibe_timer)) { + ktime_t r = hrtimer_get_remaining(&vibe_timer); + return r.tv.sec * 1000 + r.tv.nsec / 1000000; + } else + return 0; +} + +static enum hrtimer_restart vibrator_timer_func(struct hrtimer *timer) +{ + timed_vibrator_off(NULL); + return HRTIMER_NORESTART; +} + +static struct timed_output_dev pmic_vibrator = { + .name = "vibrator", + .get_time = vibrator_get_time, + .enable = vibrator_enable, +}; + +void __init msm_init_pmic_vibrator(void) +{ + INIT_WORK(&work_vibrator_on, pmic_vibrator_on); + INIT_WORK(&work_vibrator_off, pmic_vibrator_off); + + hrtimer_init(&vibe_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + vibe_timer.function = vibrator_timer_func; + + timed_output_dev_register(&pmic_vibrator); +} + +MODULE_DESCRIPTION("timed output pmic vibrator device"); +MODULE_LICENSE("GPL"); + -- cgit v1.2.3 From f65bcfc24418203a27acdbc88a6e268fd0278c65 Mon Sep 17 00:00:00 2001 From: Thomas Tsai Date: Wed, 18 Feb 2009 08:34:13 -0800 Subject: [ARM] msm: FIQ: Add ability to unselect an FIQ IRQ Signed-off-by: San Mehat --- arch/arm/mach-msm/include/mach/fiq.h | 1 + arch/arm/mach-msm/irq.c | 12 ++++++++++++ 2 files changed, 13 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/include/mach/fiq.h b/arch/arm/mach-msm/include/mach/fiq.h index a272c890c68a..29a3ba1f33f3 100644 --- a/arch/arm/mach-msm/include/mach/fiq.h +++ b/arch/arm/mach-msm/include/mach/fiq.h @@ -18,6 +18,7 @@ /* cause an interrupt to be an FIQ instead of a regular IRQ */ void msm_fiq_select(int number); +void msm_fiq_unselect(int number); /* enable/disable an interrupt that is an FIQ (not safe from FIQ context) */ void msm_fiq_enable(int number); diff --git a/arch/arm/mach-msm/irq.c b/arch/arm/mach-msm/irq.c index a8f20a45432f..cb4bda509879 100644 --- a/arch/arm/mach-msm/irq.c +++ b/arch/arm/mach-msm/irq.c @@ -484,6 +484,18 @@ void msm_fiq_select(int irq) local_irq_restore(flags); } +void msm_fiq_unselect(int irq) +{ + void __iomem *reg = VIC_INT_SELECT0 + ((irq & 32) ? 4 : 0); + unsigned index = (irq >> 5) & 1; + uint32_t mask = 1UL << (irq & 31); + unsigned long flags; + + local_irq_save(flags); + msm_irq_shadow_reg[index].int_select &= (!mask); + writel(msm_irq_shadow_reg[index].int_select, reg); + local_irq_restore(flags); +} /* set_fiq_handler originally from arch/arm/kernel/fiq.c */ static void set_fiq_handler(void *start, unsigned int length) { -- cgit v1.2.3 From 8eae5059d496e03829cee2a4c29f213eba7ff916 Mon Sep 17 00:00:00 2001 From: Thomas Tsai Date: Wed, 18 Feb 2009 09:03:23 -0800 Subject: [ARM] msm: iomap: Add entries for HSUSB_BASE, SSBI, and TSSC Signed-off-by: San Mehat --- arch/arm/mach-msm/include/mach/msm_iomap.h | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/include/mach/msm_iomap.h b/arch/arm/mach-msm/include/mach/msm_iomap.h index 9dae1a98c77a..ea107948e3dc 100644 --- a/arch/arm/mach-msm/include/mach/msm_iomap.h +++ b/arch/arm/mach-msm/include/mach/msm_iomap.h @@ -112,6 +112,7 @@ #define MSM_I2C_SIZE SZ_4K #define MSM_HSUSB_PHYS 0xA0800000 +#define MSM_HSUSB_BASE IOMEM(0xE0009000) #define MSM_HSUSB_SIZE SZ_4K #define MSM_PMDH_PHYS 0xAA600000 @@ -130,4 +131,12 @@ #define MSM_AD5_SIZE (SZ_1M*13) +#define MSM_SSBI_BASE IOMEM(0xE1004000) +#define MSM_SSBI_PHYS 0xA8100000 +#define MSM_SSBI_SIZE SZ_4K + +#define MSM_TSSC_BASE IOMEM(0xE1005000) +#define MSM_TSSC_PHYS 0xAA300000 +#define MSM_TSSC_SIZE SZ_4K + #endif -- cgit v1.2.3 From b6bae7e2a087bee84c635b5ed7879e50bf25dbf6 Mon Sep 17 00:00:00 2001 From: San Mehat Date: Wed, 18 Feb 2009 09:16:50 -0800 Subject: [ARM] sapphire: Initial import of Sapphire board support Signed-off-by: Thomas Tsai Signed-off-by: San Mehat --- arch/arm/mach-msm/Kconfig | 5 + arch/arm/mach-msm/Makefile | 6 + arch/arm/mach-msm/board-sapphire-gpio.c | 326 ++++++++ arch/arm/mach-msm/board-sapphire-h2w.c | 545 +++++++++++++ arch/arm/mach-msm/board-sapphire-keypad.c | 122 +++ arch/arm/mach-msm/board-sapphire-mmc.c | 479 ++++++++++++ arch/arm/mach-msm/board-sapphire-panel.c | 656 ++++++++++++++++ arch/arm/mach-msm/board-sapphire-rfkill.c | 99 +++ arch/arm/mach-msm/board-sapphire-wifi.c | 74 ++ arch/arm/mach-msm/board-sapphire.c | 1175 ++++++++++++++++++++++++++++ arch/arm/mach-msm/board-sapphire.h | 219 ++++++ arch/arm/mach-msm/devices_htc.c | 434 ++++++++++ arch/arm/mach-msm/include/mach/board_htc.h | 78 ++ 13 files changed, 4218 insertions(+) create mode 100644 arch/arm/mach-msm/board-sapphire-gpio.c create mode 100644 arch/arm/mach-msm/board-sapphire-h2w.c create mode 100644 arch/arm/mach-msm/board-sapphire-keypad.c create mode 100644 arch/arm/mach-msm/board-sapphire-mmc.c create mode 100644 arch/arm/mach-msm/board-sapphire-panel.c create mode 100644 arch/arm/mach-msm/board-sapphire-rfkill.c create mode 100644 arch/arm/mach-msm/board-sapphire-wifi.c create mode 100644 arch/arm/mach-msm/board-sapphire.c create mode 100644 arch/arm/mach-msm/board-sapphire.h create mode 100644 arch/arm/mach-msm/devices_htc.c create mode 100644 arch/arm/mach-msm/include/mach/board_htc.h (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index e080df74cdbd..407ca114ea4e 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -63,6 +63,11 @@ config MACH_TROUT help Support for the HTC Dream, T-Mobile G1, Android ADP1 devices. +config MACH_SAPPHIRE + depends on ARCH_MSM + default y + bool "Sapphire" + config HTC_HEADSET tristate "HTC 2 Wire detection driver" default n diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 72c8d5c1de60..1618d2929177 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -1,5 +1,6 @@ obj-y += io.o idle.o irq.o timer.o dma.o obj-y += devices.o +obj-y += devices_htc.o obj-y += proc_comm.o obj-y += vreg.o obj-y += acpuclock.o @@ -23,6 +24,11 @@ obj-$(CONFIG_MACH_TROUT) += board-dream.o obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o board-halibut-keypad.o obj-$(CONFIG_MACH_TROUT) += htc_akm_cal.o htc_wifi_nvs.o htc_acoustic.o obj-$(CONFIG_MACH_TROUT) += board-trout-mmc.o board-trout-wifi.o +obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire.o board-sapphire-gpio.o +obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire-keypad.o board-sapphire-panel.o +obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire-mmc.o board-sapphire-wifi.o +obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire-rfkill.o msm_vibrator.o + obj-$(CONFIG_TROUT_BATTCHG) += htc_battery.o obj-$(CONFIG_HTC_PWRSINK) += htc_pwrsink.o diff --git a/arch/arm/mach-msm/board-sapphire-gpio.c b/arch/arm/mach-msm/board-sapphire-gpio.c new file mode 100644 index 000000000000..2f2df97956cf --- /dev/null +++ b/arch/arm/mach-msm/board-sapphire-gpio.c @@ -0,0 +1,326 @@ +/* arch/arm/mach-msm/board-sapphire-gpio.c + * Copyright (C) 2007-2009 HTC Corporation. + * Author: Thomas Tsai + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 "gpio_chip.h" +#include "board-sapphire.h" + +#ifdef DEBUG_SAPPHIRE_GPIO +#define DBG(fmt, arg...) printk(KERN_INFO "%s: " fmt "\n", __func__, ## arg) +#else +#define DBG(fmt, arg...) do {} while (0) +#endif + +#define SAPPHIRE_CPLD_INT_STATUS (SAPPHIRE_CPLD_BASE + 0x0E) +#define SAPPHIRE_CPLD_INT_LEVEL (SAPPHIRE_CPLD_BASE + 0x08) +#define SAPPHIRE_CPLD_INT_MASK (SAPPHIRE_CPLD_BASE + 0x0C) + +/*CPLD misc reg offset*/ +static const int _g_CPLD_MISCn_Offset[] = { 0x0A, /*misc1 reg*/ + 0x00, /*misc2 reg*/ + 0x02, /*misc3 reg*/ + 0x04, /*misc4 reg*/ + 0x06}; /*misc5 reg*/ +/*CPLD INT Bank*/ +/*BANK0: int1 status, int2 level, int3 mask*/ +static const int _g_INT_BANK_Offset[][3] = {{0x0E, 0x08, 0x0C} }; + +static uint8_t sapphire_cpld_initdata[4] = { + [0] = 0x80, /* for serial debug UART3, low current misc2*/ + [1] = 0x34, /* jog & tp enable, I2C pull misc3*/ + [3] = 0x04, /* mmdi 32k en misc5*/ +}; + +/*save current working int mask, so the value can be restored after resume. +Sapphire has only bank0.*/ +static uint8_t sapphire_int_mask[] = { + [0] = 0xfb, /* enable all interrupts, bit 2 is not used */ +}; + +/*Sleep have to prepare the wake up source in advance. +default to disable all wakeup sources when suspend.*/ +static uint8_t sapphire_sleep_int_mask[] = { + [0] = 0x00, /* bit2 is not used */ +}; + +static int sapphire_suspended; + +static int sapphire_gpio_read(struct gpio_chip *chip, unsigned n) +{ + if (n < SAPPHIRE_GPIO_INT_B0_BASE) /*MISCn*/ + return !!(readb(CPLD_GPIO_REG(n)) & CPLD_GPIO_BIT_POS_MASK(n)); + else if (n <= SAPPHIRE_GPIO_END) /*gpio n is INT pin*/ + return !!(readb(CPLD_INT_LEVEL_REG_G(n)) & + CPLD_GPIO_BIT_POS_MASK(n)); + return 0; +} + +/*CPLD Write only register :MISC2, MISC3, MISC4, MISC5 => reg=0,2,4,6 +Reading from write-only registers is undefined, so the writing value +should be kept in shadow for later usage.*/ +int sapphire_gpio_write(struct gpio_chip *chip, unsigned n, unsigned on) +{ + unsigned long flags; + uint8_t reg_val; + if (n > SAPPHIRE_GPIO_END) + return -1; + + local_irq_save(flags); + reg_val = readb(CPLD_GPIO_REG(n)); + if (on) + reg_val |= CPLD_GPIO_BIT_POS_MASK(n); + else + reg_val &= ~CPLD_GPIO_BIT_POS_MASK(n); + writeb(reg_val, CPLD_GPIO_REG(n)); + + DBG("gpio=%d, l=0x%x\r\n", n, readb(SAPPHIRE_CPLD_INT_LEVEL)); + + local_irq_restore(flags); + + return 0; +} + +static int sapphire_gpio_configure(struct gpio_chip *chip, unsigned int gpio, + unsigned long flags) +{ + if (flags & (GPIOF_OUTPUT_LOW | GPIOF_OUTPUT_HIGH)) + sapphire_gpio_write(chip, gpio, flags & GPIOF_OUTPUT_HIGH); + + DBG("gpio=%d, l=0x%x\r\n", gpio, readb(SAPPHIRE_CPLD_INT_LEVEL)); + + return 0; +} + +static int sapphire_gpio_get_irq_num(struct gpio_chip *chip, unsigned int gpio, + unsigned int *irqp, unsigned long *irqnumflagsp) +{ + DBG("gpio=%d, l=0x%x\r\n", gpio, readb(SAPPHIRE_CPLD_INT_LEVEL)); + DBG("SAPPHIRE_GPIO_INT_B0_BASE=%d, SAPPHIRE_GPIO_LAST_INT=%d\r\n", + SAPPHIRE_GPIO_INT_B0_BASE, SAPPHIRE_GPIO_LAST_INT); + if ((gpio < SAPPHIRE_GPIO_INT_B0_BASE) || + (gpio > SAPPHIRE_GPIO_LAST_INT)) + return -ENOENT; + *irqp = SAPPHIRE_GPIO_TO_INT(gpio); + DBG("*irqp=%d\r\n", *irqp); + if (irqnumflagsp) + *irqnumflagsp = 0; + return 0; +} + +/*write 1 to clear INT status bit.*/ +static void sapphire_gpio_irq_ack(unsigned int irq) +{ + /*write 1 to clear*/ + writeb(SAPPHIRE_INT_BIT_MASK(irq), CPLD_INT_STATUS_REG(irq)); +} + +/*unmask/enable the INT +static void sapphire_gpio_irq_unmask(unsigned int irq)*/ +static void sapphire_gpio_irq_enable(unsigned int irq) +{ + unsigned long flags; + uint8_t reg_val; + + local_irq_save(flags); /*disabling all interrupts*/ + + reg_val = readb(CPLD_INT_MASK_REG(irq)) | SAPPHIRE_INT_BIT_MASK(irq); + DBG("(irq=%d,0x%x, 0x%x)\r\n", irq, CPLD_INT_MASK_REG(irq), + SAPPHIRE_INT_BIT_MASK(irq)); + DBG("sapphire_suspended=%d\r\n", sapphire_suspended); + /*printk(KERN_INFO "sapphire_gpio_irq_mask irq %d => %d:%02x\n", + irq, bank, reg_val);*/ + if (!sapphire_suspended) + writeb(reg_val, CPLD_INT_MASK_REG(irq)); + + reg_val = readb(CPLD_INT_MASK_REG(irq)); + DBG("reg_val= 0x%x\r\n", reg_val); + DBG("l=0x%x\r\n", readb(SAPPHIRE_CPLD_INT_LEVEL)); + + local_irq_restore(flags); /*restore the interrupts*/ +} + +/*mask/disable INT +static void sapphire_gpio_irq_mask(unsigned int irq)*/ +static void sapphire_gpio_irq_disable(unsigned int irq) +{ + unsigned long flags; + uint8_t reg_val; + + local_irq_save(flags); + reg_val = readb(CPLD_INT_MASK_REG(irq)) & ~SAPPHIRE_INT_BIT_MASK(irq); + /*CPLD INT MASK is r/w now.*/ + + /*printk(KERN_INFO "sapphire_gpio_irq_unmask irq %d => %d:%02x\n", + irq, bank, reg_val);*/ + DBG("(%d,0x%x, 0x%x, 0x%x)\r\n", irq, reg_val, CPLD_INT_MASK_REG(irq), + SAPPHIRE_INT_BIT_MASK(irq)); + DBG("sapphire_suspended=%d\r\n", sapphire_suspended); + if (!sapphire_suspended) + writeb(reg_val, CPLD_INT_MASK_REG(irq)); + + reg_val = readb(CPLD_INT_MASK_REG(irq)); + DBG("reg_val= 0x%x\r\n", reg_val); + DBG("l=0x%x\r\n", readb(SAPPHIRE_CPLD_INT_LEVEL)); + + local_irq_restore(flags); +} + +/*preparing enable/disable wake source before sleep*/ +int sapphire_gpio_irq_set_wake(unsigned int irq, unsigned int on) +{ + unsigned long flags; + uint8_t mask = SAPPHIRE_INT_BIT_MASK(irq); + + local_irq_save(flags); + + if (on) /*wake on -> mask the bit*/ + sapphire_sleep_int_mask[CPLD_INT_TO_BANK(irq)] |= mask; + else /*no wake -> unmask the bit*/ + sapphire_sleep_int_mask[CPLD_INT_TO_BANK(irq)] &= ~mask; + local_irq_restore(flags); + return 0; +} + +/*Sapphire has only one INT Bank.*/ +static void sapphire_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) +{ + int j; + unsigned v; + int int_base = SAPPHIRE_INT_START; + + v = readb(SAPPHIRE_CPLD_INT_STATUS); /*INT1 status reg, BANK0*/ + + for (j = 0; j < 8 ; j++) { /*8 bit per bank*/ + if (v & (1U << j)) { /*got the INT Bit*/ + DBG("generic_handle_irq j=0x%x\r\n", j); + generic_handle_irq(int_base + j); + } + } + + desc->chip->ack(irq); /*clear CPLD INT in SOC side.*/ + DBG("irq=%d, l=0x%x\r\n", irq, readb(SAPPHIRE_CPLD_INT_LEVEL)); +} + +/*Save current working sources before sleep, so we can restore it after + * resume.*/ +static int sapphire_sysdev_suspend(struct sys_device *dev, pm_message_t state) +{ + sapphire_suspended = 1; + /*save current masking*/ + sapphire_int_mask[0] = readb(SAPPHIRE_CPLD_BASE + + SAPPHIRE_GPIO_INT_B0_MASK_REG); + + /*set waking source before sleep.*/ + writeb(sapphire_sleep_int_mask[0], + SAPPHIRE_CPLD_BASE + SAPPHIRE_GPIO_INT_B0_MASK_REG); + + return 0; +} + +/*All the registers will be kept till a power loss...*/ +int sapphire_sysdev_resume(struct sys_device *dev) +{ + /*restore the working mask saved before sleep*/ + writeb(sapphire_int_mask[0], SAPPHIRE_CPLD_BASE + + SAPPHIRE_GPIO_INT_B0_MASK_REG); + sapphire_suspended = 0; + return 0; +} + +/** + * linux/irq.h :: struct irq_chip + * @enable: enable the interrupt (defaults to chip->unmask if NULL) + * @disable: disable the interrupt (defaults to chip->mask if NULL) + * @ack: start of a new interrupt + * @mask: mask an interrupt source + * @mask_ack: ack and mask an interrupt source + * @unmask: unmask an interrupt source + */ +static struct irq_chip sapphire_gpio_irq_chip = { + .name = "sapphiregpio", + .ack = sapphire_gpio_irq_ack, + .mask = sapphire_gpio_irq_disable, /*sapphire_gpio_irq_mask,*/ + .unmask = sapphire_gpio_irq_enable, /*sapphire_gpio_irq_unmask,*/ + .set_wake = sapphire_gpio_irq_set_wake, + /*.set_type = sapphire_gpio_irq_set_type,*/ +}; + +/*Thomas:For CPLD*/ +static struct gpio_chip sapphire_gpio_chip = { + .start = SAPPHIRE_GPIO_START, + .end = SAPPHIRE_GPIO_END, + .configure = sapphire_gpio_configure, + .get_irq_num = sapphire_gpio_get_irq_num, + .read = sapphire_gpio_read, + .write = sapphire_gpio_write, +/* .read_detect_status = sapphire_gpio_read_detect_status, + .clear_detect_status = sapphire_gpio_clear_detect_status */ +}; + +struct sysdev_class sapphire_sysdev_class = { + .name = "sapphiregpio_irq", + .suspend = sapphire_sysdev_suspend, + .resume = sapphire_sysdev_resume, +}; + +static struct sys_device sapphire_irq_device = { + .cls = &sapphire_sysdev_class, +}; + +int sapphire_init_gpio(void) +{ + int i; + if (!machine_is_sapphire()) + return 0; + + DBG("%d,%d\r\n", SAPPHIRE_INT_START, SAPPHIRE_INT_END); + DBG("NR_MSM_IRQS=%d, NR_GPIO_IRQS=%d\r\n", NR_MSM_IRQS, NR_GPIO_IRQS); + for (i = SAPPHIRE_INT_START; i <= SAPPHIRE_INT_END; i++) { + set_irq_chip(i, &sapphire_gpio_irq_chip); + set_irq_handler(i, handle_edge_irq); + set_irq_flags(i, IRQF_VALID); + } + + register_gpio_chip(&sapphire_gpio_chip); + + /*setup CPLD INT connecting to SOC's gpio 17 */ + set_irq_type(MSM_GPIO_TO_INT(17), IRQF_TRIGGER_HIGH); + set_irq_chained_handler(MSM_GPIO_TO_INT(17), sapphire_gpio_irq_handler); + set_irq_wake(MSM_GPIO_TO_INT(17), 1); + + if (sysdev_class_register(&sapphire_sysdev_class) == 0) + sysdev_register(&sapphire_irq_device); + + return 0; +} + +int sapphire_init_cpld(unsigned int sys_rev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(sapphire_cpld_initdata); i++) + writeb(sapphire_cpld_initdata[i], SAPPHIRE_CPLD_BASE + i * 2); + return 0; +} + +arch_initcall(sapphire_init_gpio); diff --git a/arch/arm/mach-msm/board-sapphire-h2w.c b/arch/arm/mach-msm/board-sapphire-h2w.c new file mode 100644 index 000000000000..aa83e216974d --- /dev/null +++ b/arch/arm/mach-msm/board-sapphire-h2w.c @@ -0,0 +1,545 @@ +/* + * H2W device detection driver. + * + * Copyright (C) 2008 HTC Corporation. + * Copyright (C) 2008 Google, Inc. + * + * Authors: + * Laurence Chen + * Nick Pelly + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +/* For detecting HTC 2 Wire devices, such as wired headset. + + Logically, the H2W driver is always present, and H2W state (hi->state) + indicates what is currently plugged into the H2W interface. + + When the headset is plugged in, CABLE_IN1 is pulled low. When the headset + button is pressed, CABLE_IN2 is pulled low. These two lines are shared with + the TX and RX (respectively) of UART3 - used for serial debugging. + + This headset driver keeps the CPLD configured as UART3 for as long as + possible, so that we can do serial FIQ debugging even when the kernel is + locked and this driver no longer runs. So it only configures the CPLD to + GPIO while the headset is plugged in, and for 10ms during detection work. + + Unfortunately we can't leave the CPLD as UART3 while a headset is plugged + in, UART3 is pullup on TX but the headset is pull-down, causing a 55 mA + drain on sapphire. + + The headset detection work involves setting CPLD to GPIO, and then pulling + CABLE_IN1 high with a stronger pullup than usual. A H2W headset will still + pull this line low, whereas other attachments such as a serial console + would get pulled up by this stronger pullup. + + Headset insertion/removal causes UEvent's to be sent, and + /sys/class/switch/h2w/state to be updated. + + Button presses are interpreted as input event (KEY_MEDIA). Button presses + are ignored if the headset is plugged in, so the buttons on 11 pin -> 3.5mm + jack adapters do not work until a headset is plugged into the adapter. This + is to avoid serial RX traffic causing spurious button press events. + + We tend to check the status of CABLE_IN1 a few more times than strictly + necessary during headset detection, to avoid spurious headset insertion + events caused by serial debugger TX traffic. +*/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "board-sapphire.h" + +#ifdef CONFIG_DEBUG_SAPPHIRE_H2W +#define H2W_DBG(fmt, arg...) printk(KERN_INFO "[H2W] %s " fmt "\n", __FUNCTION__, ## arg) +#else +#define H2W_DBG(fmt, arg...) do {} while (0) +#endif + +static struct workqueue_struct *g_detection_work_queue; +static void detection_work(struct work_struct *work); +static DECLARE_WORK(g_detection_work, detection_work); +enum { + NO_DEVICE = 0, + HTC_HEADSET = 1, +}; + +enum { + UART3 = 0, + GPIO = 1, +}; + +struct h2w_info { + struct switch_dev sdev; + struct input_dev *input; + + atomic_t btn_state; + int ignore_btn; + + unsigned int irq; + unsigned int irq_btn; + + struct hrtimer timer; + ktime_t debounce_time; + + struct hrtimer btn_timer; + ktime_t btn_debounce_time; +}; +static struct h2w_info *hi; + +static ssize_t sapphire_h2w_print_name(struct switch_dev *sdev, char *buf) +{ + switch (switch_get_state(&hi->sdev)) { + case NO_DEVICE: + return sprintf(buf, "No Device\n"); + case HTC_HEADSET: + return sprintf(buf, "Headset\n"); + } + return -EINVAL; +} + +static void configure_cpld(int route) +{ + H2W_DBG(" route = %s", route == UART3 ? "UART3" : "GPIO"); + switch (route) { + case UART3: + gpio_set_value(SAPPHIRE_GPIO_H2W_SEL0, 0); + gpio_set_value(SAPPHIRE_GPIO_H2W_SEL1, 1); + break; + case GPIO: + gpio_set_value(SAPPHIRE_GPIO_H2W_SEL0, 0); + gpio_set_value(SAPPHIRE_GPIO_H2W_SEL1, 0); + break; + } +} + +static void button_pressed(void) +{ + H2W_DBG(""); + atomic_set(&hi->btn_state, 1); + input_report_key(hi->input, KEY_MEDIA, 1); + input_sync(hi->input); +} + +static void button_released(void) +{ + H2W_DBG(""); + atomic_set(&hi->btn_state, 0); + input_report_key(hi->input, KEY_MEDIA, 0); + input_sync(hi->input); +} + +#ifdef CONFIG_MSM_SERIAL_DEBUGGER +extern void msm_serial_debug_enable(int); +#endif + +static void insert_headset(void) +{ + unsigned long irq_flags; + + H2W_DBG(""); + + switch_set_state(&hi->sdev, HTC_HEADSET); + configure_cpld(GPIO); + +#ifdef CONFIG_MSM_SERIAL_DEBUGGER + msm_serial_debug_enable(false); +#endif + + + /* On some non-standard headset adapters (usually those without a + * button) the btn line is pulled down at the same time as the detect + * line. We can check here by sampling the button line, if it is + * low then it is probably a bad adapter so ignore the button. + * If the button is released then we stop ignoring the button, so that + * the user can recover from the situation where a headset is plugged + * in with button held down. + */ + hi->ignore_btn = !gpio_get_value(SAPPHIRE_GPIO_CABLE_IN2); + + /* Enable button irq */ + local_irq_save(irq_flags); + enable_irq(hi->irq_btn); + local_irq_restore(irq_flags); + + hi->debounce_time = ktime_set(0, 20000000); /* 20 ms */ +} + +static void remove_headset(void) +{ + unsigned long irq_flags; + + H2W_DBG(""); + + switch_set_state(&hi->sdev, NO_DEVICE); + configure_cpld(UART3); + + /* Disable button */ + local_irq_save(irq_flags); + disable_irq(hi->irq_btn); + local_irq_restore(irq_flags); + + if (atomic_read(&hi->btn_state)) + button_released(); + + hi->debounce_time = ktime_set(0, 100000000); /* 100 ms */ +} + +static void detection_work(struct work_struct *work) +{ + unsigned long irq_flags; + int clk, cable_in1; + + H2W_DBG(""); + + if (gpio_get_value(SAPPHIRE_GPIO_CABLE_IN1) != 0) { + /* Headset not plugged in */ + if (switch_get_state(&hi->sdev) == HTC_HEADSET) + remove_headset(); + return; + } + + /* Something plugged in, lets make sure its a headset */ + + /* Switch CPLD to GPIO to do detection */ + configure_cpld(GPIO); + /* Disable headset interrupt while detecting.*/ + local_irq_save(irq_flags); + disable_irq(hi->irq); + local_irq_restore(irq_flags); + + /* Set GPIO_CABLE_IN1 as output high */ + gpio_direction_output(SAPPHIRE_GPIO_CABLE_IN1, 1); + /* Delay 10ms for pin stable. */ + msleep(10); + /* Save H2W_CLK */ + clk = gpio_get_value(SAPPHIRE_GPIO_H2W_CLK_GPI); + /* Set GPIO_CABLE_IN1 as input */ + gpio_direction_input(SAPPHIRE_GPIO_CABLE_IN1); + + /* Restore IRQs */ + local_irq_save(irq_flags); + enable_irq(hi->irq); + local_irq_restore(irq_flags); + + cable_in1 = gpio_get_value(SAPPHIRE_GPIO_CABLE_IN1); + + if (cable_in1 == 0 && clk == 0) { + if (switch_get_state(&hi->sdev) == NO_DEVICE) + insert_headset(); + } else { + configure_cpld(UART3); + H2W_DBG("CABLE_IN1 was low, but not a headset " + "(recent cable_in1 = %d, clk = %d)", cable_in1, clk); + } +} + +static enum hrtimer_restart button_event_timer_func(struct hrtimer *data) +{ + H2W_DBG(""); + + if (switch_get_state(&hi->sdev) == HTC_HEADSET) { + if (gpio_get_value(SAPPHIRE_GPIO_CABLE_IN2)) { + if (hi->ignore_btn) + hi->ignore_btn = 0; + else if (atomic_read(&hi->btn_state)) + button_released(); + } else { + if (!hi->ignore_btn && !atomic_read(&hi->btn_state)) + button_pressed(); + } + } + + return HRTIMER_NORESTART; +} + +static enum hrtimer_restart detect_event_timer_func(struct hrtimer *data) +{ + H2W_DBG(""); + + queue_work(g_detection_work_queue, &g_detection_work); + return HRTIMER_NORESTART; +} + +static irqreturn_t detect_irq_handler(int irq, void *dev_id) +{ + int value1, value2; + int retry_limit = 10; + + H2W_DBG(""); + do { + value1 = gpio_get_value(SAPPHIRE_GPIO_CABLE_IN1); + set_irq_type(hi->irq, value1 ? + IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH); + value2 = gpio_get_value(SAPPHIRE_GPIO_CABLE_IN1); + } while (value1 != value2 && retry_limit-- > 0); + + H2W_DBG("value2 = %d (%d retries)", value2, (10-retry_limit)); + + if ((switch_get_state(&hi->sdev) == NO_DEVICE) ^ value2) { + if (switch_get_state(&hi->sdev) == HTC_HEADSET) + hi->ignore_btn = 1; + /* Do the rest of the work in timer context */ + hrtimer_start(&hi->timer, hi->debounce_time, HRTIMER_MODE_REL); + } + + return IRQ_HANDLED; +} + +static irqreturn_t button_irq_handler(int irq, void *dev_id) +{ + int value1, value2; + int retry_limit = 10; + + H2W_DBG(""); + do { + value1 = gpio_get_value(SAPPHIRE_GPIO_CABLE_IN2); + set_irq_type(hi->irq_btn, value1 ? + IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH); + value2 = gpio_get_value(SAPPHIRE_GPIO_CABLE_IN2); + } while (value1 != value2 && retry_limit-- > 0); + + H2W_DBG("value2 = %d (%d retries)", value2, (10-retry_limit)); + + hrtimer_start(&hi->btn_timer, hi->btn_debounce_time, HRTIMER_MODE_REL); + + return IRQ_HANDLED; +} + +#if defined(CONFIG_DEBUG_FS) +static void h2w_debug_set(void *data, u64 val) +{ + switch_set_state(&hi->sdev, (int)val); +} + +static u64 h2w_debug_get(void *data) +{ + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(h2w_debug_fops, h2w_debug_get, h2w_debug_set, "%llu\n"); +static int __init h2w_debug_init(void) +{ + struct dentry *dent; + + dent = debugfs_create_dir("h2w", 0); + if (IS_ERR(dent)) + return PTR_ERR(dent); + + debugfs_create_file("state", 0644, dent, NULL, &h2w_debug_fops); + + return 0; +} + +device_initcall(h2w_debug_init); +#endif + +static int sapphire_h2w_probe(struct platform_device *pdev) +{ + int ret; + unsigned long irq_flags; + + printk(KERN_INFO "H2W: Registering H2W (headset) driver\n"); + hi = kzalloc(sizeof(struct h2w_info), GFP_KERNEL); + if (!hi) + return -ENOMEM; + + atomic_set(&hi->btn_state, 0); + hi->ignore_btn = 0; + + hi->debounce_time = ktime_set(0, 100000000); /* 100 ms */ + hi->btn_debounce_time = ktime_set(0, 10000000); /* 10 ms */ + hi->sdev.name = "h2w"; + hi->sdev.print_name = sapphire_h2w_print_name; + + ret = switch_dev_register(&hi->sdev); + if (ret < 0) + goto err_switch_dev_register; + + g_detection_work_queue = create_workqueue("detection"); + if (g_detection_work_queue == NULL) { + ret = -ENOMEM; + goto err_create_work_queue; + } + + ret = gpio_request(SAPPHIRE_GPIO_CABLE_IN1, "h2w_detect"); + if (ret < 0) + goto err_request_detect_gpio; + + ret = gpio_request(SAPPHIRE_GPIO_CABLE_IN2, "h2w_button"); + if (ret < 0) + goto err_request_button_gpio; + + ret = gpio_direction_input(SAPPHIRE_GPIO_CABLE_IN1); + if (ret < 0) + goto err_set_detect_gpio; + + ret = gpio_direction_input(SAPPHIRE_GPIO_CABLE_IN2); + if (ret < 0) + goto err_set_button_gpio; + + hi->irq = gpio_to_irq(SAPPHIRE_GPIO_CABLE_IN1); + if (hi->irq < 0) { + ret = hi->irq; + goto err_get_h2w_detect_irq_num_failed; + } + + hi->irq_btn = gpio_to_irq(SAPPHIRE_GPIO_CABLE_IN2); + if (hi->irq_btn < 0) { + ret = hi->irq_btn; + goto err_get_button_irq_num_failed; + } + + /* Set CPLD MUX to H2W <-> CPLD GPIO */ + configure_cpld(UART3); + /* Set the CPLD connected H2W GPIO's to input */ + gpio_set_value(SAPPHIRE_GPIO_H2W_CLK_DIR, 0); + gpio_set_value(SAPPHIRE_GPIO_H2W_DAT_DIR, 0); + + hrtimer_init(&hi->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + hi->timer.function = detect_event_timer_func; + hrtimer_init(&hi->btn_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + hi->btn_timer.function = button_event_timer_func; + + ret = request_irq(hi->irq, detect_irq_handler, + IRQF_TRIGGER_LOW, "h2w_detect", NULL); + if (ret < 0) + goto err_request_detect_irq; + + /* Disable button until plugged in */ + set_irq_flags(hi->irq_btn, IRQF_VALID | IRQF_NOAUTOEN); + ret = request_irq(hi->irq_btn, button_irq_handler, + IRQF_TRIGGER_LOW, "h2w_button", NULL); + if (ret < 0) + goto err_request_h2w_headset_button_irq; + + ret = set_irq_wake(hi->irq, 1); + if (ret < 0) + goto err_request_input_dev; + ret = set_irq_wake(hi->irq_btn, 1); + if (ret < 0) + goto err_request_input_dev; + + hi->input = input_allocate_device(); + if (!hi->input) { + ret = -ENOMEM; + goto err_request_input_dev; + } + + hi->input->name = "h2w headset"; + hi->input->evbit[0] = BIT_MASK(EV_KEY); + hi->input->keybit[BIT_WORD(KEY_MEDIA)] = BIT_MASK(KEY_MEDIA); + + ret = input_register_device(hi->input); + if (ret < 0) + goto err_register_input_dev; + + return 0; + +err_register_input_dev: + input_free_device(hi->input); +err_request_input_dev: + free_irq(hi->irq_btn, 0); +err_request_h2w_headset_button_irq: + free_irq(hi->irq, 0); +err_request_detect_irq: +err_get_button_irq_num_failed: +err_get_h2w_detect_irq_num_failed: +err_set_button_gpio: +err_set_detect_gpio: + gpio_free(SAPPHIRE_GPIO_CABLE_IN2); +err_request_button_gpio: + gpio_free(SAPPHIRE_GPIO_CABLE_IN1); +err_request_detect_gpio: + destroy_workqueue(g_detection_work_queue); +err_create_work_queue: + switch_dev_unregister(&hi->sdev); +err_switch_dev_register: + printk(KERN_ERR "H2W: Failed to register driver\n"); + + return ret; +} + +static int sapphire_h2w_remove(struct platform_device *pdev) +{ + H2W_DBG(""); + if (switch_get_state(&hi->sdev)) + remove_headset(); + input_unregister_device(hi->input); + gpio_free(SAPPHIRE_GPIO_CABLE_IN2); + gpio_free(SAPPHIRE_GPIO_CABLE_IN1); + free_irq(hi->irq_btn, 0); + free_irq(hi->irq, 0); + destroy_workqueue(g_detection_work_queue); + switch_dev_unregister(&hi->sdev); + + return 0; +} + +static struct platform_device sapphire_h2w_device = { + .name = "sapphire-h2w", +}; + +static struct platform_driver sapphire_h2w_driver = { + .probe = sapphire_h2w_probe, + .remove = sapphire_h2w_remove, + .driver = { + .name = "sapphire-h2w", + .owner = THIS_MODULE, + }, +}; + +static int __init sapphire_h2w_init(void) +{ + if (!machine_is_sapphire()) + return 0; + int ret; + H2W_DBG(""); + ret = platform_driver_register(&sapphire_h2w_driver); + if (ret) + return ret; + return platform_device_register(&sapphire_h2w_device); +} + +static void __exit sapphire_h2w_exit(void) +{ + platform_device_unregister(&sapphire_h2w_device); + platform_driver_unregister(&sapphire_h2w_driver); +} + +module_init(sapphire_h2w_init); +module_exit(sapphire_h2w_exit); + +MODULE_AUTHOR("Laurence Chen "); +MODULE_DESCRIPTION("HTC 2 Wire detection driver for sapphire"); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-msm/board-sapphire-keypad.c b/arch/arm/mach-msm/board-sapphire-keypad.c new file mode 100644 index 000000000000..14f12e5e865c --- /dev/null +++ b/arch/arm/mach-msm/board-sapphire-keypad.c @@ -0,0 +1,122 @@ +/* arch/arm/mach-msm/board-sapphire-keypad.c + * Copyright (C) 2007-2009 HTC Corporation. + * Author: Thomas Tsai + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 "gpio_chip.h" +#include "board-sapphire.h" +static char *keycaps = "--qwerty"; +#undef MODULE_PARAM_PREFIX +#define MODULE_PARAM_PREFIX "board_sapphire." +module_param_named(keycaps, keycaps, charp, 0); + + +static unsigned int sapphire_col_gpios[] = { 35, 34 }; + +/* KP_MKIN2 (GPIO40) is not used? */ +static unsigned int sapphire_row_gpios[] = { 42, 41 }; + +#define KEYMAP_INDEX(col, row) ((col)*ARRAY_SIZE(sapphire_row_gpios) + (row)) + +/*scan matrix key*/ +/* HOME(up) + MENU (down)*/ +static const unsigned short sapphire_keymap1[ARRAY_SIZE(sapphire_col_gpios) * + ARRAY_SIZE(sapphire_row_gpios)] = { + [KEYMAP_INDEX(0, 0)] = KEY_BACK, + [KEYMAP_INDEX(0, 1)] = KEY_MENU, + + [KEYMAP_INDEX(1, 0)] = KEY_HOME, + [KEYMAP_INDEX(1, 1)] = KEY_SEND, +}; + +/* MENU(up) + HOME (down)*/ +static const unsigned short sapphire_keymap0[ARRAY_SIZE(sapphire_col_gpios) * + ARRAY_SIZE(sapphire_row_gpios)] = { + [KEYMAP_INDEX(0, 0)] = KEY_BACK, + [KEYMAP_INDEX(0, 1)] = KEY_HOME, + + [KEYMAP_INDEX(1, 0)] = KEY_MENU, + [KEYMAP_INDEX(1, 1)] = KEY_SEND, +}; + +static struct gpio_event_matrix_info sapphire_keypad_matrix_info = { + .info.func = gpio_event_matrix_func, + .keymap = sapphire_keymap1, + .output_gpios = sapphire_col_gpios, + .input_gpios = sapphire_row_gpios, + .noutputs = ARRAY_SIZE(sapphire_col_gpios), + .ninputs = ARRAY_SIZE(sapphire_row_gpios), + .settle_time.tv.nsec = 40 * NSEC_PER_USEC, + .poll_time.tv.nsec = 20 * NSEC_PER_MSEC, + .debounce_delay.tv.nsec = 50 * NSEC_PER_MSEC, + .flags = GPIOKPF_LEVEL_TRIGGERED_IRQ | + GPIOKPF_REMOVE_PHANTOM_KEYS | + GPIOKPF_PRINT_UNMAPPED_KEYS /*| GPIOKPF_PRINT_MAPPED_KEYS*/ +}; + +static struct gpio_event_direct_entry sapphire_keypad_nav_map[] = { + { SAPPHIRE_POWER_KEY, KEY_END }, + { SAPPHIRE_VOLUME_UP, KEY_VOLUMEUP }, + { SAPPHIRE_VOLUME_DOWN, KEY_VOLUMEDOWN }, +}; + +static struct gpio_event_input_info sapphire_keypad_nav_info = { + .info.func = gpio_event_input_func, + .flags = 0, + .type = EV_KEY, + .keymap = sapphire_keypad_nav_map, + .debounce_time.tv.nsec = 20 * NSEC_PER_MSEC, + .keymap_size = ARRAY_SIZE(sapphire_keypad_nav_map) +}; + +static struct gpio_event_info *sapphire_keypad_info[] = { + &sapphire_keypad_matrix_info.info, + &sapphire_keypad_nav_info.info, +}; + +static struct gpio_event_platform_data sapphire_keypad_data = { + .name = "sapphire-keypad", + .info = sapphire_keypad_info, + .info_count = ARRAY_SIZE(sapphire_keypad_info) +}; + +static struct platform_device sapphire_keypad_device = { + .name = GPIO_EVENT_DEV_NAME, + .id = 0, + .dev = { + .platform_data = &sapphire_keypad_data, + }, +}; + +static int __init sapphire_init_keypad(void) +{ + if (!machine_is_sapphire()) + return 0; + + switch (sapphire_get_hwid()) { + case 0: + sapphire_keypad_matrix_info.keymap = sapphire_keymap0; + break; + default: + sapphire_keypad_matrix_info.keymap = sapphire_keymap1; + break; + } + return platform_device_register(&sapphire_keypad_device); +} + +device_initcall(sapphire_init_keypad); + diff --git a/arch/arm/mach-msm/board-sapphire-mmc.c b/arch/arm/mach-msm/board-sapphire-mmc.c new file mode 100644 index 000000000000..ff2a5fdc6c14 --- /dev/null +++ b/arch/arm/mach-msm/board-sapphire-mmc.c @@ -0,0 +1,479 @@ +/* linux/arch/arm/mach-msm/board-sapphire-mmc.c + * Copyright (C) 2007-2009 HTC Corporation. + * Author: Thomas Tsai + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 "devices.h" +#include "gpio_chip.h" +#include "board-sapphire.h" +#include "proc_comm.h" + +#define DEBUG_SDSLOT_VDD 1 + +extern int msm_add_sdcc(unsigned int controller, + struct mmc_platform_data *plat); + +/* ---- COMMON ---- */ +static void config_gpio_table(uint32_t *table, int len) +{ + int n; + unsigned id; + for (n = 0; n < len; n++) { + id = table[n]; + msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0); + } +} + +/* ---- SDCARD ---- */ + +static uint32_t sdcard_on_gpio_table[] = { + PCOM_GPIO_CFG(62, 2, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA), /* CLK */ + PCOM_GPIO_CFG(63, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* CMD */ + PCOM_GPIO_CFG(64, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* DAT3 */ + PCOM_GPIO_CFG(65, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* DAT2 */ + PCOM_GPIO_CFG(66, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT1 */ + PCOM_GPIO_CFG(67, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT0 */ +}; + +static uint32_t sdcard_off_gpio_table[] = { + PCOM_GPIO_CFG(62, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* CLK */ + PCOM_GPIO_CFG(63, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* CMD */ + PCOM_GPIO_CFG(64, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT3 */ + PCOM_GPIO_CFG(65, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT2 */ + PCOM_GPIO_CFG(66, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT1 */ + PCOM_GPIO_CFG(67, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT0 */ +}; + +static uint opt_disable_sdcard; + +static int __init sapphire_disablesdcard_setup(char *str) +{ + int cal = simple_strtol(str, NULL, 0); + + opt_disable_sdcard = cal; + return 1; +} + +__setup("board_sapphire.disable_sdcard=", sapphire_disablesdcard_setup); + +static struct vreg *vreg_sdslot; /* SD slot power */ + +struct mmc_vdd_xlat { + int mask; + int level; +}; + +static struct mmc_vdd_xlat mmc_vdd_table[] = { + { MMC_VDD_165_195, 1800 }, + { MMC_VDD_20_21, 2050 }, + { MMC_VDD_21_22, 2150 }, + { MMC_VDD_22_23, 2250 }, + { MMC_VDD_23_24, 2350 }, + { MMC_VDD_24_25, 2450 }, + { MMC_VDD_25_26, 2550 }, + { MMC_VDD_26_27, 2650 }, + { MMC_VDD_27_28, 2750 }, + { MMC_VDD_28_29, 2850 }, + { MMC_VDD_29_30, 2950 }, +}; + +static unsigned int sdslot_vdd = 0xffffffff; +static unsigned int sdslot_vreg_enabled; + +static uint32_t sapphire_sdslot_switchvdd(struct device *dev, unsigned int vdd) +{ + int i, rc; + + BUG_ON(!vreg_sdslot); + + if (vdd == sdslot_vdd) + return 0; + + sdslot_vdd = vdd; + + if (vdd == 0) { +#if DEBUG_SDSLOT_VDD + printk(KERN_DEBUG "%s: Disabling SD slot power\n", __func__); +#endif + config_gpio_table(sdcard_off_gpio_table, + ARRAY_SIZE(sdcard_off_gpio_table)); + vreg_disable(vreg_sdslot); + sdslot_vreg_enabled = 0; + return 0; + } + + if (!sdslot_vreg_enabled) { + rc = vreg_enable(vreg_sdslot); + if (rc) { + printk(KERN_ERR "%s: Error enabling vreg (%d)\n", + __func__, rc); + } + config_gpio_table(sdcard_on_gpio_table, + ARRAY_SIZE(sdcard_on_gpio_table)); + sdslot_vreg_enabled = 1; + } + + for (i = 0; i < ARRAY_SIZE(mmc_vdd_table); i++) { + if (mmc_vdd_table[i].mask == (1 << vdd)) { +#if DEBUG_SDSLOT_VDD + printk(KERN_DEBUG "%s: Setting level to %u\n", + __func__, mmc_vdd_table[i].level); +#endif + rc = vreg_set_level(vreg_sdslot, + mmc_vdd_table[i].level); + if (rc) { + printk(KERN_ERR + "%s: Error setting vreg level (%d)\n", + __func__, rc); + } + return 0; + } + } + + printk(KERN_ERR "%s: Invalid VDD %d specified\n", __func__, vdd); + return 0; +} + +static unsigned int sapphire_sdslot_status(struct device *dev) +{ + unsigned int status; + + status = (unsigned int) gpio_get_value(SAPPHIRE_GPIO_SDMC_CD_N); + return !status; +} + +#define SAPPHIRE_MMC_VDD (MMC_VDD_165_195 | MMC_VDD_20_21 | MMC_VDD_21_22 \ + | MMC_VDD_22_23 | MMC_VDD_23_24 | MMC_VDD_24_25 \ + | MMC_VDD_25_26 | MMC_VDD_26_27 | MMC_VDD_27_28 \ + | MMC_VDD_28_29 | MMC_VDD_29_30) + +static struct mmc_platform_data sapphire_sdslot_data = { + .ocr_mask = SAPPHIRE_MMC_VDD, + .status_irq = SAPPHIRE_GPIO_TO_INT(SAPPHIRE_GPIO_SDMC_CD_N), + .status = sapphire_sdslot_status, + .translate_vdd = sapphire_sdslot_switchvdd, +}; + +/* ---- WIFI ---- */ + +static uint32_t wifi_on_gpio_table[] = { + PCOM_GPIO_CFG(51, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT3 */ + PCOM_GPIO_CFG(52, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT2 */ + PCOM_GPIO_CFG(53, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT1 */ + PCOM_GPIO_CFG(54, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT0 */ + PCOM_GPIO_CFG(55, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* CMD */ + PCOM_GPIO_CFG(56, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA), /* CLK */ + PCOM_GPIO_CFG(29, 0, GPIO_INPUT, GPIO_NO_PULL, GPIO_4MA), /* WLAN IRQ */ +}; + +static uint32_t wifi_off_gpio_table[] = { + PCOM_GPIO_CFG(51, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT3 */ + PCOM_GPIO_CFG(52, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT2 */ + PCOM_GPIO_CFG(53, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT1 */ + PCOM_GPIO_CFG(54, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT0 */ + PCOM_GPIO_CFG(55, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* CMD */ + PCOM_GPIO_CFG(56, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* CLK */ + PCOM_GPIO_CFG(29, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* WLAN IRQ */ +}; + +static struct vreg *vreg_wifi_osc; /* WIFI 32khz oscilator */ +static int sapphire_wifi_cd = 0; /* WIFI virtual 'card detect' status */ + +static struct sdio_embedded_func wifi_func = { + .f_class = SDIO_CLASS_WLAN, + .f_maxblksize = 512, +}; + +static struct embedded_sdio_data sapphire_wifi_emb_data = { + .cis = { + .vendor = 0x104c, + .device = 0x9066, + .blksize = 512, + .max_dtr = 20000000, + }, + .cccr = { + .multi_block = 0, + .low_speed = 0, + .wide_bus = 1, + .high_power = 0, + .high_speed = 0, + }, + .funcs = &wifi_func, + .num_funcs = 1, +}; + +static void (*wifi_status_cb)(int card_present, void *dev_id); +static void *wifi_status_cb_devid; + +static int sapphire_wifi_status_register(void (*callback)(int card_present, + void *dev_id), + void *dev_id) +{ + if (wifi_status_cb) + return -EAGAIN; + wifi_status_cb = callback; + wifi_status_cb_devid = dev_id; + return 0; +} + +static unsigned int sapphire_wifi_status(struct device *dev) +{ + return sapphire_wifi_cd; +} + +int sapphire_wifi_set_carddetect(int val) +{ + printk(KERN_DEBUG "%s: %d\n", __func__, val); + sapphire_wifi_cd = val; + if (wifi_status_cb) + wifi_status_cb(val, wifi_status_cb_devid); + else + printk(KERN_WARNING "%s: Nobody to notify\n", __func__); + return 0; +} +#ifndef CONFIG_WIFI_CONTROL_FUNC +EXPORT_SYMBOL(sapphire_wifi_set_carddetect); +#endif + +static int sapphire_wifi_power_state; +static int sapphire_bt_power_state; + +int sapphire_wifi_power(int on) +{ + int rc; + + printk(KERN_DEBUG "%s: %d\n", __func__, on); + + if (on) { + config_gpio_table(wifi_on_gpio_table, + ARRAY_SIZE(wifi_on_gpio_table)); + rc = vreg_enable(vreg_wifi_osc); + if (rc) + return rc; + htc_pwrsink_set(PWRSINK_WIFI, 70); + } else { + config_gpio_table(wifi_off_gpio_table, + ARRAY_SIZE(wifi_off_gpio_table)); + htc_pwrsink_set(PWRSINK_WIFI, 0); + } + gpio_set_value(SAPPHIRE_GPIO_MAC_32K_EN, on); + mdelay(100); + gpio_set_value(SAPPHIRE_GPIO_WIFI_EN, on); + mdelay(100); + if (!on) + vreg_disable(vreg_wifi_osc); + sapphire_wifi_power_state = on; + return 0; +} +#ifndef CONFIG_WIFI_CONTROL_FUNC +EXPORT_SYMBOL(sapphire_wifi_power); +#endif + +/* Eenable VREG_MMC pin to turn on fastclock oscillator : colin */ +int sapphire_bt_fastclock_power(int on) +{ + int rc; + + printk(KERN_DEBUG "sapphire_bt_fastclock_power on = %d\n", on); + if (vreg_wifi_osc) { + if (on) { + rc = vreg_enable(vreg_wifi_osc); + printk(KERN_DEBUG "BT vreg_enable vreg_mmc, rc=%d\n", + rc); + if (rc) { + printk("Error turn sapphire_bt_fastclock_power rc=%d\n", rc); + return rc; + } + } else { + if (!sapphire_wifi_power_state) { + vreg_disable(vreg_wifi_osc); + printk(KERN_DEBUG "BT disable vreg_wifi_osc.\n"); + } else + printk(KERN_DEBUG "BT shouldn't disable vreg_wifi_osc. WiFi is using it!!\n"); + } + } + sapphire_bt_power_state = on; + return 0; +} +EXPORT_SYMBOL(sapphire_bt_fastclock_power); + +static int sapphire_wifi_reset_state; +void sapphire_wifi_reset(int on) +{ + printk(KERN_DEBUG "%s: %d\n", __func__, on); + gpio_set_value(SAPPHIRE_GPIO_WIFI_PA_RESETX, !on); + sapphire_wifi_reset_state = on; + mdelay(50); +} +#ifndef CONFIG_WIFI_CONTROL_FUNC +EXPORT_SYMBOL(sapphire_wifi_reset); +#endif + +static struct mmc_platform_data sapphire_wifi_data = { + .ocr_mask = MMC_VDD_28_29, + .status = sapphire_wifi_status, + .register_status_notify = sapphire_wifi_status_register, + .embedded_sdio = &sapphire_wifi_emb_data, +}; + +int __init sapphire_init_mmc(unsigned int sys_rev) +{ + wifi_status_cb = NULL; + + sdslot_vreg_enabled = 0; + + vreg_sdslot = vreg_get(0, "gp6"); + if (IS_ERR(vreg_sdslot)) + return PTR_ERR(vreg_sdslot); + vreg_wifi_osc = vreg_get(0, "mmc"); + if (IS_ERR(vreg_wifi_osc)) + return PTR_ERR(vreg_wifi_osc); + + set_irq_wake(SAPPHIRE_GPIO_TO_INT(SAPPHIRE_GPIO_SDMC_CD_N), 1); + + msm_add_sdcc(1, &sapphire_wifi_data); + + if (!opt_disable_sdcard) + msm_add_sdcc(2, &sapphire_sdslot_data); + else + printk(KERN_INFO "sapphire: SD-Card interface disabled\n"); + return 0; +} + +#if defined(CONFIG_DEBUG_FS) +static int sapphiremmc_dbg_wifi_reset_set(void *data, u64 val) +{ + sapphire_wifi_reset((int) val); + return 0; +} + +static int sapphiremmc_dbg_wifi_reset_get(void *data, u64 *val) +{ + *val = sapphire_wifi_reset_state; + return 0; +} + +static int sapphiremmc_dbg_wifi_cd_set(void *data, u64 val) +{ + sapphire_wifi_set_carddetect((int) val); + return 0; +} + +static int sapphiremmc_dbg_wifi_cd_get(void *data, u64 *val) +{ + *val = sapphire_wifi_cd; + return 0; +} + +static int sapphiremmc_dbg_wifi_pwr_set(void *data, u64 val) +{ + sapphire_wifi_power((int) val); + return 0; +} + +static int sapphiremmc_dbg_wifi_pwr_get(void *data, u64 *val) +{ + + *val = sapphire_wifi_power_state; + return 0; +} + +static int sapphiremmc_dbg_sd_pwr_set(void *data, u64 val) +{ + sapphire_sdslot_switchvdd(NULL, (unsigned int) val); + return 0; +} + +static int sapphiremmc_dbg_sd_pwr_get(void *data, u64 *val) +{ + *val = sdslot_vdd; + return 0; +} + +static int sapphiremmc_dbg_sd_cd_set(void *data, u64 val) +{ + return -ENOSYS; +} + +static int sapphiremmc_dbg_sd_cd_get(void *data, u64 *val) +{ + *val = sapphire_sdslot_status(NULL); + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(sapphiremmc_dbg_wifi_reset_fops, + sapphiremmc_dbg_wifi_reset_get, + sapphiremmc_dbg_wifi_reset_set, "%llu\n"); + +DEFINE_SIMPLE_ATTRIBUTE(sapphiremmc_dbg_wifi_cd_fops, + sapphiremmc_dbg_wifi_cd_get, + sapphiremmc_dbg_wifi_cd_set, "%llu\n"); + +DEFINE_SIMPLE_ATTRIBUTE(sapphiremmc_dbg_wifi_pwr_fops, + sapphiremmc_dbg_wifi_pwr_get, + sapphiremmc_dbg_wifi_pwr_set, "%llu\n"); + +DEFINE_SIMPLE_ATTRIBUTE(sapphiremmc_dbg_sd_pwr_fops, + sapphiremmc_dbg_sd_pwr_get, + sapphiremmc_dbg_sd_pwr_set, "%llu\n"); + +DEFINE_SIMPLE_ATTRIBUTE(sapphiremmc_dbg_sd_cd_fops, + sapphiremmc_dbg_sd_cd_get, + sapphiremmc_dbg_sd_cd_set, "%llu\n"); + +static int __init sapphiremmc_dbg_init(void) +{ + struct dentry *dent; + + if (!machine_is_sapphire()) + return 0; + + dent = debugfs_create_dir("sapphiremmc_dbg", 0); + if (IS_ERR(dent)) + return PTR_ERR(dent); + + debugfs_create_file("wifi_reset", 0644, dent, NULL, + &sapphiremmc_dbg_wifi_reset_fops); + debugfs_create_file("wifi_cd", 0644, dent, NULL, + &sapphiremmc_dbg_wifi_cd_fops); + debugfs_create_file("wifi_pwr", 0644, dent, NULL, + &sapphiremmc_dbg_wifi_pwr_fops); + + debugfs_create_file("sd_pwr", 0644, dent, NULL, + &sapphiremmc_dbg_sd_pwr_fops); + debugfs_create_file("sd_cd", 0644, dent, NULL, + &sapphiremmc_dbg_sd_cd_fops); + + return 0; +} + +device_initcall(sapphiremmc_dbg_init); + +#endif diff --git a/arch/arm/mach-msm/board-sapphire-panel.c b/arch/arm/mach-msm/board-sapphire-panel.c new file mode 100644 index 000000000000..24933f3eab52 --- /dev/null +++ b/arch/arm/mach-msm/board-sapphire-panel.c @@ -0,0 +1,656 @@ +/* linux/arch/arm/mach-msm/board-sapphire-panel.c + * Copyright (C) 2007-2009 HTC Corporation. + * Author: Thomas Tsai + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 "gpio_chip.h" +#include "board-sapphire.h" +#include "proc_comm.h" +#include "devices.h" + +enum sapphire_panel_type { + SAPPHIRE_PANEL_SHARP = 0, + SAPPHIRE_PANEL_TOPPOLY, + NUM_OF_SAPPHIRE_PANELS, +}; +static int g_panel_id = -1 ; + +#define SAPPHIRE_DEFAULT_BACKLIGHT_BRIGHTNESS 132 + +static int sapphire_backlight_off; +static int sapphire_backlight_brightness = + SAPPHIRE_DEFAULT_BACKLIGHT_BRIGHTNESS; + +static uint8_t sapphire_backlight_last_level = 33; +static DEFINE_MUTEX(sapphire_backlight_lock); + +/* Divid dimming level into 12 sections, and restrict maximum level to 27 */ +#define DIMMING_STEPS 12 +static unsigned dimming_levels[NUM_OF_SAPPHIRE_PANELS][DIMMING_STEPS] = { + {0, 1, 2, 3, 6, 9, 11, 13, 16, 19, 22, 25}, /* Sharp */ + {0, 1, 2, 4, 7, 10, 13, 15, 18, 21, 24, 27}, /* Toppolly */ +}; +static unsigned pwrsink_percents[] = {0, 6, 8, 15, 26, 34, 46, 54, 65, 77, 87, + 100}; + +static void sapphire_set_backlight_level(uint8_t level) +{ + unsigned dimming_factor = 255/DIMMING_STEPS + 1 ; + unsigned percent = ((int)level * 100) / 255; + unsigned long flags; + int i = 0; + + printk(KERN_INFO "level=%d, new level=dimming_levels[%d]=%d\n", + level, level/dimming_factor, + dimming_levels[g_panel_id][level/dimming_factor]); + percent = pwrsink_percents[level/dimming_factor]; + level = dimming_levels[g_panel_id][level/dimming_factor]; + + if (sapphire_backlight_last_level == level) + return; + + if (level == 0) { + gpio_set_value(27, 0); + msleep(2); + } else { + local_irq_save(flags); + if (sapphire_backlight_last_level == 0) { + gpio_set_value(27, 1); + udelay(40); + sapphire_backlight_last_level = 33; + } + i = (sapphire_backlight_last_level - level + 33) % 33; + while (i-- > 0) { + gpio_set_value(27, 0); + udelay(1); + gpio_set_value(27, 1); + udelay(1); + } + local_irq_restore(flags); + } + sapphire_backlight_last_level = level; + htc_pwrsink_set(PWRSINK_BACKLIGHT, percent); +} + +#define MDDI_CLIENT_CORE_BASE 0x108000 +#define LCD_CONTROL_BLOCK_BASE 0x110000 +#define SPI_BLOCK_BASE 0x120000 +#define I2C_BLOCK_BASE 0x130000 +#define PWM_BLOCK_BASE 0x140000 +#define GPIO_BLOCK_BASE 0x150000 +#define SYSTEM_BLOCK1_BASE 0x160000 +#define SYSTEM_BLOCK2_BASE 0x170000 + + +#define DPSUS (MDDI_CLIENT_CORE_BASE|0x24) +#define SYSCLKENA (MDDI_CLIENT_CORE_BASE|0x2C) +#define PWM0OFF (PWM_BLOCK_BASE|0x1C) + +#define V_VDDE2E_VDD2_GPIO 0 +#define V_VDDE2E_VDD2_GPIO_5M 89 +#define MDDI_RST_N 82 + +#define MDDICAP0 (MDDI_CLIENT_CORE_BASE|0x00) +#define MDDICAP1 (MDDI_CLIENT_CORE_BASE|0x04) +#define MDDICAP2 (MDDI_CLIENT_CORE_BASE|0x08) +#define MDDICAP3 (MDDI_CLIENT_CORE_BASE|0x0C) +#define MDCAPCHG (MDDI_CLIENT_CORE_BASE|0x10) +#define MDCRCERC (MDDI_CLIENT_CORE_BASE|0x14) +#define TTBUSSEL (MDDI_CLIENT_CORE_BASE|0x18) +#define DPSET0 (MDDI_CLIENT_CORE_BASE|0x1C) +#define DPSET1 (MDDI_CLIENT_CORE_BASE|0x20) +#define DPSUS (MDDI_CLIENT_CORE_BASE|0x24) +#define DPRUN (MDDI_CLIENT_CORE_BASE|0x28) +#define SYSCKENA (MDDI_CLIENT_CORE_BASE|0x2C) +#define TESTMODE (MDDI_CLIENT_CORE_BASE|0x30) +#define FIFOMONI (MDDI_CLIENT_CORE_BASE|0x34) +#define INTMONI (MDDI_CLIENT_CORE_BASE|0x38) +#define MDIOBIST (MDDI_CLIENT_CORE_BASE|0x3C) +#define MDIOPSET (MDDI_CLIENT_CORE_BASE|0x40) +#define BITMAP0 (MDDI_CLIENT_CORE_BASE|0x44) +#define BITMAP1 (MDDI_CLIENT_CORE_BASE|0x48) +#define BITMAP2 (MDDI_CLIENT_CORE_BASE|0x4C) +#define BITMAP3 (MDDI_CLIENT_CORE_BASE|0x50) +#define BITMAP4 (MDDI_CLIENT_CORE_BASE|0x54) + +#define SRST (LCD_CONTROL_BLOCK_BASE|0x00) +#define PORT_ENB (LCD_CONTROL_BLOCK_BASE|0x04) +#define START (LCD_CONTROL_BLOCK_BASE|0x08) +#define PORT (LCD_CONTROL_BLOCK_BASE|0x0C) +#define CMN (LCD_CONTROL_BLOCK_BASE|0x10) +#define GAMMA (LCD_CONTROL_BLOCK_BASE|0x14) +#define INTFLG (LCD_CONTROL_BLOCK_BASE|0x18) +#define INTMSK (LCD_CONTROL_BLOCK_BASE|0x1C) +#define MPLFBUF (LCD_CONTROL_BLOCK_BASE|0x20) +#define HDE_LEFT (LCD_CONTROL_BLOCK_BASE|0x24) +#define VDE_TOP (LCD_CONTROL_BLOCK_BASE|0x28) +#define PXL (LCD_CONTROL_BLOCK_BASE|0x30) +#define HCYCLE (LCD_CONTROL_BLOCK_BASE|0x34) +#define HSW (LCD_CONTROL_BLOCK_BASE|0x38) +#define HDE_START (LCD_CONTROL_BLOCK_BASE|0x3C) +#define HDE_SIZE (LCD_CONTROL_BLOCK_BASE|0x40) +#define VCYCLE (LCD_CONTROL_BLOCK_BASE|0x44) +#define VSW (LCD_CONTROL_BLOCK_BASE|0x48) +#define VDE_START (LCD_CONTROL_BLOCK_BASE|0x4C) +#define VDE_SIZE (LCD_CONTROL_BLOCK_BASE|0x50) +#define WAKEUP (LCD_CONTROL_BLOCK_BASE|0x54) +#define WSYN_DLY (LCD_CONTROL_BLOCK_BASE|0x58) +#define REGENB (LCD_CONTROL_BLOCK_BASE|0x5C) +#define VSYNIF (LCD_CONTROL_BLOCK_BASE|0x60) +#define WRSTB (LCD_CONTROL_BLOCK_BASE|0x64) +#define RDSTB (LCD_CONTROL_BLOCK_BASE|0x68) +#define ASY_DATA (LCD_CONTROL_BLOCK_BASE|0x6C) +#define ASY_DATB (LCD_CONTROL_BLOCK_BASE|0x70) +#define ASY_DATC (LCD_CONTROL_BLOCK_BASE|0x74) +#define ASY_DATD (LCD_CONTROL_BLOCK_BASE|0x78) +#define ASY_DATE (LCD_CONTROL_BLOCK_BASE|0x7C) +#define ASY_DATF (LCD_CONTROL_BLOCK_BASE|0x80) +#define ASY_DATG (LCD_CONTROL_BLOCK_BASE|0x84) +#define ASY_DATH (LCD_CONTROL_BLOCK_BASE|0x88) +#define ASY_CMDSET (LCD_CONTROL_BLOCK_BASE|0x8C) + +#define SSICTL (SPI_BLOCK_BASE|0x00) +#define SSITIME (SPI_BLOCK_BASE|0x04) +#define SSITX (SPI_BLOCK_BASE|0x08) +#define SSIRX (SPI_BLOCK_BASE|0x0C) +#define SSIINTC (SPI_BLOCK_BASE|0x10) +#define SSIINTS (SPI_BLOCK_BASE|0x14) +#define SSIDBG1 (SPI_BLOCK_BASE|0x18) +#define SSIDBG2 (SPI_BLOCK_BASE|0x1C) +#define SSIID (SPI_BLOCK_BASE|0x20) + +#define WKREQ (SYSTEM_BLOCK1_BASE|0x00) +#define CLKENB (SYSTEM_BLOCK1_BASE|0x04) +#define DRAMPWR (SYSTEM_BLOCK1_BASE|0x08) +#define INTMASK (SYSTEM_BLOCK1_BASE|0x0C) +#define GPIOSEL (SYSTEM_BLOCK2_BASE|0x00) + +#define GPIODATA (GPIO_BLOCK_BASE|0x00) +#define GPIODIR (GPIO_BLOCK_BASE|0x04) +#define GPIOIS (GPIO_BLOCK_BASE|0x08) +#define GPIOIBE (GPIO_BLOCK_BASE|0x0C) +#define GPIOIEV (GPIO_BLOCK_BASE|0x10) +#define GPIOIE (GPIO_BLOCK_BASE|0x14) +#define GPIORIS (GPIO_BLOCK_BASE|0x18) +#define GPIOMIS (GPIO_BLOCK_BASE|0x1C) +#define GPIOIC (GPIO_BLOCK_BASE|0x20) +#define GPIOOMS (GPIO_BLOCK_BASE|0x24) +#define GPIOPC (GPIO_BLOCK_BASE|0x28) +#define GPIOID (GPIO_BLOCK_BASE|0x30) + +#define SPI_WRITE(reg, val) \ + { SSITX, 0x00010000 | (((reg) & 0xff) << 8) | ((val) & 0xff) }, \ + { 0, 5 }, + +#define SPI_WRITE1(reg) \ + { SSITX, (reg) & 0xff }, \ + { 0, 5 }, + +struct mddi_table { + uint32_t reg; + uint32_t value; +}; +static struct mddi_table mddi_toshiba_init_table[] = { + { DPSET0, 0x09e90046 }, + { DPSET1, 0x00000118 }, + { DPSUS, 0x00000000 }, + { DPRUN, 0x00000001 }, + { 1, 14 }, /* msleep 14 */ + { SYSCKENA, 0x00000001 }, + /*{ CLKENB, 0x000000EF } */ + { CLKENB, 0x0000A1EF }, /* # SYS.CLKENB # Enable clocks for each module (without DCLK , i2cCLK) */ + /*{ CLKENB, 0x000025CB }, Clock enable register */ + + { GPIODATA, 0x02000200 }, /* # GPI .GPIODATA # GPIO2(RESET_LCD_N) set to 0 , GPIO3(eDRAM_Power) set to 0 */ + { GPIODIR, 0x000030D }, /* 24D # GPI .GPIODIR # Select direction of GPIO port (0,2,3,6,9 output) */ + { GPIOSEL, 0/*0x00000173*/}, /* # SYS.GPIOSEL # GPIO port multiplexing control */ + { GPIOPC, 0x03C300C0 }, /* # GPI .GPIOPC # GPIO2,3 PD cut */ + { WKREQ, 0x00000000 }, /* # SYS.WKREQ # Wake-up request event is VSYNC alignment */ + + { GPIOIBE, 0x000003FF }, + { GPIOIS, 0x00000000 }, + { GPIOIC, 0x000003FF }, + { GPIOIE, 0x00000000 }, + + { GPIODATA, 0x00040004 }, /* # GPI .GPIODATA # eDRAM VD supply */ + { 1, 1 }, /* msleep 1 */ + { GPIODATA, 0x02040004 }, /* # GPI .GPIODATA # eDRAM VD supply */ + { DRAMPWR, 0x00000001 }, /* eDRAM power */ +}; + +static struct mddi_table mddi_toshiba_panel_init_table[] = { + { SRST, 0x00000003 }, /* FIFO/LCDC not reset */ + { PORT_ENB, 0x00000001 }, /* Enable sync. Port */ + { START, 0x00000000 }, /* To stop operation */ + /*{ START, 0x00000001 }, To start operation */ + { PORT, 0x00000004 }, /* Polarity of VS/HS/DE. */ + { CMN, 0x00000000 }, + { GAMMA, 0x00000000 }, /* No Gamma correction */ + { INTFLG, 0x00000000 }, /* VSYNC interrupt flag clear/status */ + { INTMSK, 0x00000000 }, /* VSYNC interrupt mask is off. */ + { MPLFBUF, 0x00000000 }, /* Select frame buffer's base address. */ + { HDE_LEFT, 0x00000000 }, /* The value of HDE_LEFT. */ + { VDE_TOP, 0x00000000 }, /* The value of VDE_TPO. */ + { PXL, 0x00000001 }, /* 1. RGB666 */ + /* 2. Data is valid from 1st frame of beginning. */ + { HDE_START, 0x00000006 }, /* HDE_START= 14 PCLK */ + { HDE_SIZE, 0x0000009F }, /* HDE_SIZE=320 PCLK */ + { HSW, 0x00000004 }, /* HSW= 10 PCLK */ + { VSW, 0x00000001 }, /* VSW=2 HCYCLE */ + { VDE_START, 0x00000003 }, /* VDE_START=4 HCYCLE */ + { VDE_SIZE, 0x000001DF }, /* VDE_SIZE=480 HCYCLE */ + { WAKEUP, 0x000001e2 }, /* Wakeup position in VSYNC mode. */ + { WSYN_DLY, 0x00000000 }, /* Wakeup position in VSIN mode. */ + { REGENB, 0x00000001 }, /* Set 1 to enable to change the value of registers. */ + { CLKENB, 0x000025CB }, /* Clock enable register */ + + { SSICTL, 0x00000170 }, /* SSI control register */ + { SSITIME, 0x00000250 }, /* SSI timing control register */ + { SSICTL, 0x00000172 }, /* SSI control register */ +}; + + +static struct mddi_table mddi_sharp_init_table[] = { + { VCYCLE, 0x000001eb }, + { HCYCLE, 0x000000ae }, + { REGENB, 0x00000001 }, /* Set 1 to enable to change the value of registers. */ + { GPIODATA, 0x00040000 }, /* GPIO2 low */ + { GPIODIR, 0x00000004 }, /* GPIO2 out */ + { 1, 1 }, /* msleep 1 */ + { GPIODATA, 0x00040004 }, /* GPIO2 high */ + { 1, 10 }, /* msleep 10 */ + SPI_WRITE(0x5f, 0x01) + SPI_WRITE1(0x11) + { 1, 200 }, /* msleep 200 */ + SPI_WRITE1(0x29) + SPI_WRITE1(0xde) + { START, 0x00000001 }, /* To start operation */ +}; + +static struct mddi_table mddi_sharp_deinit_table[] = { + { 1, 200 }, /* msleep 200 */ + SPI_WRITE(0x10, 0x1) + { 1, 100 }, /* msleep 100 */ + { GPIODATA, 0x00040004 }, /* GPIO2 high */ + { GPIODIR, 0x00000004 }, /* GPIO2 out */ + { GPIODATA, 0x00040000 }, /* GPIO2 low */ + { 1, 10 }, /* msleep 10 */ +}; + +static struct mddi_table mddi_tpo_init_table[] = { + { VCYCLE, 0x000001e5 }, + { HCYCLE, 0x000000ac }, + { REGENB, 0x00000001 }, /* Set 1 to enable to change the value of registers. */ + { 0, 20 }, /* udelay 20 */ + { GPIODATA, 0x00000004 }, /* GPIO2 high */ + { GPIODIR, 0x00000004 }, /* GPIO2 out */ + { 0, 20 }, /* udelay 20 */ + + SPI_WRITE(0x08, 0x01) + { 0, 500 }, /* udelay 500 */ + SPI_WRITE(0x08, 0x00) + SPI_WRITE(0x02, 0x00) + SPI_WRITE(0x03, 0x04) + SPI_WRITE(0x04, 0x0e) + SPI_WRITE(0x09, 0x02) + SPI_WRITE(0x0b, 0x08) + SPI_WRITE(0x0c, 0x53) + SPI_WRITE(0x0d, 0x01) + SPI_WRITE(0x0e, 0xe0) + SPI_WRITE(0x0f, 0x01) + SPI_WRITE(0x10, 0x58) + SPI_WRITE(0x20, 0x1e) + SPI_WRITE(0x21, 0x0a) + SPI_WRITE(0x22, 0x0a) + SPI_WRITE(0x23, 0x1e) + SPI_WRITE(0x25, 0x32) + SPI_WRITE(0x26, 0x00) + SPI_WRITE(0x27, 0xac) + SPI_WRITE(0x29, 0x06) + SPI_WRITE(0x2a, 0xa4) + SPI_WRITE(0x2b, 0x45) + SPI_WRITE(0x2c, 0x45) + SPI_WRITE(0x2d, 0x15) + SPI_WRITE(0x2e, 0x5a) + SPI_WRITE(0x2f, 0xff) + SPI_WRITE(0x30, 0x6b) + SPI_WRITE(0x31, 0x0d) + SPI_WRITE(0x32, 0x48) + SPI_WRITE(0x33, 0x82) + SPI_WRITE(0x34, 0xbd) + SPI_WRITE(0x35, 0xe7) + SPI_WRITE(0x36, 0x18) + SPI_WRITE(0x37, 0x94) + SPI_WRITE(0x38, 0x01) + SPI_WRITE(0x39, 0x5d) + SPI_WRITE(0x3a, 0xae) + SPI_WRITE(0x3b, 0xff) + SPI_WRITE(0x07, 0x09) + { 0, 10 }, /* udelay 10 */ + { START, 0x00000001 }, /* To start operation */ +}; + +static struct mddi_table mddi_tpo_deinit_table[] = { + SPI_WRITE(0x07, 0x19) + { START, 0x00000000 }, /* To stop operation */ + { GPIODATA, 0x00040004 }, /* GPIO2 high */ + { GPIODIR, 0x00000004 }, /* GPIO2 out */ + { GPIODATA, 0x00040000 }, /* GPIO2 low */ + { 0, 5 }, /* usleep 5 */ +}; + + +#define GPIOSEL_VWAKEINT (1U << 0) +#define INTMASK_VWAKEOUT (1U << 0) + +static void sapphire_process_mddi_table( + struct msm_mddi_client_data *client_data, + struct mddi_table *table, size_t count) +{ + int i; + for (i = 0; i < count; i++) { + uint32_t reg = table[i].reg; + uint32_t value = table[i].value; + + if (reg == 0) + udelay(value); + else if (reg == 1) + msleep(value); + else + client_data->remote_write(client_data, value, reg); + } +} + +static struct vreg *vreg_lcm_2v85; + +static void sapphire_mddi_power_client(struct msm_mddi_client_data *client_data, + int on) +{ + unsigned id, on_off; + printk(KERN_INFO "sapphire_mddi_client_power:%d\r\n", on); + if (on) { + on_off = 0; + id = PM_VREG_PDOWN_MDDI_ID; + msm_proc_comm(PCOM_VREG_PULLDOWN, &on_off, &id); + + gpio_set_value(SAPPHIRE_MDDI_1V5_EN, 1); + mdelay(5); /* delay time >5ms and <10ms */ + + if (is_12pin_camera()) + gpio_set_value(V_VDDE2E_VDD2_GPIO_5M, 1); + else + gpio_set_value(V_VDDE2E_VDD2_GPIO, 1); + + gpio_set_value(SAPPHIRE_GPIO_MDDI_32K_EN, 1); + msleep(3); + id = PM_VREG_PDOWN_AUX_ID; + msm_proc_comm(PCOM_VREG_PULLDOWN, &on_off, &id); + vreg_enable(vreg_lcm_2v85); + msleep(3); + gpio_set_value(MDDI_RST_N, 1); + msleep(10); + } else { + gpio_set_value(SAPPHIRE_GPIO_MDDI_32K_EN, 0); + gpio_set_value(MDDI_RST_N, 0); + msleep(10); + vreg_disable(vreg_lcm_2v85); + on_off = 1; + id = PM_VREG_PDOWN_AUX_ID; + msm_proc_comm(PCOM_VREG_PULLDOWN, &on_off, &id); + msleep(5); + if (is_12pin_camera()) + gpio_set_value(V_VDDE2E_VDD2_GPIO_5M, 0); + else + gpio_set_value(V_VDDE2E_VDD2_GPIO, 0); + + msleep(200); + gpio_set_value(SAPPHIRE_MDDI_1V5_EN, 0); + id = PM_VREG_PDOWN_MDDI_ID; + msm_proc_comm(PCOM_VREG_PULLDOWN, &on_off, &id); + } +} + +static int sapphire_mddi_toshiba_client_init( + struct msm_mddi_bridge_platform_data *bridge_data, + struct msm_mddi_client_data *client_data) +{ + int panel_id; + + client_data->auto_hibernate(client_data, 0); + sapphire_process_mddi_table(client_data, mddi_toshiba_init_table, + ARRAY_SIZE(mddi_toshiba_init_table)); + client_data->auto_hibernate(client_data, 1); + g_panel_id = panel_id = + (client_data->remote_read(client_data, GPIODATA) >> 4) & 3; + if (panel_id > 1) { + printk(KERN_ERR "unknown panel id at mddi_enable\n"); + return -1; + } + return 0; +} + +static int sapphire_mddi_toshiba_client_uninit( + struct msm_mddi_bridge_platform_data *bridge_data, + struct msm_mddi_client_data *client_data) +{ + return 0; +} + +static int sapphire_mddi_panel_unblank( + struct msm_mddi_bridge_platform_data *bridge_data, + struct msm_mddi_client_data *client_data) +{ + int panel_id, ret = 0; + + sapphire_set_backlight_level(0); + client_data->auto_hibernate(client_data, 0); + sapphire_process_mddi_table(client_data, mddi_toshiba_panel_init_table, + ARRAY_SIZE(mddi_toshiba_panel_init_table)); + panel_id = (client_data->remote_read(client_data, GPIODATA) >> 4) & 3; + switch (panel_id) { + case 0: + printk(KERN_DEBUG "init sharp panel\n"); + sapphire_process_mddi_table(client_data, + mddi_sharp_init_table, + ARRAY_SIZE(mddi_sharp_init_table)); + break; + case 1: + printk(KERN_DEBUG "init tpo panel\n"); + sapphire_process_mddi_table(client_data, + mddi_tpo_init_table, + ARRAY_SIZE(mddi_tpo_init_table)); + break; + default: + printk(KERN_DEBUG "unknown panel_id: %d\n", panel_id); + ret = -1; + }; + mutex_lock(&sapphire_backlight_lock); + sapphire_set_backlight_level(sapphire_backlight_brightness); + sapphire_backlight_off = 0; + mutex_unlock(&sapphire_backlight_lock); + client_data->auto_hibernate(client_data, 1); + /* reenable vsync */ + client_data->remote_write(client_data, GPIOSEL_VWAKEINT, + GPIOSEL); + client_data->remote_write(client_data, INTMASK_VWAKEOUT, + INTMASK); + return ret; + +} + +static int sapphire_mddi_panel_blank( + struct msm_mddi_bridge_platform_data *bridge_data, + struct msm_mddi_client_data *client_data) +{ + int panel_id, ret = 0; + + panel_id = (client_data->remote_read(client_data, GPIODATA) >> 4) & 3; + client_data->auto_hibernate(client_data, 0); + switch (panel_id) { + case 0: + printk(KERN_DEBUG "deinit sharp panel\n"); + sapphire_process_mddi_table(client_data, + mddi_sharp_deinit_table, + ARRAY_SIZE(mddi_sharp_deinit_table)); + break; + case 1: + printk(KERN_DEBUG "deinit tpo panel\n"); + sapphire_process_mddi_table(client_data, + mddi_tpo_deinit_table, + ARRAY_SIZE(mddi_tpo_deinit_table)); + break; + default: + printk(KERN_DEBUG "unknown panel_id: %d\n", panel_id); + ret = -1; + }; + client_data->auto_hibernate(client_data, 1); + mutex_lock(&sapphire_backlight_lock); + sapphire_set_backlight_level(0); + sapphire_backlight_off = 1; + mutex_unlock(&sapphire_backlight_lock); + client_data->remote_write(client_data, 0, SYSCLKENA); + client_data->remote_write(client_data, 1, DPSUS); + + return ret; +} + +static void sapphire_brightness_set(struct led_classdev *led_cdev, enum led_brightness value) +{ + mutex_lock(&sapphire_backlight_lock); + sapphire_backlight_brightness = value; + if (!sapphire_backlight_off) + sapphire_set_backlight_level(sapphire_backlight_brightness); + mutex_unlock(&sapphire_backlight_lock); +} + +static struct led_classdev sapphire_backlight_led = { + .name = "lcd-backlight", + .brightness = SAPPHIRE_DEFAULT_BACKLIGHT_BRIGHTNESS, + .brightness_set = sapphire_brightness_set, +}; + +static int sapphire_backlight_probe(struct platform_device *pdev) +{ + led_classdev_register(&pdev->dev, &sapphire_backlight_led); + return 0; +} + +static int sapphire_backlight_remove(struct platform_device *pdev) +{ + led_classdev_unregister(&sapphire_backlight_led); + return 0; +} + +static struct platform_driver sapphire_backlight_driver = { + .probe = sapphire_backlight_probe, + .remove = sapphire_backlight_remove, + .driver = { + .name = "sapphire-backlight", + .owner = THIS_MODULE, + }, +}; + +static struct resource resources_msm_fb[] = { + { + .start = SMI64_MSM_FB_BASE, + .end = SMI64_MSM_FB_BASE + SMI64_MSM_FB_SIZE - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct msm_mddi_bridge_platform_data toshiba_client_data = { + .init = sapphire_mddi_toshiba_client_init, + .uninit = sapphire_mddi_toshiba_client_uninit, + .blank = sapphire_mddi_panel_blank, + .unblank = sapphire_mddi_panel_unblank, + .fb_data = { + .xres = 320, + .yres = 480, + .width = 45, + .height = 67, + .output_format = 0, + }, +}; + +static struct msm_mddi_platform_data mddi_pdata = { + .clk_rate = 122880000, + .power_client = sapphire_mddi_power_client, + .fb_resource = resources_msm_fb, + .num_clients = 1, + .client_platform_data = { + { + .product_id = (0xd263 << 16 | 0), + .name = "mddi_c_d263_0000", + .id = 0, + .client_data = &toshiba_client_data, + .clk_rate = 0, + }, + }, +}; + +static struct platform_device sapphire_backlight = { + .name = "sapphire-backlight", +}; + +int __init sapphire_init_panel(void) +{ + int rc = -1; + uint32_t config = PCOM_GPIO_CFG(27, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA); /* GPIO27 */ + + if (!machine_is_sapphire()) + return 0; + + /* checking board as soon as possible */ + printk("sapphire_init_panel:machine_is_sapphire=%d, machine_arch_type=%d, MACH_TYPE_SAPPHIRE=%d\r\n", machine_is_sapphire(), machine_arch_type, MACH_TYPE_SAPPHIRE); + if (!machine_is_sapphire()) + return 0; + + vreg_lcm_2v85 = vreg_get(0, "gp4"); + if (IS_ERR(vreg_lcm_2v85)) + return PTR_ERR(vreg_lcm_2v85); + + msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &config, 0); + + /* setup FB by SMI size */ + if (sapphire_get_smi_size() == 32) { + resources_msm_fb[0].start = SMI32_MSM_FB_BASE; + resources_msm_fb[0].end = SMI32_MSM_FB_BASE + SMI32_MSM_FB_SIZE - 1; + } + + rc = platform_device_register(&msm_device_mdp); + if (rc) + return rc; + msm_device_mddi0.dev.platform_data = &mddi_pdata; + rc = platform_device_register(&msm_device_mddi0); + if (rc) + return rc; + platform_device_register(&sapphire_backlight); + return platform_driver_register(&sapphire_backlight_driver); +} + +device_initcall(sapphire_init_panel); diff --git a/arch/arm/mach-msm/board-sapphire-rfkill.c b/arch/arm/mach-msm/board-sapphire-rfkill.c new file mode 100644 index 000000000000..135ffe82c328 --- /dev/null +++ b/arch/arm/mach-msm/board-sapphire-rfkill.c @@ -0,0 +1,99 @@ +/* linux/arch/arm/mach-msm/board-sapphire-rfkill.c + * Copyright (C) 2007-2009 HTC Corporation. + * Author: Thomas Tsai + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. +*/ + +/* Control bluetooth power for sapphire platform */ + +#include +#include +#include +#include +#include +#include +#include +#include "gpio_chip.h" +#include "board-sapphire.h" + +void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state); + +static struct rfkill *bt_rfk; +static const char bt_name[] = "brf6300"; + +extern int sapphire_bt_fastclock_power(int on); + +static int bluetooth_set_power(void *data, enum rfkill_state state) +{ + switch (state) { + case RFKILL_STATE_UNBLOCKED: + sapphire_bt_fastclock_power(1); + gpio_set_value(SAPPHIRE_GPIO_BT_32K_EN, 1); + udelay(10); + gpio_configure(101, GPIOF_DRIVE_OUTPUT | GPIOF_OUTPUT_HIGH); + break; + case RFKILL_STATE_SOFT_BLOCKED: + gpio_configure(101, GPIOF_DRIVE_OUTPUT | GPIOF_OUTPUT_LOW); + gpio_set_value(SAPPHIRE_GPIO_BT_32K_EN, 0); + sapphire_bt_fastclock_power(0); + break; + default: + printk(KERN_ERR "bad bluetooth rfkill state %d\n", state); + } + return 0; +} + +static int __init sapphire_rfkill_probe(struct platform_device *pdev) +{ + int rc = 0; + + /* default to bluetooth off */ + rfkill_switch_all(RFKILL_TYPE_BLUETOOTH, RFKILL_STATE_SOFT_BLOCKED); + bluetooth_set_power(NULL, RFKILL_STATE_SOFT_BLOCKED); + + bt_rfk = rfkill_allocate(&pdev->dev, RFKILL_TYPE_BLUETOOTH); + if (!bt_rfk) + return -ENOMEM; + + bt_rfk->name = bt_name; + bt_rfk->state = RFKILL_STATE_SOFT_BLOCKED; + /* userspace cannot take exclusive control */ + bt_rfk->user_claim_unsupported = 1; + bt_rfk->user_claim = 0; + bt_rfk->data = NULL; /* user data */ + bt_rfk->toggle_radio = bluetooth_set_power; + + rc = rfkill_register(bt_rfk); + + if (rc) + rfkill_free(bt_rfk); + return rc; +} + +static struct platform_driver sapphire_rfkill_driver = { + .probe = sapphire_rfkill_probe, + .driver = { + .name = "sapphire_rfkill", + .owner = THIS_MODULE, + }, +}; + +static int __init sapphire_rfkill_init(void) +{ + if (!machine_is_sapphire()) + return 0; + return platform_driver_register(&sapphire_rfkill_driver); +} + +module_init(sapphire_rfkill_init); +MODULE_DESCRIPTION("sapphire rfkill"); +MODULE_AUTHOR("Nick Pelly "); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-msm/board-sapphire-wifi.c b/arch/arm/mach-msm/board-sapphire-wifi.c new file mode 100644 index 000000000000..43f827c60f13 --- /dev/null +++ b/arch/arm/mach-msm/board-sapphire-wifi.c @@ -0,0 +1,74 @@ +/* arch/arm/mach-msm/board-sapphire-wifi.c + * + * Copyright (C) 2008 Google, Inc. + * Author: Dmitry Shmidt + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#ifdef CONFIG_WIFI_CONTROL_FUNC +#include +#include +#include +#include +#include +#include + +extern int sapphire_wifi_set_carddetect(int val); +extern int sapphire_wifi_power(int on); +extern int sapphire_wifi_reset(int on); + +#ifdef CONFIG_WIFI_MEM_PREALLOC +typedef struct wifi_mem_prealloc_struct { + void *mem_ptr; + unsigned long size; +} wifi_mem_prealloc_t; + +static wifi_mem_prealloc_t wifi_mem_array[WMPA_NUMBER_OF_SECTIONS] = { + { NULL, (WMPA_SECTION_SIZE_0 + WMPA_SECTION_HEADER) }, + { NULL, (WMPA_SECTION_SIZE_1 + WMPA_SECTION_HEADER) }, + { NULL, (WMPA_SECTION_SIZE_2 + WMPA_SECTION_HEADER) } +}; + +static void *sapphire_wifi_mem_prealloc(int section, unsigned long size) +{ + if ((section < 0) || (section >= WMPA_NUMBER_OF_SECTIONS)) + return NULL; + if (wifi_mem_array[section].size < size) + return NULL; + return wifi_mem_array[section].mem_ptr; +} + +int __init sapphire_init_wifi_mem (void) +{ + int i; + + for (i = 0; (i < WMPA_NUMBER_OF_SECTIONS); i++) { + wifi_mem_array[i].mem_ptr = vmalloc(wifi_mem_array[i].size); + if (wifi_mem_array[i].mem_ptr == NULL) + return -ENOMEM; + } + return 0; +} +#endif + +struct wifi_platform_data sapphire_wifi_control = { + .set_power = sapphire_wifi_power, + .set_reset = sapphire_wifi_reset, + .set_carddetect = sapphire_wifi_set_carddetect, +#ifdef CONFIG_WIFI_MEM_PREALLOC + .mem_prealloc = sapphire_wifi_mem_prealloc, +#else + .mem_prealloc = NULL, +#endif +}; + +#endif diff --git a/arch/arm/mach-msm/board-sapphire.c b/arch/arm/mach-msm/board-sapphire.c new file mode 100644 index 000000000000..4a34f94f21ee --- /dev/null +++ b/arch/arm/mach-msm/board-sapphire.c @@ -0,0 +1,1175 @@ +/* linux/arch/arm/mach-msm/board-sapphire.c + * Copyright (C) 2007-2009 HTC Corporation. + * Author: Thomas Tsai + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 +#include +#ifdef CONFIG_USB_FUNCTION +#include +#endif +#ifdef CONFIG_USB_ANDROID +#include +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + + +#include "gpio_chip.h" +#include "board-sapphire.h" + +#include +#include +#include +#include +#include + +#ifdef CONFIG_WIFI_CONTROL_FUNC +#ifdef CONFIG_WIFI_MEM_PREALLOC +extern int sapphire_init_wifi_mem(void); +#endif +extern struct wifi_platform_data sapphire_wifi_control; +#endif + +#include "proc_comm.h" +#include "devices.h" + +void msm_init_irq(void); +void msm_init_gpio(void); +void msm_init_pmic_vibrator(void); + +extern int sapphire_init_mmc(unsigned int); + +struct sapphire_axis_info { + struct gpio_event_axis_info info; + uint16_t in_state; + uint16_t out_state; + uint16_t temp_state; + uint16_t threshold; +}; +static bool nav_just_on; +static int nav_on_jiffies; +static int smi_sz = 64; +static unsigned int hwid = 0; +static unsigned int skuid = 0; +static unsigned engineerid = (0x01 << 1); /* default is 3M sensor */ + +uint16_t sapphire_axis_map(struct gpio_event_axis_info *info, uint16_t in) +{ + struct sapphire_axis_info *ai = container_of(info, struct sapphire_axis_info, info); + uint16_t out = ai->out_state; + + if (nav_just_on) { + if (jiffies == nav_on_jiffies || jiffies == nav_on_jiffies + 1) + goto ignore; + nav_just_on = 0; + } + if ((ai->in_state ^ in) & 1) + out--; + if ((ai->in_state ^ in) & 2) + out++; + ai->out_state = out; +ignore: + ai->in_state = in; + if (ai->out_state - ai->temp_state == ai->threshold) { + ai->temp_state++; + ai->out_state = ai->temp_state; + } else if (ai->temp_state - ai->out_state == ai->threshold) { + ai->temp_state--; + ai->out_state = ai->temp_state; + } else if (abs(ai->out_state - ai->temp_state) > ai->threshold) + ai->temp_state = ai->out_state; + + return ai->temp_state; +} + +int sapphire_nav_power(const struct gpio_event_platform_data *pdata, bool on) +{ + gpio_set_value(SAPPHIRE_GPIO_JOG_EN, on); + if (on) { + nav_just_on = 1; + nav_on_jiffies = jiffies; + } + return 0; +} + +static uint32_t sapphire_x_axis_gpios[] = { + SAPPHIRE_BALL_LEFT_0, SAPPHIRE_BALL_RIGHT_0 +}; + +static struct sapphire_axis_info sapphire_x_axis = { + .threshold = 2, + .info = { + .info.func = gpio_event_axis_func, + .count = ARRAY_SIZE(sapphire_x_axis_gpios), + .type = EV_REL, + .code = REL_X, + .decoded_size = 1U << ARRAY_SIZE(sapphire_x_axis_gpios), + .map = sapphire_axis_map, + .gpio = sapphire_x_axis_gpios, + .flags = GPIOEAF_PRINT_UNKNOWN_DIRECTION /*| GPIOEAF_PRINT_RAW | GPIOEAF_PRINT_EVENT */ + } +}; + +static uint32_t sapphire_y_axis_gpios[] = { + SAPPHIRE_BALL_UP_0, SAPPHIRE_BALL_DOWN_0 +}; + +static struct sapphire_axis_info sapphire_y_axis = { + .threshold = 2, + .info = { + .info.func = gpio_event_axis_func, + .count = ARRAY_SIZE(sapphire_y_axis_gpios), + .type = EV_REL, + .code = REL_Y, + .decoded_size = 1U << ARRAY_SIZE(sapphire_y_axis_gpios), + .map = sapphire_axis_map, + .gpio = sapphire_y_axis_gpios, + .flags = GPIOEAF_PRINT_UNKNOWN_DIRECTION /*| GPIOEAF_PRINT_RAW | GPIOEAF_PRINT_EVENT */ + } +}; + +static struct gpio_event_direct_entry sapphire_nav_buttons[] = { + { SAPPHIRE_GPIO_NAVI_ACT_N, BTN_MOUSE }, + { SAPPHIRE_GPIO_SEARCH_ACT_N, KEY_COMPOSE }, /* CPLD Key Search */ +}; + +static struct gpio_event_input_info sapphire_nav_button_info = { + .info.func = gpio_event_input_func, + .flags = GPIOEDF_PRINT_KEYS | GPIOEDF_PRINT_KEY_DEBOUNCE, + .poll_time.tv.nsec = 40 * NSEC_PER_MSEC, + .type = EV_KEY, + .keymap = sapphire_nav_buttons, + .keymap_size = ARRAY_SIZE(sapphire_nav_buttons) +}; + +static struct gpio_event_info *sapphire_nav_info[] = { + &sapphire_x_axis.info.info, + &sapphire_y_axis.info.info, + &sapphire_nav_button_info.info +}; + +static struct gpio_event_platform_data sapphire_nav_data = { + .name = "sapphire-nav", + .info = sapphire_nav_info, + .info_count = ARRAY_SIZE(sapphire_nav_info), + .power = sapphire_nav_power, +}; + +static struct platform_device sapphire_nav_device = { + .name = GPIO_EVENT_DEV_NAME, + .id = 2, + .dev = { + .platform_data = &sapphire_nav_data, + }, +}; + +static int sapphire_reset_keys_up[] = { + BTN_MOUSE, + 0 +}; + +static struct keyreset_platform_data sapphire_reset_keys_pdata = { + .keys_up = sapphire_reset_keys_up, + .keys_down = { + KEY_SEND, + KEY_MENU, + KEY_END, + 0 + }, +}; + +struct platform_device sapphire_reset_keys_device = { + .name = KEYRESET_NAME, + .dev.platform_data = &sapphire_reset_keys_pdata, +}; + +static int sapphire_ts_power(int on) +{ + int gpio_tp_ls_en = SAPPHIRE_TP_LS_EN; + + if (is_12pin_camera()) + gpio_tp_ls_en = SAPPHIRE20_TP_LS_EN; + + if (on) { + sapphire_gpio_write(NULL, SAPPHIRE_GPIO_TP_EN, 1); + /* touchscreen must be powered before we enable i2c pullup */ + msleep(2); + /* enable touch panel level shift */ + gpio_set_value(gpio_tp_ls_en, 1); + msleep(2); + } else { + gpio_set_value(gpio_tp_ls_en, 0); + sapphire_gpio_write(NULL, SAPPHIRE_GPIO_TP_EN, 0); + } + + return 0; +} + +static struct synaptics_i2c_rmi_platform_data sapphire_ts_data[] = { +{ + .version = 0x0101, + .power = sapphire_ts_power, + .flags = SYNAPTICS_FLIP_Y | SYNAPTICS_SNAP_TO_INACTIVE_EDGE, + .inactive_left = -50 * 0x10000 / 4334, + .inactive_right = -50 * 0x10000 / 4334, + .inactive_top = -40 * 0x10000 / 6696, + .inactive_bottom = -40 * 0x10000 / 6696, + .snap_left_on = 50 * 0x10000 / 4334, + .snap_left_off = 60 * 0x10000 / 4334, + .snap_right_on = 50 * 0x10000 / 4334, + .snap_right_off = 60 * 0x10000 / 4334, + .snap_top_on = 100 * 0x10000 / 6696, + .snap_top_off = 110 * 0x10000 / 6696, + .snap_bottom_on = 100 * 0x10000 / 6696, + .snap_bottom_off = 110 * 0x10000 / 6696, + }, + { + .flags = SYNAPTICS_FLIP_Y | SYNAPTICS_SNAP_TO_INACTIVE_EDGE, + .inactive_left = ((4674 - 4334) / 2 + 200) * 0x10000 / 4334, + .inactive_right = ((4674 - 4334) / 2 + 200) * 0x10000 / 4334, + .inactive_top = ((6946 - 6696) / 2) * 0x10000 / 6696, + .inactive_bottom = ((6946 - 6696) / 2) * 0x10000 / 6696, + } +}; + +static struct akm8976_platform_data compass_platform_data = { + .reset = SAPPHIRE_GPIO_COMPASS_RST_N, + .clk_on = SAPPHIRE_GPIO_COMPASS_32K_EN, + .intr = SAPPHIRE_GPIO_COMPASS_IRQ, +}; + +static struct elan_i2c_platform_data elan_i2c_data[] = { + { + .version = 0x104, + .abs_x_min = 0, + .abs_y_min = 0, + .intr_gpio = SAPPHIRE_GPIO_TP_ATT_N, + .power = sapphire_ts_power, + }, + { + .version = 0x103, + .abs_x_min = 0, + .abs_x_max = 512 * 2, + .abs_y_min = 0, + .abs_y_max = 896 * 2, + .intr_gpio = SAPPHIRE_GPIO_TP_ATT_N, + .power = sapphire_ts_power, + }, + { + .version = 0x102, + .abs_x_min = 0, + .abs_x_max = 384, + .abs_y_min = 0, + .abs_y_max = 576, + .intr_gpio = SAPPHIRE_GPIO_TP_ATT_N, + .power = sapphire_ts_power, + }, + { + .version = 0x101, + .abs_x_min = 32 + 1, + .abs_x_max = 352 - 1, + .abs_y_min = 32 + 1, + .abs_y_max = 544 - 1, + .intr_gpio = SAPPHIRE_GPIO_TP_ATT_N, + .power = sapphire_ts_power, + } +}; + +static struct msm_camera_device_platform_data msm_camera_device_mt9t013 = { + .sensor_reset = 108, + .sensor_pwd = 85, + .vcm_pwd = SAPPHIRE_GPIO_VCM_PWDN, + .config_gpio_on = config_sapphire_camera_on_gpios, + .config_gpio_off = config_sapphire_camera_off_gpios, +}; + +static struct platform_device sapphire_camera = { + .name = "camera", + .dev = { + .platform_data = &msm_camera_device_mt9t013, + }, +}; + +static struct i2c_board_info i2c_devices[] = { + { + I2C_BOARD_INFO(SYNAPTICS_I2C_RMI_NAME, 0x20), + .platform_data = sapphire_ts_data, + .irq = SAPPHIRE_GPIO_TO_INT(SAPPHIRE_GPIO_TP_ATT_N) + }, + { + I2C_BOARD_INFO(ELAN_8232_I2C_NAME, 0x10), + .platform_data = &elan_i2c_data, + .irq = SAPPHIRE_GPIO_TO_INT(SAPPHIRE_GPIO_TP_ATT_N), + }, + { + I2C_BOARD_INFO("akm8976", 0x1C), + .platform_data = &compass_platform_data, + .irq = SAPPHIRE_GPIO_TO_INT(SAPPHIRE_GPIO_COMPASS_IRQ), + }, + { + I2C_BOARD_INFO("mt9t013", 0x6C >> 1), + .platform_data = &msm_camera_device_mt9t013, + }, +}; + +#ifdef CONFIG_LEDS_CPLD +static struct resource cpldled_resources[] = { + { + .start = SAPPHIRE_CPLD_LED_BASE, + .end = SAPPHIRE_CPLD_LED_BASE + SAPPHIRE_CPLD_LED_SIZE - 1, + .flags = IORESOURCE_MEM, + } +}; + +static struct platform_device android_CPLD_leds = { + .name = "leds-cpld", + .id = -1, + .num_resources = ARRAY_SIZE(cpldled_resources), + .resource = cpldled_resources, +}; +#endif + +#if 0 +static struct gpio_led android_led_list[] = { + { + .name = "button-backlight", + .gpio = SAPPHIRE_GPIO_APKEY_LED_EN, + }, +}; + +static struct gpio_led_platform_data android_leds_data = { + .num_leds = ARRAY_SIZE(android_led_list), + .leds = android_led_list, +}; + +static struct platform_device android_leds = { + .name = "leds-gpio", + .id = -1, + .dev = { + .platform_data = &android_leds_data, + }, +}; +#endif + +#ifdef CONFIG_HTC_HEADSET +/* RTS/CTS to GPO/GPI. */ +static uint32_t uart1_on_gpio_table[] = { + /* allenou, uart hs test, 2008/11/18 */ + #ifdef CONFIG_SERIAL_MSM_HS + /* RTS */ + PCOM_GPIO_CFG(SAPPHIRE_GPIO_UART1_RTS, 2, + GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + /* CTS */ + PCOM_GPIO_CFG(SAPPHIRE_GPIO_UART1_CTS, 2, + GPIO_INPUT, GPIO_PULL_UP, GPIO_8MA), + #else + /* RTS */ + PCOM_GPIO_CFG(SAPPHIRE_GPIO_UART1_RTS, 1, + GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), + /* CTS */ + PCOM_GPIO_CFG(SAPPHIRE_GPIO_UART1_CTS, 1, + GPIO_INPUT, GPIO_PULL_DOWN, GPIO_4MA), + #endif +}; + +/* RTS,CTS to BT. */ +static uint32_t uart1_off_gpio_table[] = { + /* RTS */ + PCOM_GPIO_CFG(SAPPHIRE_GPIO_UART1_RTS, 0, + GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), + /* CTS */ + PCOM_GPIO_CFG(SAPPHIRE_GPIO_UART1_CTS, 0, + GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), +}; + +/* Sapphire: Switch between UART3 and GPIO */ +static uint32_t uart3_on_gpio_table[] = { + /* RX */ + PCOM_GPIO_CFG(SAPPHIRE_GPIO_UART3_RX, 1, + GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), + /* TX */ + PCOM_GPIO_CFG(SAPPHIRE_GPIO_UART3_TX, 1, + GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), +}; + +/* set TX,RX to GPI */ +static uint32_t uart3_off_gpi_table[] = { + /* RX, H2W DATA */ + PCOM_GPIO_CFG(SAPPHIRE_GPIO_H2W_DATA, 0, + GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), + /* TX, H2W CLK */ + PCOM_GPIO_CFG(SAPPHIRE_GPIO_H2W_CLK, 0, + GPIO_INPUT, GPIO_KEEPER, GPIO_2MA), +}; + +static int sapphire_h2w_path = H2W_GPIO; + +static void h2w_config_cpld(int route) +{ + switch (route) { + case H2W_UART1: + /* Make sure uart1 funtion pin opened. */ + msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, + uart1_on_gpio_table+0, 0); + msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, + uart1_on_gpio_table+1, 0); + gpio_set_value(SAPPHIRE_GPIO_H2W_SEL0, 1); + gpio_set_value(SAPPHIRE_GPIO_H2W_SEL1, 0); + sapphire_h2w_path = H2W_UART1; + printk(KERN_INFO "H2W route = H2W-UART1, BT-X, UART3-X \n"); + break; + case H2W_BT: + gpio_set_value(SAPPHIRE_GPIO_H2W_SEL0, 1); + gpio_set_value(SAPPHIRE_GPIO_H2W_SEL1, 1); + /* UART1 RTS/CTS to GPO/GPI. */ + msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, + uart1_off_gpio_table+0, 0); + msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, + uart1_off_gpio_table+1, 0); + sapphire_h2w_path = H2W_BT; + printk(KERN_INFO "H2W route = H2W-BT, UART1-X, UART3-X \n"); + break; + case H2W_UART3: + msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, + uart3_on_gpio_table+0, 0); + msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, + uart3_on_gpio_table+1, 0); + gpio_set_value(SAPPHIRE_GPIO_H2W_SEL0, 0); + gpio_set_value(SAPPHIRE_GPIO_H2W_SEL1, 1); + /* Make sure uart1 funtion pin opened. */ + msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, + uart1_on_gpio_table+0, 0); + msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, + uart1_on_gpio_table+1, 0); + sapphire_h2w_path = H2W_UART3; + printk(KERN_INFO "H2W route = H2W-UART3, BT-UART1 \n"); + break; + case H2W_GPIO: /*H2W_UART3 TX,RX are changed to H2W_GPIO */ + default: + gpio_set_value(SAPPHIRE_GPIO_H2W_SEL0, 0); + gpio_set_value(SAPPHIRE_GPIO_H2W_SEL1, 0); + /* Set the CPLD connected H2W GPIO's to input */ + gpio_set_value(SAPPHIRE_GPIO_H2W_CLK_DIR, 0); + gpio_set_value(SAPPHIRE_GPIO_H2W_DAT_DIR, 0); + /* TX,RX GPI first. */ + msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, + uart3_off_gpi_table+0, 0); + msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, + uart3_off_gpi_table+1, 0); + /* Make sure uart1 funtion pin opened. */ + msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, + uart1_on_gpio_table+0, 0); + msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, + uart1_on_gpio_table+1, 0); + sapphire_h2w_path = H2W_GPIO; + printk(KERN_INFO "H2W route = H2W-GPIO, BT-UART1 \n"); + break; + } +} + +static void h2w_init_cpld(void) +{ + h2w_config_cpld(H2W_GPIO); +} + +static void set_h2w_dat(int n) +{ + gpio_set_value(SAPPHIRE_GPIO_H2W_DATA, n); +} + +static void set_h2w_clk(int n) +{ + gpio_set_value(SAPPHIRE_GPIO_H2W_CLK, n); +} + +static void set_h2w_dat_dir(int n) +{ + if (n == 0) /* input */ + gpio_direction_input(SAPPHIRE_GPIO_H2W_DATA); + else + gpio_configure(SAPPHIRE_GPIO_H2W_DATA, GPIOF_DRIVE_OUTPUT); + + gpio_set_value(SAPPHIRE_GPIO_H2W_DAT_DIR, n); + +} + +static void set_h2w_clk_dir(int n) +{ + if (n == 0) /* input */ + gpio_direction_input(SAPPHIRE_GPIO_H2W_CLK); + else + gpio_configure(SAPPHIRE_GPIO_H2W_CLK, GPIOF_DRIVE_OUTPUT); + + gpio_set_value(SAPPHIRE_GPIO_H2W_CLK_DIR, n); +} + +static int get_h2w_dat(void) +{ + return gpio_get_value(SAPPHIRE_GPIO_H2W_DATA); +} + +static int get_h2w_clk(void) +{ + return gpio_get_value(SAPPHIRE_GPIO_H2W_CLK); +} + +static int set_h2w_path(const char *val, struct kernel_param *kp) +{ + int ret = -EINVAL; + + ret = param_set_int(val, kp); + if (ret) + return ret; + + switch (sapphire_h2w_path) { + case H2W_GPIO: + case H2W_UART1: + case H2W_UART3: + case H2W_BT: + break; + default: + sapphire_h2w_path = -1; + return -EINVAL; + } + + h2w_config_cpld(sapphire_h2w_path); + return ret; +} +module_param_call(h2w_path, set_h2w_path, param_get_int, + &sapphire_h2w_path, S_IWUSR | S_IRUGO); + + +static struct h2w_platform_data sapphire_h2w_data = { + .power_name = "wlan", + .cable_in1 = SAPPHIRE_GPIO_CABLE_IN1, + .cable_in2 = SAPPHIRE_GPIO_CABLE_IN2, + .h2w_clk = SAPPHIRE_GPIO_H2W_CLK, + .h2w_data = SAPPHIRE_GPIO_H2W_DATA, + .debug_uart = H2W_UART3, + .config_cpld = h2w_config_cpld, + .init_cpld = h2w_init_cpld, + .set_dat = set_h2w_dat, + .set_clk = set_h2w_clk, + .set_dat_dir = set_h2w_dat_dir, + .set_clk_dir = set_h2w_clk_dir, + .get_dat = get_h2w_dat, + .get_clk = get_h2w_clk, +}; + +static struct platform_device sapphire_h2w = { + .name = "h2w", + .id = -1, + .dev = { + .platform_data = &sapphire_h2w_data, + }, +}; +#endif + +#ifdef CONFIG_USB_FUNCTION +static void sapphire_phy_reset(void) +{ + gpio_set_value(SAPPHIRE_GPIO_USB_PHY_RST_N, 0); + mdelay(10); + gpio_set_value(SAPPHIRE_GPIO_USB_PHY_RST_N, 1); + mdelay(10); +} +#endif + +static struct pwr_sink sapphire_pwrsink_table[] = { + { + .id = PWRSINK_AUDIO, + .ua_max = 100000, + }, + { + .id = PWRSINK_BACKLIGHT, + .ua_max = 125000, + }, + { + .id = PWRSINK_LED_BUTTON, + .ua_max = 0, + }, + { + .id = PWRSINK_LED_KEYBOARD, + .ua_max = 0, + }, + { + .id = PWRSINK_GP_CLK, + .ua_max = 0, + }, + { + .id = PWRSINK_BLUETOOTH, + .ua_max = 15000, + }, + { + .id = PWRSINK_CAMERA, + .ua_max = 0, + }, + { + .id = PWRSINK_SDCARD, + .ua_max = 0, + }, + { + .id = PWRSINK_VIDEO, + .ua_max = 0, + }, + { + .id = PWRSINK_WIFI, + .ua_max = 200000, + }, + { + .id = PWRSINK_SYSTEM_LOAD, + .ua_max = 100000, + .percent_util = 38, + }, +}; + +static struct pwr_sink_platform_data sapphire_pwrsink_data = { + .num_sinks = ARRAY_SIZE(sapphire_pwrsink_table), + .sinks = sapphire_pwrsink_table, + .suspend_late = NULL, + .resume_early = NULL, + .suspend_early = NULL, + .resume_late = NULL, +}; + +static struct platform_device sapphire_pwr_sink = { + .name = "htc_pwrsink", + .id = -1, + .dev = { + .platform_data = &sapphire_pwrsink_data, + }, +}; + +static struct platform_device sapphire_rfkill = { + .name = "sapphire_rfkill", + .id = -1, +}; + +static struct msm_pmem_setting pmem_setting_32 = { + .pmem_start = SMI32_MSM_PMEM_MDP_BASE, + .pmem_size = SMI32_MSM_PMEM_MDP_SIZE, + .pmem_adsp_start = SMI32_MSM_PMEM_ADSP_BASE, + .pmem_adsp_size = SMI32_MSM_PMEM_ADSP_SIZE, + .pmem_gpu0_start = MSM_PMEM_GPU0_BASE, + .pmem_gpu0_size = MSM_PMEM_GPU0_SIZE, + .pmem_gpu1_start = MSM_PMEM_GPU1_BASE, + .pmem_gpu1_size = MSM_PMEM_GPU1_SIZE, + .pmem_camera_start = 0, + .pmem_camera_size = 0, + .ram_console_start = MSM_RAM_CONSOLE_BASE, + .ram_console_size = MSM_RAM_CONSOLE_SIZE, +}; + +static struct msm_pmem_setting pmem_setting_64 = { + .pmem_start = SMI64_MSM_PMEM_MDP_BASE, + .pmem_size = SMI64_MSM_PMEM_MDP_SIZE, + .pmem_adsp_start = SMI64_MSM_PMEM_ADSP_BASE, + .pmem_adsp_size = SMI64_MSM_PMEM_ADSP_SIZE, + .pmem_gpu0_start = MSM_PMEM_GPU0_BASE, + .pmem_gpu0_size = MSM_PMEM_GPU0_SIZE, + .pmem_gpu1_start = MSM_PMEM_GPU1_BASE, + .pmem_gpu1_size = MSM_PMEM_GPU1_SIZE, + .pmem_camera_start = SMI64_MSM_PMEM_CAMERA_BASE, + .pmem_camera_size = SMI64_MSM_PMEM_CAMERA_SIZE, + .ram_console_start = MSM_RAM_CONSOLE_BASE, + .ram_console_size = MSM_RAM_CONSOLE_SIZE, +}; + +#ifdef CONFIG_WIFI_CONTROL_FUNC +static struct platform_device sapphire_wifi = { + .name = "msm_wifi", + .id = 1, + .num_resources = 0, + .resource = NULL, + .dev = { + .platform_data = &sapphire_wifi_control, + }, +}; +#endif + +#define SND(num, desc) { .name = desc, .id = num } +static struct snd_endpoint snd_endpoints_list[] = { + SND(0, "HANDSET"), + SND(1, "SPEAKER"), + SND(2, "HEADSET"), + SND(3, "BT"), + SND(44, "BT_EC_OFF"), + SND(10, "HEADSET_AND_SPEAKER"), + SND(256, "CURRENT"), + + /* Bluetooth accessories. */ + + SND(12, "HTC BH S100"), + SND(13, "HTC BH M100"), + SND(14, "Motorola H500"), + SND(15, "Nokia HS-36W"), + SND(16, "PLT 510v.D"), + SND(17, "M2500 by Plantronics"), + SND(18, "Nokia HDW-3"), + SND(19, "HBH-608"), + SND(20, "HBH-DS970"), + SND(21, "i.Tech BlueBAND"), + SND(22, "Nokia BH-800"), + SND(23, "Motorola H700"), + SND(24, "HTC BH M200"), + SND(25, "Jabra JX10"), + SND(26, "320Plantronics"), + SND(27, "640Plantronics"), + SND(28, "Jabra BT500"), + SND(29, "Motorola HT820"), + SND(30, "HBH-IV840"), + SND(31, "6XXPlantronics"), + SND(32, "3XXPlantronics"), + SND(33, "HBH-PV710"), + SND(34, "Motorola H670"), + SND(35, "HBM-300"), + SND(36, "Nokia BH-208"), + SND(37, "Samsung WEP410"), + SND(38, "Jabra BT8010"), + SND(39, "Motorola S9"), + SND(40, "Jabra BT620s"), + SND(41, "Nokia BH-902"), + SND(42, "HBH-DS220"), + SND(43, "HBH-DS980"), +}; +#undef SND + +static struct msm_snd_endpoints sapphire_snd_endpoints = { + .endpoints = snd_endpoints_list, + .num = ARRAY_SIZE(snd_endpoints_list), +}; + +static struct platform_device sapphire_snd = { + .name = "msm_snd", + .id = -1, + .dev = { + .platform_data = &sapphire_snd_endpoints, + }, +}; + +static struct platform_device *devices[] __initdata = { + &msm_device_smd, + &msm_device_nand, + &msm_device_i2c, + &msm_device_uart1, +#if !defined(CONFIG_MSM_SERIAL_DEBUGGER) && !defined(CONFIG_TROUT_H2W) + &msm_device_uart3, +#endif +#ifdef CONFIG_SERIAL_MSM_HS + &msm_device_uart_dm1, +#endif + &sapphire_nav_device, + &sapphire_reset_keys_device, +#ifdef CONFIG_LEDS_CPLD + &android_CPLD_leds, +#endif +#ifdef CONFIG_HTC_HEADSET + &sapphire_h2w, +#endif + &sapphire_rfkill, +#ifdef CONFIG_WIFI_CONTROL_FUNC + &sapphire_wifi, +#endif + +#ifdef CONFIG_HTC_PWRSINK + &sapphire_pwr_sink, +#endif + &sapphire_snd, + &sapphire_camera, +}; + +extern struct sys_timer msm_timer; + +static void __init sapphire_init_irq(void) +{ + printk(KERN_DEBUG "sapphire_init_irq()\n"); + msm_init_irq(); +} + +static uint cpld_iset; +static uint cpld_charger_en; +static uint cpld_usb_h2w_sw; +static uint opt_disable_uart3; + +module_param_named(iset, cpld_iset, uint, 0); +module_param_named(charger_en, cpld_charger_en, uint, 0); +module_param_named(usb_h2w_sw, cpld_usb_h2w_sw, uint, 0); +module_param_named(disable_uart3, opt_disable_uart3, uint, 0); + +static void sapphire_reset(void) +{ + gpio_set_value(SAPPHIRE_GPIO_PS_HOLD, 0); +} + +static uint32_t gpio_table[] = { + /* BLUETOOTH */ +#ifdef CONFIG_SERIAL_MSM_HS + PCOM_GPIO_CFG(43, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* RTS */ + PCOM_GPIO_CFG(44, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* CTS */ + PCOM_GPIO_CFG(45, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* RX */ + PCOM_GPIO_CFG(46, 3, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* TX */ +#else + PCOM_GPIO_CFG(43, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* RTS */ + PCOM_GPIO_CFG(44, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* CTS */ + PCOM_GPIO_CFG(45, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* RX */ + PCOM_GPIO_CFG(46, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* TX */ +#endif +}; + + +static uint32_t camera_off_gpio_table[] = { + /* CAMERA */ + PCOM_GPIO_CFG(2, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT2 */ + PCOM_GPIO_CFG(3, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT3 */ + PCOM_GPIO_CFG(4, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT4 */ + PCOM_GPIO_CFG(5, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT5 */ + PCOM_GPIO_CFG(6, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT6 */ + PCOM_GPIO_CFG(7, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT7 */ + PCOM_GPIO_CFG(8, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT8 */ + PCOM_GPIO_CFG(9, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT9 */ + PCOM_GPIO_CFG(10, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT10 */ + PCOM_GPIO_CFG(11, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT11 */ + PCOM_GPIO_CFG(12, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* PCLK */ + PCOM_GPIO_CFG(13, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* HSYNC_IN */ + PCOM_GPIO_CFG(14, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* VSYNC_IN */ + PCOM_GPIO_CFG(15, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* MCLK */ +}; + +static uint32_t camera_on_gpio_table[] = { + /* CAMERA */ + PCOM_GPIO_CFG(2, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT2 */ + PCOM_GPIO_CFG(3, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT3 */ + PCOM_GPIO_CFG(4, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT4 */ + PCOM_GPIO_CFG(5, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT5 */ + PCOM_GPIO_CFG(6, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT6 */ + PCOM_GPIO_CFG(7, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT7 */ + PCOM_GPIO_CFG(8, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT8 */ + PCOM_GPIO_CFG(9, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT9 */ + PCOM_GPIO_CFG(10, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT10 */ + PCOM_GPIO_CFG(11, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT11 */ + PCOM_GPIO_CFG(12, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_16MA), /* PCLK */ + PCOM_GPIO_CFG(13, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* HSYNC_IN */ + PCOM_GPIO_CFG(14, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* VSYNC_IN */ + PCOM_GPIO_CFG(15, 1, GPIO_OUTPUT, GPIO_PULL_DOWN, GPIO_16MA), /* MCLK */ +}; + +static uint32_t camera_off_gpio_12pins_table[] = { + /* CAMERA */ + PCOM_GPIO_CFG(0, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT0 */ + PCOM_GPIO_CFG(1, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT1 */ + PCOM_GPIO_CFG(2, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT2 */ + PCOM_GPIO_CFG(3, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT3 */ + PCOM_GPIO_CFG(4, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT4 */ + PCOM_GPIO_CFG(5, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT5 */ + PCOM_GPIO_CFG(6, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT6 */ + PCOM_GPIO_CFG(7, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT7 */ + PCOM_GPIO_CFG(8, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT8 */ + PCOM_GPIO_CFG(9, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT9 */ + PCOM_GPIO_CFG(10, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT10 */ + PCOM_GPIO_CFG(11, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT11 */ + PCOM_GPIO_CFG(12, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* PCLK */ + PCOM_GPIO_CFG(13, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* HSYNC_IN */ + PCOM_GPIO_CFG(14, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* VSYNC_IN */ + PCOM_GPIO_CFG(15, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* MCLK */ +}; + +static uint32_t camera_on_gpio_12pins_table[] = { + /* CAMERA */ + PCOM_GPIO_CFG(0, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT0 */ + PCOM_GPIO_CFG(1, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT1 */ + PCOM_GPIO_CFG(2, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT2 */ + PCOM_GPIO_CFG(3, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT3 */ + PCOM_GPIO_CFG(4, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT4 */ + PCOM_GPIO_CFG(5, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT5 */ + PCOM_GPIO_CFG(6, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT6 */ + PCOM_GPIO_CFG(7, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT7 */ + PCOM_GPIO_CFG(8, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT8 */ + PCOM_GPIO_CFG(9, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT9 */ + PCOM_GPIO_CFG(10, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT10 */ + PCOM_GPIO_CFG(11, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT11 */ + PCOM_GPIO_CFG(12, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_16MA), /* PCLK */ + PCOM_GPIO_CFG(13, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* HSYNC_IN */ + PCOM_GPIO_CFG(14, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* VSYNC_IN */ + PCOM_GPIO_CFG(15, 1, GPIO_OUTPUT, GPIO_PULL_DOWN, GPIO_16MA), /* MCLK */ +}; + +static void config_gpio_table(uint32_t *table, int len) +{ + int n; + unsigned id; + for (n = 0; n < len; n++) { + id = table[n]; + msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0); + } +} + +void config_sapphire_camera_on_gpios(void) +{ + /*Add for judage it's 10 pins or 12 pins platform ----->*/ + if (is_12pin_camera()) { + config_gpio_table(camera_on_gpio_12pins_table, + ARRAY_SIZE(camera_on_gpio_12pins_table)); + } else { + config_gpio_table(camera_on_gpio_table, + ARRAY_SIZE(camera_on_gpio_table)); + } + /*End Of Add for judage it's 10 pins or 12 pins platform*/ +} + +void config_sapphire_camera_off_gpios(void) +{ + /*Add for judage it's 10 pins or 12 pins platform ----->*/ + if (is_12pin_camera()) { + config_gpio_table(camera_off_gpio_12pins_table, + ARRAY_SIZE(camera_off_gpio_12pins_table)); + } else { + config_gpio_table(camera_off_gpio_table, + ARRAY_SIZE(camera_off_gpio_table)); + } + /*End Of Add for judage it's 10 pins or 12 pins platform*/ +} + +static void __init config_gpios(void) +{ + config_gpio_table(gpio_table, ARRAY_SIZE(gpio_table)); + config_sapphire_camera_off_gpios(); +} + +void msm_serial_debug_init(unsigned int base, int irq, + struct device *clk_device, int signal_irq); + +static struct msm_acpu_clock_platform_data sapphire_clock_data = { + .acpu_switch_time_us = 20, + .max_speed_delta_khz = 256000, + .vdd_switch_time_us = 62, + .power_collapse_khz = 19200000, + .wait_for_irq_khz = 128000000, +}; + +#ifdef CONFIG_SERIAL_MSM_HS +static struct msm_serial_hs_platform_data msm_uart_dm1_pdata = { + .wakeup_irq = MSM_GPIO_TO_INT(45), + .inject_rx_on_wakeup = 1, + .rx_to_inject = 0x32, +}; +#endif + +static void __init sapphire_init(void) +{ + int rc; + int i; + printk("sapphire_init() revision=%d\n", system_rev); + + /* + * Setup common MSM GPIOS + */ + config_gpios(); + + msm_hw_reset_hook = sapphire_reset; + + msm_acpu_clock_init(&sapphire_clock_data); + + /* adjust GPIOs based on bootloader request */ + printk("sapphire_init: cpld_usb_hw2_sw = %d\n", cpld_usb_h2w_sw); + gpio_set_value(SAPPHIRE_GPIO_USB_H2W_SW, cpld_usb_h2w_sw); + +#if defined(CONFIG_MSM_SERIAL_DEBUGGER) + if (!opt_disable_uart3) + msm_serial_debug_init(MSM_UART3_PHYS, INT_UART3, + &msm_device_uart3.dev, 1); +#endif + + /* gpio_configure(108, IRQF_TRIGGER_LOW); */ + + /* H2W pins <-> UART3, Bluetooth <-> UART1 */ + gpio_set_value(SAPPHIRE_GPIO_H2W_SEL0, 0); + gpio_set_value(SAPPHIRE_GPIO_H2W_SEL1, 1); + /* put the AF VCM in powerdown mode to avoid noise */ + if (sapphire_is_5M_camera()) + sapphire_gpio_write(NULL, SAPPHIRE_GPIO_VCM_PWDN, 0); + else + sapphire_gpio_write(NULL, SAPPHIRE_GPIO_VCM_PWDN, 1); + mdelay(100); + +#ifdef CONFIG_SERIAL_MSM_HS + msm_device_uart_dm1.dev.platform_data = &msm_uart_dm1_pdata; +#endif + msm_add_usb_devices(sapphire_phy_reset); + + if (32 == smi_sz) + msm_add_mem_devices(&pmem_setting_32); + else + msm_add_mem_devices(&pmem_setting_64); + + rc = sapphire_init_mmc(system_rev); + if (rc) + printk(KERN_CRIT "%s: MMC init failure (%d)\n", __func__, rc); + +#ifdef CONFIG_WIFI_MEM_PREALLOC + rc = sapphire_init_wifi_mem(); + if (rc) { + printk(KERN_CRIT "%s: WiFi memory init failure (%d)\n", + __func__, rc); + } +#endif + msm_init_pmic_vibrator(); + + platform_add_devices(devices, ARRAY_SIZE(devices)); + i2c_register_board_info(0, i2c_devices, ARRAY_SIZE(i2c_devices)); +} + +static struct map_desc sapphire_io_desc[] __initdata = { + { + .virtual = SAPPHIRE_CPLD_BASE, + .pfn = __phys_to_pfn(SAPPHIRE_CPLD_START), + .length = SAPPHIRE_CPLD_SIZE, + .type = MT_DEVICE_NONSHARED + } +}; + + +unsigned int sapphire_get_hwid(void) +{ + printk(KERN_DEBUG "sapphire_get_hwid=0x%x\r\n", hwid); + + return hwid; +} + +unsigned int sapphire_get_skuid(void) +{ + printk(KERN_DEBUG "sapphire_get_skuid=0x%x\r\n", skuid); + + return skuid; +} + +unsigned sapphire_engineerid(void) +{ + printk(KERN_DEBUG "sapphire_engineerid=0x%x\r\n", engineerid); + + return engineerid; +} + +int sapphire_is_5M_camera(void) +{ + int ret = 0; + if (sapphire_get_skuid() == 0x1FF00 && !(sapphire_engineerid() & 0x02)) + ret = 1; + else if (sapphire_get_skuid() == 0x20100 && !(sapphire_engineerid() & 0x02)) + ret = 1; + printk(KERN_DEBUG "sapphire_is_5M_camera=%d\n", ret); + return ret; +} + +/* it can support 3M and 5M sensor */ +unsigned int is_12pin_camera(void) +{ + unsigned int ret = 0; + + if (sapphire_get_skuid() == 0x1FF00 || sapphire_get_skuid() == 0x20100) + ret = 1; + else + ret = 0; + printk(KERN_DEBUG "is_12pin_camera=%d\r\n", ret); + return ret; +} + +int sapphire_get_smi_size(void) +{ + printk(KERN_DEBUG "get_smi_size=%d\r\n", smi_sz); + return smi_sz; +} + +static void __init sapphire_fixup(struct machine_desc *desc, struct tag *tags, + char **cmdline, struct meminfo *mi) +{ + smi_sz = parse_tag_smi((const struct tag *)tags); + printk("sapphire_fixup:smisize=%d\n", smi_sz); + hwid = parse_tag_hwid((const struct tag *)tags); + printk("sapphire_fixup:hwid=0x%x\n", hwid); + skuid = parse_tag_skuid((const struct tag *)tags); + printk("sapphire_fixup:skuid=0x%x\n", skuid); + engineerid = parse_tag_engineerid((const struct tag *)tags); + printk("sapphire_fixup:engineerid=0x%x\n", engineerid); + + mi->nr_banks = 1; + mi->bank[0].start = PHYS_OFFSET; + mi->bank[0].node = PHYS_TO_NID(PHYS_OFFSET); + if (smi_sz == 32) { + mi->bank[0].size = (84*1024*1024); + } else if (smi_sz == 64) { + mi->bank[0].size = (101*1024*1024); + } else { + printk(KERN_ERR "can not get smi size\n"); + + /*Give a default value when not get smi size*/ + smi_sz = 64; + mi->bank[0].size = (101*1024*1024); + printk(KERN_ERR "use default : smisize=%d\n", smi_sz); + } +} + +static void __init sapphire_map_io(void) +{ + msm_map_common_io(); + iotable_init(sapphire_io_desc, ARRAY_SIZE(sapphire_io_desc)); + msm_clock_init(); +} + +MACHINE_START(SAPPHIRE, "sapphire") +/* Maintainer: Brian Swetland */ +#ifdef CONFIG_MSM_DEBUG_UART + .phys_io = MSM_DEBUG_UART_PHYS, + .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc, +#endif + .boot_params = 0x10000100, + .fixup = sapphire_fixup, + .map_io = sapphire_map_io, + .init_irq = sapphire_init_irq, + .init_machine = sapphire_init, + .timer = &msm_timer, +MACHINE_END diff --git a/arch/arm/mach-msm/board-sapphire.h b/arch/arm/mach-msm/board-sapphire.h new file mode 100644 index 000000000000..3327dfeafde0 --- /dev/null +++ b/arch/arm/mach-msm/board-sapphire.h @@ -0,0 +1,219 @@ +/* linux/arch/arm/mach-msm/board-sapphire.h + * Copyright (C) 2007-2009 HTC Corporation. + * Author: Thomas Tsai + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. +*/ +#ifndef __ARCH_ARM_MACH_MSM_BOARD_SAPPHIRE_H +#define __ARCH_ARM_MACH_MSM_BOARD_SAPPHIRE_H + +#include + +#define MSM_SMI_BASE 0x00000000 +#define MSM_SMI_SIZE 0x00800000 + +#define MSM_EBI_BASE 0x10000000 +#define MSM_EBI_SIZE 0x06e00000 + +#define MSM_PMEM_GPU0_BASE 0x00000000 +#define MSM_PMEM_GPU0_SIZE 0x00700000 + +#define SMI64_MSM_PMEM_MDP_BASE 0x02000000 +#define SMI64_MSM_PMEM_MDP_SIZE 0x00800000 + +#define SMI64_MSM_PMEM_ADSP_BASE 0x02800000 +#define SMI64_MSM_PMEM_ADSP_SIZE 0x00800000 + +#define SMI64_MSM_PMEM_CAMERA_BASE 0x03000000 +#define SMI64_MSM_PMEM_CAMERA_SIZE 0x01000000 + +#define SMI64_MSM_FB_BASE 0x00700000 +#define SMI64_MSM_FB_SIZE 0x00100000 + +#define SMI64_MSM_LINUX_BASE MSM_EBI_BASE +#define SMI64_MSM_LINUX_SIZE 0x06500000 + + +#define SMI32_MSM_LINUX_BASE MSM_EBI_BASE +#define SMI32_MSM_LINUX_SIZE 0x5400000 + +#define SMI32_MSM_PMEM_MDP_BASE SMI32_MSM_LINUX_BASE + SMI32_MSM_LINUX_SIZE +#define SMI32_MSM_PMEM_MDP_SIZE 0x800000 + +#define SMI32_MSM_PMEM_ADSP_BASE SMI32_MSM_PMEM_MDP_BASE + SMI32_MSM_PMEM_MDP_SIZE +#define SMI32_MSM_PMEM_ADSP_SIZE 0x800000 + +#define SMI32_MSM_FB_BASE SMI32_MSM_PMEM_ADSP_BASE + SMI32_MSM_PMEM_ADSP_SIZE +#define SMI32_MSM_FB_SIZE 0x9b000 + + +#define MSM_PMEM_GPU1_SIZE 0x800000 +#define MSM_PMEM_GPU1_BASE MSM_RAM_CONSOLE_BASE - MSM_PMEM_GPU1_SIZE + +#define MSM_RAM_CONSOLE_BASE MSM_EBI_BASE + 0x6d00000 +#define MSM_RAM_CONSOLE_SIZE 128 * SZ_1K + +#if (SMI32_MSM_FB_BASE + SMI32_MSM_FB_SIZE) >= (MSM_PMEM_GPU1_BASE) +#error invalid memory map +#endif + +#if (SMI64_MSM_FB_BASE + SMI64_MSM_FB_SIZE) >= (MSM_PMEM_GPU1_BASE) +#error invalid memory map +#endif + +#define DECLARE_MSM_IOMAP +#include + +/* +** SOC GPIO +*/ +#define SAPPHIRE_BALL_UP_0 94 +#define SAPPHIRE_BALL_LEFT_0 18 +#define SAPPHIRE_BALL_DOWN_0 49 +#define SAPPHIRE_BALL_RIGHT_0 19 + +#define SAPPHIRE_POWER_KEY 20 +#define SAPPHIRE_VOLUME_UP 36 +#define SAPPHIRE_VOLUME_DOWN 39 + +#define SAPPHIRE_GPIO_PS_HOLD (25) +#define SAPPHIRE_MDDI_1V5_EN (28) +#define SAPPHIRE_BL_PWM (27) +#define SAPPHIRE_TP_LS_EN (1) +#define SAPPHIRE20_TP_LS_EN (88) + +/* H2W */ +#define SAPPHIRE_GPIO_CABLE_IN1 (83) +#define SAPPHIRE_GPIO_CABLE_IN2 (37) +#define SAPPHIRE_GPIO_UART3_RX (86) +#define SAPPHIRE_GPIO_UART3_TX (87) +#define SAPPHIRE_GPIO_H2W_DATA (86) +#define SAPPHIRE_GPIO_H2W_CLK (87) + +#define SAPPHIRE_GPIO_UART1_RTS (43) +#define SAPPHIRE_GPIO_UART1_CTS (44) + +/* +** CPLD GPIO +** +** Sapphire Altera CPLD can keep the registers value and +** doesn't need a shadow to backup. +**/ +#define SAPPHIRE_CPLD_BASE 0xE8100000 /* VA */ +#define SAPPHIRE_CPLD_START 0x98000000 /* PA */ +#define SAPPHIRE_CPLD_SIZE SZ_4K + +#define SAPPHIRE_GPIO_START (128) /* Pseudo GPIO number */ + +/* Sapphire has one INT BANK only. */ +#define SAPPHIRE_GPIO_INT_B0_MASK_REG (0x0c) /*INT3 MASK*/ +#define SAPPHIRE_GPIO_INT_B0_STAT_REG (0x0e) /*INT1 STATUS*/ + +/* LED control register */ +#define SAPPHIRE_CPLD_LED_BASE (SAPPHIRE_CPLD_BASE + 0x10) /* VA */ +#define SAPPHIRE_CPLD_LED_START (SAPPHIRE_CPLD_START + 0x10) /* PA */ +#define SAPPHIRE_CPLD_LED_SIZE 0x08 + +/* MISCn: GPO pin to Enable/Disable some functions. */ +#define SAPPHIRE_GPIO_MISC1_BASE (SAPPHIRE_GPIO_START + 0x00) +#define SAPPHIRE_GPIO_MISC2_BASE (SAPPHIRE_GPIO_START + 0x08) +#define SAPPHIRE_GPIO_MISC3_BASE (SAPPHIRE_GPIO_START + 0x10) +#define SAPPHIRE_GPIO_MISC4_BASE (SAPPHIRE_GPIO_START + 0x18) +#define SAPPHIRE_GPIO_MISC5_BASE (SAPPHIRE_GPIO_START + 0x20) + +/* INT BANK0: INT1: int status, INT2: int level, INT3: int Mask */ +#define SAPPHIRE_GPIO_INT_B0_BASE (SAPPHIRE_GPIO_START + 0x28) + +/* MISCn GPIO: */ +#define SAPPHIRE_GPIO_CPLD128_VER_0 (SAPPHIRE_GPIO_MISC1_BASE + 4) +#define SAPPHIRE_GPIO_CPLD128_VER_1 (SAPPHIRE_GPIO_MISC1_BASE + 5) +#define SAPPHIRE_GPIO_CPLD128_VER_2 (SAPPHIRE_GPIO_MISC1_BASE + 6) +#define SAPPHIRE_GPIO_CPLD128_VER_3 (SAPPHIRE_GPIO_MISC1_BASE + 7) + +#define SAPPHIRE_GPIO_H2W_DAT_DIR (SAPPHIRE_GPIO_MISC2_BASE + 2) +#define SAPPHIRE_GPIO_H2W_CLK_DIR (SAPPHIRE_GPIO_MISC2_BASE + 3) +#define SAPPHIRE_GPIO_H2W_SEL0 (SAPPHIRE_GPIO_MISC2_BASE + 6) +#define SAPPHIRE_GPIO_H2W_SEL1 (SAPPHIRE_GPIO_MISC2_BASE + 7) + +#define SAPPHIRE_GPIO_I2C_PULL (SAPPHIRE_GPIO_MISC3_BASE + 2) +#define SAPPHIRE_GPIO_TP_EN (SAPPHIRE_GPIO_MISC3_BASE + 4) +#define SAPPHIRE_GPIO_JOG_EN (SAPPHIRE_GPIO_MISC3_BASE + 5) +#define SAPPHIRE_GPIO_JOG_LED_EN (SAPPHIRE_GPIO_MISC3_BASE + 6) +#define SAPPHIRE_GPIO_APKEY_LED_EN (SAPPHIRE_GPIO_MISC3_BASE + 7) + +#define SAPPHIRE_GPIO_VCM_PWDN (SAPPHIRE_GPIO_MISC4_BASE + 0) +#define SAPPHIRE_GPIO_USB_H2W_SW (SAPPHIRE_GPIO_MISC4_BASE + 1) +#define SAPPHIRE_GPIO_COMPASS_RST_N (SAPPHIRE_GPIO_MISC4_BASE + 2) +#define SAPPHIRE_GPIO_USB_PHY_RST_N (SAPPHIRE_GPIO_MISC4_BASE + 5) +#define SAPPHIRE_GPIO_WIFI_PA_RESETX (SAPPHIRE_GPIO_MISC4_BASE + 6) +#define SAPPHIRE_GPIO_WIFI_EN (SAPPHIRE_GPIO_MISC4_BASE + 7) + +#define SAPPHIRE_GPIO_BT_32K_EN (SAPPHIRE_GPIO_MISC5_BASE + 0) +#define SAPPHIRE_GPIO_MAC_32K_EN (SAPPHIRE_GPIO_MISC5_BASE + 1) +#define SAPPHIRE_GPIO_MDDI_32K_EN (SAPPHIRE_GPIO_MISC5_BASE + 2) +#define SAPPHIRE_GPIO_COMPASS_32K_EN (SAPPHIRE_GPIO_MISC5_BASE + 3) + +/* INT STATUS/LEVEL/MASK : INT GPIO should be the last. */ +#define SAPPHIRE_GPIO_NAVI_ACT_N (SAPPHIRE_GPIO_INT_B0_BASE + 0) +#define SAPPHIRE_GPIO_COMPASS_IRQ (SAPPHIRE_GPIO_INT_B0_BASE + 1) +#define SAPPHIRE_GPIO_SEARCH_ACT_N (SAPPHIRE_GPIO_INT_B0_BASE + 2) +#define SAPPHIRE_GPIO_AUD_HSMIC_DET_N (SAPPHIRE_GPIO_INT_B0_BASE + 3) +#define SAPPHIRE_GPIO_SDMC_CD_N (SAPPHIRE_GPIO_INT_B0_BASE + 4) +#define SAPPHIRE_GPIO_CAM_BTN_STEP1_N (SAPPHIRE_GPIO_INT_B0_BASE + 5) +#define SAPPHIRE_GPIO_CAM_BTN_STEP2_N (SAPPHIRE_GPIO_INT_B0_BASE + 6) +#define SAPPHIRE_GPIO_TP_ATT_N (SAPPHIRE_GPIO_INT_B0_BASE + 7) + +#define SAPPHIRE_GPIO_END SAPPHIRE_GPIO_TP_ATT_N +#define SAPPHIRE_GPIO_LAST_INT (SAPPHIRE_GPIO_TP_ATT_N) + +/* Bit position in the CPLD MISCn by the CPLD GPIOn: only bit0-7 is used. */ +#define CPLD_GPIO_BIT_POS_MASK(n) (1U << ((n) & 7)) +#define CPLD_GPIO_REG_OFFSET(n) _g_CPLD_MISCn_Offset[((n)-SAPPHIRE_GPIO_START) >> 3] +#define CPLD_GPIO_REG(n) (CPLD_GPIO_REG_OFFSET(n) + SAPPHIRE_CPLD_BASE) + +/* +** CPLD INT Start +*/ +#define SAPPHIRE_INT_START (NR_MSM_IRQS + NR_GPIO_IRQS) /* pseudo number for CPLD INT */ +/* Using INT status/Bank0 for GPIO to INT */ +#define SAPPHIRE_GPIO_TO_INT(n) ((n-SAPPHIRE_GPIO_INT_B0_BASE) + SAPPHIRE_INT_START) +#define SAPPHIRE_INT_END (SAPPHIRE_GPIO_TO_INT(SAPPHIRE_GPIO_END)) + +/* get the INT reg by GPIO number */ +#define CPLD_INT_GPIO_TO_BANK(n) (((n)-SAPPHIRE_GPIO_INT_B0_BASE) >> 3) +#define CPLD_INT_STATUS_REG_OFFSET_G(n) _g_INT_BANK_Offset[CPLD_INT_GPIO_TO_BANK(n)][0] +#define CPLD_INT_LEVEL_REG_OFFSET_G(n) _g_INT_BANK_Offset[CPLD_INT_GPIO_TO_BANK(n)][1] +#define CPLD_INT_MASK_REG_OFFSET_G(n) _g_INT_BANK_Offset[CPLD_INT_GPIO_TO_BANK(n)][2] +#define CPLD_INT_STATUS_REG_G(n) (SAPPHIRE_CPLD_BASE + CPLD_INT_STATUS_REG_OFFSET_G(n)) +#define CPLD_INT_LEVEL_REG_G(n) (SAPPHIRE_CPLD_BASE + CPLD_INT_LEVEL_REG_OFFSET_G(n)) +#define CPLD_INT_MASK_REG_G(n) (SAPPHIRE_CPLD_BASE + CPLD_INT_MASK_REG_OFFSET_G(n)) + +/* get the INT reg by INT number */ +#define CPLD_INT_TO_BANK(i) ((i-SAPPHIRE_INT_START) >> 3) +#define CPLD_INT_STATUS_REG_OFFSET(i) _g_INT_BANK_Offset[CPLD_INT_TO_BANK(i)][0] +#define CPLD_INT_LEVEL_REG_OFFSET(i) _g_INT_BANK_Offset[CPLD_INT_TO_BANK(i)][1] +#define CPLD_INT_MASK_REG_OFFSET(i) _g_INT_BANK_Offset[CPLD_INT_TO_BANK(i)][2] +#define CPLD_INT_STATUS_REG(i) (SAPPHIRE_CPLD_BASE + CPLD_INT_STATUS_REG_OFFSET(i)) +#define CPLD_INT_LEVEL_REG(i) (SAPPHIRE_CPLD_BASE + CPLD_INT_LEVEL_REG_OFFSET(i)) +#define CPLD_INT_MASK_REG(i) (SAPPHIRE_CPLD_BASE + CPLD_INT_MASK_REG_OFFSET(i) ) + +/* return the bit mask by INT number */ +#define SAPPHIRE_INT_BIT_MASK(i) (1U << ((i - SAPPHIRE_INT_START) & 7)) + +void config_sapphire_camera_on_gpios(void); +void config_sapphire_camera_off_gpios(void); +int sapphire_get_smi_size(void); +unsigned int sapphire_get_hwid(void); +unsigned int sapphire_get_skuid(void); +unsigned int is_12pin_camera(void); +int sapphire_is_5M_camera(void); +int sapphire_gpio_write(struct gpio_chip *chip, unsigned n, unsigned on); + +#endif /* GUARD */ diff --git a/arch/arm/mach-msm/devices_htc.c b/arch/arm/mach-msm/devices_htc.c new file mode 100644 index 000000000000..dd6a26fbf16e --- /dev/null +++ b/arch/arm/mach-msm/devices_htc.c @@ -0,0 +1,434 @@ +/* linux/arch/arm/mach-msm/devices.c + * + * Copyright (C) 2008 Google, Inc. + * Copyright (C) 2007-2009 HTC Corporation. + * Author: Thomas Tsai + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 "gpio_chip.h" +#include "devices.h" +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static char *df_serialno = "000000000000"; + +#if 0 +struct platform_device *devices[] __initdata = { + &msm_device_nand, + &msm_device_smd, + &msm_device_i2c, +}; + +void __init msm_add_devices(void) +{ + platform_add_devices(devices, ARRAY_SIZE(devices)); +} +#endif + +#define HSUSB_API_INIT_PHY_PROC 2 +#define HSUSB_API_PROG 0x30000064 +#define HSUSB_API_VERS 0x10001 +static void internal_phy_reset(void) +{ + struct msm_rpc_endpoint *usb_ep; + int rc; + struct hsusb_phy_start_req { + struct rpc_request_hdr hdr; + } req; + + printk(KERN_INFO "msm_hsusb_phy_reset\n"); + + usb_ep = msm_rpc_connect(HSUSB_API_PROG, HSUSB_API_VERS, 0); + if (IS_ERR(usb_ep)) { + printk(KERN_ERR "%s: init rpc failed! error: %ld\n", + __func__, PTR_ERR(usb_ep)); + goto close; + } + rc = msm_rpc_call(usb_ep, HSUSB_API_INIT_PHY_PROC, + &req, sizeof(req), 5 * HZ); + if (rc < 0) + printk(KERN_ERR "%s: rpc call failed! (%d)\n", __func__, rc); + +close: + msm_rpc_close(usb_ep); +} + +/* adjust eye diagram, disable vbusvalid interrupts */ +static int hsusb_phy_init_seq[] = { 0x40, 0x31, 0x1D, 0x0D, 0x1D, 0x10, -1 }; + +static char *usb_functions[] = { +#if defined(CONFIG_USB_FUNCTION_MASS_STORAGE) || defined(CONFIG_USB_FUNCTION_UMS) + "usb_mass_storage", +#endif +#ifdef CONFIG_USB_FUNCTION_ADB + "adb", +#endif +}; + +static struct msm_hsusb_product usb_products[] = { + { + .product_id = 0x0c01, + .functions = 0x00000041, /* usb_mass_storage */ + }, + { + .product_id = 0x0c02, + .functions = 0x00000043, /* usb_mass_storage + adb */ + }, +}; + +#ifdef CONFIG_USB_FUNCTION +struct msm_hsusb_platform_data msm_hsusb_pdata = { + .phy_reset = internal_phy_reset, + .phy_init_seq = hsusb_phy_init_seq, + .vendor_id = 0x0bb4, + .product_id = 0x0c02, + .version = 0x0100, + .product_name = "Android Phone", + .manufacturer_name = "HTC", + + .functions = usb_functions, + .num_functions = ARRAY_SIZE(usb_functions), + .products = usb_products, + .num_products = ARRAY_SIZE(usb_products), +}; + +static struct usb_mass_storage_platform_data mass_storage_pdata = { + .nluns = 1, + .buf_size = 16384, + .vendor = "HTC ", + .product = "Android Phone ", + .release = 0x0100, +}; + +static struct platform_device usb_mass_storage_device = { + .name = "usb_mass_storage", + .id = -1, + .dev = { + .platform_data = &mass_storage_pdata, + }, +}; + +#ifdef CONFIG_USB_ANDROID +static struct android_usb_platform_data android_usb_pdata = { + .vendor_id = 0x0bb4, + .product_id = 0x0c01, + .adb_product_id = 0x0c02, + .version = 0x0100, + .product_name = "Android Phone", + .manufacturer_name = "HTC", + .nluns = 1, +}; + +static struct platform_device android_usb_device = { + .name = "android_usb", + .id = -1, + .dev = { + .platform_data = &android_usb_pdata, + }, +}; +#endif + +void __init msm_add_usb_devices(void (*phy_reset) (void)) +{ + if (phy_reset) + msm_hsusb_pdata.phy_reset = phy_reset; + /* setup */ + msm_device_hsusb.dev.platform_data = &msm_hsusb_pdata; + platform_device_register(&msm_device_hsusb); +#ifdef CONFIG_USB_FUNCTION_MASS_STORAGE + platform_device_register(&usb_mass_storage_device); +#endif +} +#endif + +static struct android_pmem_platform_data pmem_pdata = { + .name = "pmem", + .no_allocator = 1, + .cached = 1, +}; + +static struct android_pmem_platform_data pmem_adsp_pdata = { + .name = "pmem_adsp", + .no_allocator = 0, + .cached = 0, +}; + +static struct android_pmem_platform_data pmem_camera_pdata = { + .name = "pmem_camera", + .no_allocator = 0, + .cached = 0, +}; + +static struct android_pmem_platform_data pmem_gpu0_pdata = { + .name = "pmem_gpu0", + .no_allocator = 1, + .cached = 0, + .buffered = 1, +}; + +static struct android_pmem_platform_data pmem_gpu1_pdata = { + .name = "pmem_gpu1", + .no_allocator = 1, + .cached = 0, + .buffered = 1, +}; + +static struct platform_device pmem_device = { + .name = "android_pmem", + .id = 0, + .dev = { .platform_data = &pmem_pdata }, +}; + +static struct platform_device pmem_adsp_device = { + .name = "android_pmem", + .id = 1, + .dev = { .platform_data = &pmem_adsp_pdata }, +}; + +static struct platform_device pmem_gpu0_device = { + .name = "android_pmem", + .id = 2, + .dev = { .platform_data = &pmem_gpu0_pdata }, +}; + +static struct platform_device pmem_gpu1_device = { + .name = "android_pmem", + .id = 3, + .dev = { .platform_data = &pmem_gpu1_pdata }, +}; + +static struct platform_device pmem_camera_device = { + .name = "android_pmem", + .id = 4, + .dev = { .platform_data = &pmem_camera_pdata }, +}; + +static struct resource ram_console_resource[] = { + { + .flags = IORESOURCE_MEM, + } +}; + +static struct platform_device ram_console_device = { + .name = "ram_console", + .id = -1, + .num_resources = ARRAY_SIZE(ram_console_resource), + .resource = ram_console_resource, +}; + +void __init msm_add_mem_devices(struct msm_pmem_setting *setting) +{ + if (setting->pmem_size) { + pmem_pdata.start = setting->pmem_start; + pmem_pdata.size = setting->pmem_size; + platform_device_register(&pmem_device); + } + + if (setting->pmem_adsp_size) { + pmem_adsp_pdata.start = setting->pmem_adsp_start; + pmem_adsp_pdata.size = setting->pmem_adsp_size; + platform_device_register(&pmem_adsp_device); + } + + if (setting->pmem_gpu0_size) { + pmem_gpu0_pdata.start = setting->pmem_gpu0_start; + pmem_gpu0_pdata.size = setting->pmem_gpu0_size; + platform_device_register(&pmem_gpu0_device); + } + + if (setting->pmem_gpu1_size) { + pmem_gpu1_pdata.start = setting->pmem_gpu1_start; + pmem_gpu1_pdata.size = setting->pmem_gpu1_size; + platform_device_register(&pmem_gpu1_device); + } + + if (setting->pmem_camera_size) { + pmem_camera_pdata.start = setting->pmem_camera_start; + pmem_camera_pdata.size = setting->pmem_camera_size; + platform_device_register(&pmem_camera_device); + } + + if (setting->ram_console_size) { + ram_console_resource[0].start = setting->ram_console_start; + ram_console_resource[0].end = setting->ram_console_start + + setting->ram_console_size - 1; + platform_device_register(&ram_console_device); + } +} + +#define PM_LIBPROG 0x30000061 +#if (CONFIG_MSM_AMSS_VERSION == 6220) || (CONFIG_MSM_AMSS_VERSION == 6225) +#define PM_LIBVERS 0xfb837d0b +#else +#define PM_LIBVERS 0x10001 +#endif + +#if 0 +static struct platform_device *msm_serial_devices[] __initdata = { + &msm_device_uart1, + &msm_device_uart2, + &msm_device_uart3, + #ifdef CONFIG_SERIAL_MSM_HS + &msm_device_uart_dm1, + &msm_device_uart_dm2, + #endif +}; + +int __init msm_add_serial_devices(unsigned num) +{ + if (num > MSM_SERIAL_NUM) + return -EINVAL; + + return platform_device_register(msm_serial_devices[num]); +} +#endif + +#define ATAG_SMI 0x4d534D71 +/* setup calls mach->fixup, then parse_tags, parse_cmdline + * We need to setup meminfo in mach->fixup, so this function + * will need to traverse each tag to find smi tag. + */ +int __init parse_tag_smi(const struct tag *tags) +{ + int smi_sz = 0, find = 0; + struct tag *t = (struct tag *)tags; + + for (; t->hdr.size; t = tag_next(t)) { + if (t->hdr.tag == ATAG_SMI) { + printk(KERN_DEBUG "find the smi tag\n"); + find = 1; + break; + } + } + if (!find) + return -1; + + printk(KERN_DEBUG "parse_tag_smi: smi size = %d\n", t->u.mem.size); + smi_sz = t->u.mem.size; + return smi_sz; +} +__tagtable(ATAG_SMI, parse_tag_smi); + + +#define ATAG_HWID 0x4d534D72 +int __init parse_tag_hwid(const struct tag *tags) +{ + int hwid = 0, find = 0; + struct tag *t = (struct tag *)tags; + + for (; t->hdr.size; t = tag_next(t)) { + if (t->hdr.tag == ATAG_HWID) { + printk(KERN_DEBUG "find the hwid tag\n"); + find = 1; + break; + } + } + + if (find) + hwid = t->u.revision.rev; + printk(KERN_DEBUG "parse_tag_hwid: hwid = 0x%x\n", hwid); + return hwid; +} +__tagtable(ATAG_HWID, parse_tag_hwid); + +#define ATAG_SKUID 0x4d534D73 +int __init parse_tag_skuid(const struct tag *tags) +{ + int skuid = 0, find = 0; + struct tag *t = (struct tag *)tags; + + for (; t->hdr.size; t = tag_next(t)) { + if (t->hdr.tag == ATAG_SKUID) { + printk(KERN_DEBUG "find the skuid tag\n"); + find = 1; + break; + } + } + + if (find) + skuid = t->u.revision.rev; + printk(KERN_DEBUG "parse_tag_skuid: hwid = 0x%x\n", skuid); + return skuid; +} +__tagtable(ATAG_SKUID, parse_tag_skuid); + +#define ATAG_ENGINEERID 0x4d534D75 +int __init parse_tag_engineerid(const struct tag *tags) +{ + int engineerid = 0, find = 0; + struct tag *t = (struct tag *)tags; + + for (; t->hdr.size; t = tag_next(t)) { + if (t->hdr.tag == ATAG_ENGINEERID) { + printk(KERN_DEBUG "find the engineer tag\n"); + find = 1; + break; + } + } + + if (find) + engineerid = t->u.revision.rev; + printk(KERN_DEBUG "parse_tag_engineerid: hwid = 0x%x\n", engineerid); + return engineerid; +} +__tagtable(ATAG_ENGINEERID, parse_tag_engineerid); + +static int mfg_mode; +int __init board_mfg_mode_init(char *s) +{ + if (!strcmp(s, "normal")) + mfg_mode = 0; + else if (!strcmp(s, "factory2")) + mfg_mode = 1; + else if (!strcmp(s, "recovery")) + mfg_mode = 2; + else if (!strcmp(s, "charge")) + mfg_mode = 3; + + return 1; +} +__setup("androidboot.mode=", board_mfg_mode_init); + + +int board_mfg_mode(void) +{ + return mfg_mode; +} + +static int __init board_serialno_setup(char *serialno) +{ + if (board_mfg_mode() || !strlen(serialno)) + msm_hsusb_pdata.serial_number = df_serialno; + else + msm_hsusb_pdata.serial_number = serialno; + return 1; +} + +__setup("androidboot.serialno=", board_serialno_setup); diff --git a/arch/arm/mach-msm/include/mach/board_htc.h b/arch/arm/mach-msm/include/mach/board_htc.h new file mode 100644 index 000000000000..b537c91b957a --- /dev/null +++ b/arch/arm/mach-msm/include/mach/board_htc.h @@ -0,0 +1,78 @@ +/* arch/arm/mach-msm/include/mach/BOARD_HTC.h + * Copyright (C) 2007-2009 HTC Corporation. + * Author: Thomas Tsai + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ +#ifndef __ASM_ARCH_MSM_BOARD_HTC_H +#define __ASM_ARCH_MSM_BOARD_HTC_H + +#include +#include +#include + +struct msm_pmem_setting{ + resource_size_t pmem_start; + resource_size_t pmem_size; + resource_size_t pmem_adsp_start; + resource_size_t pmem_adsp_size; + resource_size_t pmem_gpu0_start; + resource_size_t pmem_gpu0_size; + resource_size_t pmem_gpu1_start; + resource_size_t pmem_gpu1_size; + resource_size_t pmem_camera_start; + resource_size_t pmem_camera_size; + resource_size_t ram_console_start; + resource_size_t ram_console_size; +}; + +enum { + MSM_SERIAL_UART1 = 0, + MSM_SERIAL_UART2, + MSM_SERIAL_UART3, +#ifdef CONFIG_SERIAL_MSM_HS + MSM_SERIAL_UART1DM, + MSM_SERIAL_UART2DM, +#endif + MSM_SERIAL_NUM, +}; + + +/* common init routines for use by arch/arm/mach-msm/board-*.c */ + +void __init msm_add_usb_devices(void (*phy_reset) (void)); +void __init msm_add_mem_devices(struct msm_pmem_setting *setting); +void __init msm_init_pmic_vibrator(void); + +struct mmc_platform_data; +int __init msm_add_sdcc_devices(unsigned int controller, struct mmc_platform_data *plat); +int __init msm_add_serial_devices(unsigned uart); + +#if defined(CONFIG_USB_FUNCTION_MSM_HSUSB) +/* START: add USB connected notify function */ +struct t_usb_status_notifier{ + struct list_head notifier_link; + const char *name; + void (*func)(int online); +}; + int usb_register_notifier(struct t_usb_status_notifier *); + static LIST_HEAD(g_lh_usb_notifier_list); +/* END: add USB connected notify function */ +#endif + +int __init board_mfg_mode(void); +int __init parse_tag_smi(const struct tag *tags); +int __init parse_tag_hwid(const struct tag * tags); +int __init parse_tag_skuid(const struct tag * tags); +int parse_tag_engineerid(const struct tag * tags); + +char *board_serialno(void); + +#endif -- cgit v1.2.3 From 89bb32ff71253354a1619b520708a080dd6f8e6b Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Tue, 17 Feb 2009 21:58:54 -0500 Subject: [ARM] msm: sapphire: Fix rounding in sapphire_set_backlight_level Previously all values less 22 turned the backlight completely off Now 0 is off and values 1 - 21 are the lowest dim value Signed-off-by: Mike Lockwood --- arch/arm/mach-msm/board-sapphire-panel.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/board-sapphire-panel.c b/arch/arm/mach-msm/board-sapphire-panel.c index 24933f3eab52..9129f4cdcb5f 100644 --- a/arch/arm/mach-msm/board-sapphire-panel.c +++ b/arch/arm/mach-msm/board-sapphire-panel.c @@ -49,7 +49,7 @@ static int sapphire_backlight_brightness = static uint8_t sapphire_backlight_last_level = 33; static DEFINE_MUTEX(sapphire_backlight_lock); -/* Divid dimming level into 12 sections, and restrict maximum level to 27 */ +/* Divide dimming level into 12 sections, and restrict maximum level to 27 */ #define DIMMING_STEPS 12 static unsigned dimming_levels[NUM_OF_SAPPHIRE_PANELS][DIMMING_STEPS] = { {0, 1, 2, 3, 6, 9, 11, 13, 16, 19, 22, 25}, /* Sharp */ @@ -60,16 +60,16 @@ static unsigned pwrsink_percents[] = {0, 6, 8, 15, 26, 34, 46, 54, 65, 77, 87, static void sapphire_set_backlight_level(uint8_t level) { - unsigned dimming_factor = 255/DIMMING_STEPS + 1 ; - unsigned percent = ((int)level * 100) / 255; + unsigned dimming_factor = 255/DIMMING_STEPS + 1; + int index = (level + dimming_factor - 1) / dimming_factor; + unsigned percent; unsigned long flags; int i = 0; printk(KERN_INFO "level=%d, new level=dimming_levels[%d]=%d\n", - level, level/dimming_factor, - dimming_levels[g_panel_id][level/dimming_factor]); - percent = pwrsink_percents[level/dimming_factor]; - level = dimming_levels[g_panel_id][level/dimming_factor]; + level, index, dimming_levels[g_panel_id][index]); + percent = pwrsink_percents[index]; + level = dimming_levels[g_panel_id][index]; if (sapphire_backlight_last_level == level) return; -- cgit v1.2.3 From fd8d8e773ce5a71d4c03b7068ea20199da2cf5a2 Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Fri, 20 Feb 2009 15:56:06 -0500 Subject: [ARM] msm: htc: Clean up USB support in trout and sapphire board files Signed-off-by: Mike Lockwood --- arch/arm/mach-msm/board-sapphire.c | 9 --- arch/arm/mach-msm/board-trout.c | 111 +------------------------------------ arch/arm/mach-msm/devices_htc.c | 26 +++++++-- 3 files changed, 23 insertions(+), 123 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/board-sapphire.c b/arch/arm/mach-msm/board-sapphire.c index 4a34f94f21ee..6284d0570cac 100644 --- a/arch/arm/mach-msm/board-sapphire.c +++ b/arch/arm/mach-msm/board-sapphire.c @@ -28,12 +28,6 @@ #include #include #include -#ifdef CONFIG_USB_FUNCTION -#include -#endif -#ifdef CONFIG_USB_ANDROID -#include -#endif #include @@ -64,7 +58,6 @@ #include #include -#include #include #include @@ -610,7 +603,6 @@ static struct platform_device sapphire_h2w = { }; #endif -#ifdef CONFIG_USB_FUNCTION static void sapphire_phy_reset(void) { gpio_set_value(SAPPHIRE_GPIO_USB_PHY_RST_N, 0); @@ -618,7 +610,6 @@ static void sapphire_phy_reset(void) gpio_set_value(SAPPHIRE_GPIO_USB_PHY_RST_N, 1); mdelay(10); } -#endif static struct pwr_sink sapphire_pwrsink_table[] = { { diff --git a/arch/arm/mach-msm/board-trout.c b/arch/arm/mach-msm/board-trout.c index 986a6ec5b0d6..14cb304bade2 100644 --- a/arch/arm/mach-msm/board-trout.c +++ b/arch/arm/mach-msm/board-trout.c @@ -28,12 +28,6 @@ #include #include #include -#ifdef CONFIG_USB_FUNCTION -#include -#endif -#ifdef CONFIG_USB_ANDROID -#include -#endif #include @@ -64,7 +58,7 @@ #include "gpio_chip.h" #include -#include +#include #include #include #ifdef CONFIG_HTC_HEADSET @@ -471,9 +465,6 @@ static struct platform_device trout_h2w = { }; #endif -/* adjust eye diagram, disable vbusvalid interrupts */ -static int trout_phy_init_seq[] = { 0x40, 0x31, 0x1D, 0x0D, 0x1D, 0x10, -1 }; - static void trout_phy_reset(void) { gpio_set_value(TROUT_GPIO_USB_PHY_RST_N, 0); @@ -482,83 +473,6 @@ static void trout_phy_reset(void) mdelay(10); } -#ifdef CONFIG_USB_FUNCTION -static char *trout_usb_functions[] = { -#if defined(CONFIG_USB_FUNCTION_MASS_STORAGE) || defined(CONFIG_USB_FUNCTION_UMS) - "usb_mass_storage", -#endif -#ifdef CONFIG_USB_FUNCTION_ADB - "adb", -#endif -}; - -static struct msm_hsusb_product trout_usb_products[] = { - { - .product_id = 0x0c01, - .functions = 0x00000001, /* "usb_mass_storage" only */ - }, - { - .product_id = 0x0c02, - .functions = 0x00000003, /* "usb_mass_storage" and "adb" */ - }, -}; -#endif - -static struct msm_hsusb_platform_data msm_hsusb_pdata = { - .phy_reset = trout_phy_reset, - .phy_init_seq = trout_phy_init_seq, -#ifdef CONFIG_USB_FUNCTION - .vendor_id = 0x0bb4, - .product_id = 0x0c02, - .version = 0x0100, - .product_name = "Android Phone", - .manufacturer_name = "HTC", - - .functions = trout_usb_functions, - .num_functions = ARRAY_SIZE(trout_usb_functions), - .products = trout_usb_products, - .num_products = ARRAY_SIZE(trout_usb_products), -#endif -}; - -#ifdef CONFIG_USB_FUNCTION_MASS_STORAGE -static struct usb_mass_storage_platform_data mass_storage_pdata = { - .nluns = 1, - .buf_size = 16384, - .vendor = "HTC ", - .product = "Android Phone ", - .release = 0x0100, -}; - -static struct platform_device usb_mass_storage_device = { - .name = "usb_mass_storage", - .id = -1, - .dev = { - .platform_data = &mass_storage_pdata, - }, -}; -#endif - -#ifdef CONFIG_USB_ANDROID -static struct android_usb_platform_data android_usb_pdata = { - .vendor_id = 0x0bb4, - .product_id = 0x0c01, - .adb_product_id = 0x0c02, - .version = 0x0100, - .product_name = "Android Phone", - .manufacturer_name = "HTC", - .nluns = 1, -}; - -static struct platform_device android_usb_device = { - .name = "android_usb", - .id = -1, - .dev = { - .platform_data = &android_usb_pdata, - }, -}; -#endif - static struct resource trout_ram_console_resource[] = { { .start = MSM_RAM_CONSOLE_BASE, @@ -726,13 +640,6 @@ static struct platform_device *devices[] __initdata = { #endif #ifdef CONFIG_SERIAL_MSM_HS &msm_device_uart_dm1, -#endif - &msm_device_hsusb, -#ifdef CONFIG_USB_FUNCTION_MASS_STORAGE - &usb_mass_storage_device, -#endif -#ifdef CONFIG_USB_ANDROID - &android_usb_device, #endif &trout_nav_device, &trout_reset_keys_device, @@ -770,19 +677,6 @@ static uint opt_disable_uart3; module_param_named(disable_uart3, opt_disable_uart3, uint, 0); -static int __init trout_serialno_setup(char *str) -{ -#ifdef CONFIG_USB_FUNCTION - msm_hsusb_pdata.serial_number = str; -#endif -#ifdef CONFIG_USB_ANDROID - android_usb_pdata.serial_number = str; -#endif - return 1; -} - -__setup("androidboot.serialno=", trout_serialno_setup); - static void trout_reset(void) { gpio_set_value(TROUT_GPIO_PS_HOLD, 0); @@ -872,11 +766,10 @@ static void __init trout_init(void) trout_y_axis.info.gpio = trout_4_y_axis_gpios; } - msm_device_hsusb.dev.platform_data = &msm_hsusb_pdata; - #ifdef CONFIG_SERIAL_MSM_HS msm_device_uart_dm1.dev.platform_data = &msm_uart_dm1_pdata; #endif + msm_add_usb_devices(trout_phy_reset); rc = trout_init_mmc(system_rev); if (rc) diff --git a/arch/arm/mach-msm/devices_htc.c b/arch/arm/mach-msm/devices_htc.c index dd6a26fbf16e..fad7dfb1bcc4 100644 --- a/arch/arm/mach-msm/devices_htc.c +++ b/arch/arm/mach-msm/devices_htc.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -83,6 +84,7 @@ close: /* adjust eye diagram, disable vbusvalid interrupts */ static int hsusb_phy_init_seq[] = { 0x40, 0x31, 0x1D, 0x0D, 0x1D, 0x10, -1 }; +#ifdef CONFIG_USB_FUNCTION static char *usb_functions[] = { #if defined(CONFIG_USB_FUNCTION_MASS_STORAGE) || defined(CONFIG_USB_FUNCTION_UMS) "usb_mass_storage", @@ -102,11 +104,12 @@ static struct msm_hsusb_product usb_products[] = { .functions = 0x00000043, /* usb_mass_storage + adb */ }, }; +#endif -#ifdef CONFIG_USB_FUNCTION struct msm_hsusb_platform_data msm_hsusb_pdata = { .phy_reset = internal_phy_reset, .phy_init_seq = hsusb_phy_init_seq, +#ifdef CONFIG_USB_FUNCTION .vendor_id = 0x0bb4, .product_id = 0x0c02, .version = 0x0100, @@ -117,8 +120,10 @@ struct msm_hsusb_platform_data msm_hsusb_pdata = { .num_functions = ARRAY_SIZE(usb_functions), .products = usb_products, .num_products = ARRAY_SIZE(usb_products), +#endif }; +#ifdef CONFIG_USB_FUNCTION static struct usb_mass_storage_platform_data mass_storage_pdata = { .nluns = 1, .buf_size = 16384, @@ -134,6 +139,7 @@ static struct platform_device usb_mass_storage_device = { .platform_data = &mass_storage_pdata, }, }; +#endif #ifdef CONFIG_USB_ANDROID static struct android_usb_platform_data android_usb_pdata = { @@ -157,16 +163,18 @@ static struct platform_device android_usb_device = { void __init msm_add_usb_devices(void (*phy_reset) (void)) { + /* setup */ if (phy_reset) msm_hsusb_pdata.phy_reset = phy_reset; - /* setup */ msm_device_hsusb.dev.platform_data = &msm_hsusb_pdata; platform_device_register(&msm_device_hsusb); #ifdef CONFIG_USB_FUNCTION_MASS_STORAGE platform_device_register(&usb_mass_storage_device); #endif -} +#ifdef CONFIG_USB_ANDROID + platform_device_register(&android_usb_device); #endif +} static struct android_pmem_platform_data pmem_pdata = { .name = "pmem", @@ -424,10 +432,18 @@ int board_mfg_mode(void) static int __init board_serialno_setup(char *serialno) { + char *str; + if (board_mfg_mode() || !strlen(serialno)) - msm_hsusb_pdata.serial_number = df_serialno; + str = df_serialno; else - msm_hsusb_pdata.serial_number = serialno; + str = serialno; +#ifdef CONFIG_USB_FUNCTION + msm_hsusb_pdata.serial_number = str; +#endif +#ifdef CONFIG_USB_ANDROID + android_usb_pdata.serial_number = str; +#endif return 1; } -- cgit v1.2.3 From 7301bf1e671280290c5351a01d06009f4206b93e Mon Sep 17 00:00:00 2001 From: Steve Muckle Date: Fri, 5 Dec 2008 17:03:15 -0500 Subject: [ARM] msm: make clkctl speed struct internal The clkctl_acpu_speed structure is not used outside the acpuclock implementation. --- arch/arm/mach-msm/acpuclock.c | 14 ++++++++++++++ arch/arm/mach-msm/acpuclock.h | 16 ---------------- 2 files changed, 14 insertions(+), 16 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/acpuclock.c b/arch/arm/mach-msm/acpuclock.c index 59c91f7150c1..7d5d6f4a4242 100644 --- a/arch/arm/mach-msm/acpuclock.c +++ b/arch/arm/mach-msm/acpuclock.c @@ -64,6 +64,20 @@ enum { VDD_END }; +struct clkctl_acpu_speed { + unsigned int a11clk_khz; + int pll; + unsigned int a11clk_src_sel; + unsigned int a11clk_src_div; + unsigned int ahbclk_khz; + unsigned int ahbclk_div; + int vdd; + unsigned long lpj; /* loops_per_jiffy */ +/* Index in acpu_freq_tbl[] for steppings. */ + short down; + short up; +}; + /* * ACPU speed table. Complete table is shown but certain speeds are commented * out to optimized speed switching. Initalize loops_per_jiffy to 0. diff --git a/arch/arm/mach-msm/acpuclock.h b/arch/arm/mach-msm/acpuclock.h index ab9c3e535747..9b2fcff97517 100644 --- a/arch/arm/mach-msm/acpuclock.h +++ b/arch/arm/mach-msm/acpuclock.h @@ -37,22 +37,6 @@ #define ACPU_PLL_2 2 #define ACPU_PLL_3 3 -struct clkctl_acpu_speed -{ - unsigned int a11clk_khz; - int pll; - unsigned int a11clk_src_sel; - unsigned int a11clk_src_div; - unsigned int ahbclk_khz; - unsigned int ahbclk_div; - int vdd; - unsigned long lpj; /* loops_per_jiffy */ -/* Index in acpu_freq_tbl[] for steppings. */ - short down; - short up; -}; - - int acpuclk_set_rate(unsigned long rate, int for_power_collapse); unsigned long acpuclk_get_rate(void); uint32_t acpuclk_get_switch_time(void); -- cgit v1.2.3 From e293e3f5d444d22c15d1e936c1b068e0e6573b54 Mon Sep 17 00:00:00 2001 From: Farmer Tseng Date: Mon, 23 Feb 2009 17:55:30 +0800 Subject: [ARM] msm: sapphire: Fix touchscreen power on/off sequence. Signed-off-by: Farmer Tseng Signed-off-by: San Mehat --- arch/arm/mach-msm/board-sapphire.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/board-sapphire.c b/arch/arm/mach-msm/board-sapphire.c index 6284d0570cac..27aed1bf8db5 100644 --- a/arch/arm/mach-msm/board-sapphire.c +++ b/arch/arm/mach-msm/board-sapphire.c @@ -233,10 +233,11 @@ static int sapphire_ts_power(int on) /* touchscreen must be powered before we enable i2c pullup */ msleep(2); /* enable touch panel level shift */ - gpio_set_value(gpio_tp_ls_en, 1); + gpio_direction_output(gpio_tp_ls_en, 1); msleep(2); } else { - gpio_set_value(gpio_tp_ls_en, 0); + gpio_direction_output(gpio_tp_ls_en, 0); + udelay(50); sapphire_gpio_write(NULL, SAPPHIRE_GPIO_TP_EN, 0); } -- cgit v1.2.3 From 4b06f72dc9fdcaf2d7f36280874f18bfd15cb071 Mon Sep 17 00:00:00 2001 From: Thomas Tsai Date: Wed, 18 Feb 2009 16:16:17 +0800 Subject: [ARM] msm: sapphire: Add support for button backlight. Signed-off-by: San Mehat --- arch/arm/mach-msm/board-sapphire.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/board-sapphire.c b/arch/arm/mach-msm/board-sapphire.c index 27aed1bf8db5..7898fce517b3 100644 --- a/arch/arm/mach-msm/board-sapphire.c +++ b/arch/arm/mach-msm/board-sapphire.c @@ -368,7 +368,6 @@ static struct platform_device android_CPLD_leds = { }; #endif -#if 0 static struct gpio_led android_led_list[] = { { .name = "button-backlight", @@ -388,7 +387,6 @@ static struct platform_device android_leds = { .platform_data = &android_leds_data, }, }; -#endif #ifdef CONFIG_HTC_HEADSET /* RTS/CTS to GPO/GPI. */ @@ -797,6 +795,7 @@ static struct platform_device *devices[] __initdata = { #endif &sapphire_nav_device, &sapphire_reset_keys_device, + &android_leds, #ifdef CONFIG_LEDS_CPLD &android_CPLD_leds, #endif -- cgit v1.2.3 From f872ce73350b2e1f02374213c27d1330f10f046f Mon Sep 17 00:00:00 2001 From: Saravana Kannan Date: Mon, 22 Dec 2008 20:24:17 -0800 Subject: [ARM] msm: acpuclock: Couple minimum AXI freq to the current CPU freq. This patch comes from qualcomm with some minor changes by mike@android.com. Signed-off-by: Mike Chan --- arch/arm/mach-msm/acpuclock.c | 64 +++++++++++++++++++++++++++---------------- arch/arm/mach-msm/clock.c | 15 ++++++++-- arch/arm/mach-msm/clock.h | 3 +- arch/arm/mach-msm/devices.c | 5 ++-- 4 files changed, 57 insertions(+), 30 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/acpuclock.c b/arch/arm/mach-msm/acpuclock.c index 7d5d6f4a4242..9a554ac8350e 100644 --- a/arch/arm/mach-msm/acpuclock.c +++ b/arch/arm/mach-msm/acpuclock.c @@ -47,6 +47,7 @@ struct clock_state unsigned long wait_for_irq_khz; }; +static struct clk *ebi1_clk; static struct clock_state drv_state = { 0 }; static void __init acpuclk_init(void); @@ -72,6 +73,7 @@ struct clkctl_acpu_speed { unsigned int ahbclk_khz; unsigned int ahbclk_div; int vdd; + unsigned int axiclk_khz; unsigned long lpj; /* loops_per_jiffy */ /* Index in acpu_freq_tbl[] for steppings. */ short down; @@ -87,33 +89,33 @@ struct clkctl_acpu_speed { */ #if (0) static struct clkctl_acpu_speed acpu_freq_tbl[] = { - { 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, VDD_0, 0, 0, 8 }, - { 61440, ACPU_PLL_0, 4, 3, 61440, 0, VDD_0, 0, 0, 8 }, - { 81920, ACPU_PLL_0, 4, 2, 40960, 1, VDD_0, 0, 0, 8 }, - { 96000, ACPU_PLL_1, 1, 7, 48000, 1, VDD_0, 0, 0, 9 }, - { 122880, ACPU_PLL_0, 4, 1, 61440, 1, VDD_3, 0, 0, 8 }, - { 128000, ACPU_PLL_1, 1, 5, 64000, 1, VDD_3, 0, 0, 12 }, - { 176000, ACPU_PLL_2, 2, 5, 88000, 1, VDD_3, 0, 0, 11 }, - { 192000, ACPU_PLL_1, 1, 3, 64000, 2, VDD_3, 0, 0, 12 }, - { 245760, ACPU_PLL_0, 4, 0, 81920, 2, VDD_4, 0, 0, 12 }, - { 256000, ACPU_PLL_1, 1, 2, 128000, 2, VDD_5, 0, 0, 12 }, - { 264000, ACPU_PLL_2, 2, 3, 88000, 2, VDD_5, 0, 6, 13 }, - { 352000, ACPU_PLL_2, 2, 2, 88000, 3, VDD_5, 0, 6, 13 }, - { 384000, ACPU_PLL_1, 1, 1, 128000, 2, VDD_6, 0, 5, -1 }, - { 528000, ACPU_PLL_2, 2, 1, 132000, 3, VDD_7, 0, 11, -1 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0 ,0}, + { 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, VDD_0, 30720, 0, 0, 8 }, + { 61440, ACPU_PLL_0, 4, 3, 61440, 0, VDD_0, 30720, 0, 0, 8 }, + { 81920, ACPU_PLL_0, 4, 2, 40960, 1, VDD_0, 61440, 0, 0, 8 }, + { 96000, ACPU_PLL_1, 1, 7, 48000, 1, VDD_0, 61440, 0, 0, 9 }, + { 122880, ACPU_PLL_0, 4, 1, 61440, 1, VDD_3, 61440, 0, 0, 8 }, + { 128000, ACPU_PLL_1, 1, 5, 64000, 1, VDD_3, 61440, 0, 0, 12 }, + { 176000, ACPU_PLL_2, 2, 5, 88000, 1, VDD_3, 61440, 0, 0, 11 }, + { 192000, ACPU_PLL_1, 1, 3, 64000, 2, VDD_3, 61440, 0, 0, 12 }, + { 245760, ACPU_PLL_0, 4, 0, 81920, 2, VDD_4, 61440, 0, 0, 12 }, + { 256000, ACPU_PLL_1, 1, 2, 128000, 2, VDD_5, 128000, 0, 0, 12 }, + { 264000, ACPU_PLL_2, 2, 3, 88000, 2, VDD_5, 128000, 0, 6, 13 }, + { 352000, ACPU_PLL_2, 2, 2, 88000, 3, VDD_5, 128000, 0, 6, 13 }, + { 384000, ACPU_PLL_1, 1, 1, 128000, 2, VDD_6, 128000, 0, 5, -1 }, + { 528000, ACPU_PLL_2, 2, 1, 132000, 3, VDD_7, 128000, 0, 11, -1 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, }; #else /* Table of freq we currently use. */ static struct clkctl_acpu_speed acpu_freq_tbl[] = { - { 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, VDD_0, 0, 0, 4 }, - { 122880, ACPU_PLL_0, 4, 1, 61440, 1, VDD_3, 0, 0, 4 }, - { 128000, ACPU_PLL_1, 1, 5, 64000, 1, VDD_3, 0, 0, 6 }, - { 176000, ACPU_PLL_2, 2, 5, 88000, 1, VDD_3, 0, 0, 5 }, - { 245760, ACPU_PLL_0, 4, 0, 81920, 2, VDD_4, 0, 0, 5 }, - { 352000, ACPU_PLL_2, 2, 2, 88000, 3, VDD_5, 0, 3, 7 }, - { 384000, ACPU_PLL_1, 1, 1, 128000, 2, VDD_6, 0, 2, -1 }, - { 528000, ACPU_PLL_2, 2, 1, 132000, 3, VDD_7, 0, 5, -1 }, - { 0, 0, 0, 0, 0, 0, 0}, + { 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, VDD_0, 30720, 0, 0, 4 }, + { 122880, ACPU_PLL_0, 4, 1, 61440, 1, VDD_3, 61440, 0, 0, 4 }, + { 128000, ACPU_PLL_1, 1, 5, 64000, 1, VDD_3, 61440, 0, 0, 6 }, + { 176000, ACPU_PLL_2, 2, 5, 88000, 1, VDD_3, 61440, 0, 0, 5 }, + { 245760, ACPU_PLL_0, 4, 0, 81920, 2, VDD_4, 61440, 0, 0, 5 }, + { 352000, ACPU_PLL_2, 2, 2, 88000, 3, VDD_5, 128000, 0, 3, 7 }, + { 384000, ACPU_PLL_1, 1, 1, 128000, 2, VDD_6, 128000, 0, 2, -1 }, + { 528000, ACPU_PLL_2, 2, 1, 132000, 3, VDD_7, 128000, 0, 5, -1 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, }; #endif @@ -373,6 +375,13 @@ int acpuclk_set_rate(unsigned long rate, int for_power_collapse) } } + /* Change the AXI bus frequency if we can. */ + if (strt_s->axiclk_khz != tgt_s->axiclk_khz) { + rc = clk_set_rate(ebi1_clk, tgt_s->axiclk_khz * 1000); + if (rc < 0) + pr_err("Setting AXI min rate failed!\n"); + } + /* Drop VDD level if we can. */ if (tgt_s->vdd < strt_s->vdd) { if (acpuclk_set_vdd_level(tgt_s->vdd) < 0) @@ -395,6 +404,7 @@ static void __init acpuclk_init(void) { struct clkctl_acpu_speed *speed; uint32_t div, sel; + int rc; /* * Determine the rate of ACPU clock @@ -424,6 +434,10 @@ static void __init acpuclk_init(void) drv_state.current_speed = speed; + rc = clk_set_rate(ebi1_clk, speed->axiclk_khz * 1000); + if (rc < 0) + pr_err("Setting AXI min rate failed!\n"); + printk(KERN_INFO "ACPU running at %d KHz\n", speed->a11clk_khz); } @@ -462,6 +476,8 @@ void __init msm_acpu_clock_init(struct msm_acpu_clock_platform_data *clkdata) { pr_info("acpu_clock_init()\n"); + ebi1_clk = clk_get(NULL, "ebi1_clk"); + mutex_init(&drv_state.lock); drv_state.acpu_switch_time_us = clkdata->acpu_switch_time_us; drv_state.max_speed_delta_khz = clkdata->max_speed_delta_khz; diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c index fbfb0fd4b76e..fa21e45edb60 100644 --- a/arch/arm/mach-msm/clock.c +++ b/arch/arm/mach-msm/clock.c @@ -48,7 +48,7 @@ static inline int pc_clk_set_rate(unsigned id, unsigned rate) return msm_proc_comm(PCOM_CLKCTL_RPC_SET_RATE, &id, &rate); } -static inline int pc_clk_set_min_rate(unsigned id, unsigned rate) +static int pc_clk_set_min_rate(unsigned id, unsigned rate) { return msm_proc_comm(PCOM_CLKCTL_RPC_MIN_RATE, &id, &rate); } @@ -147,12 +147,21 @@ EXPORT_SYMBOL(clk_get_rate); int clk_set_rate(struct clk *clk, unsigned long rate) { int ret; - if (clk->flags & CLKFLAG_USE_MIN_MAX_TO_SET) { + if (clk->flags & CLKFLAG_USE_MAX_TO_SET) { ret = pc_clk_set_max_rate(clk->id, rate); if (ret) return ret; - return pc_clk_set_min_rate(clk->id, rate); } + if (clk->flags & CLKFLAG_USE_MIN_TO_SET) { + ret = pc_clk_set_min_rate(clk->id, rate); + if (ret) + return ret; + } + + if (clk->flags & CLKFLAG_USE_MAX_TO_SET || + clk->flags & CLKFLAG_USE_MIN_TO_SET) + return ret; + return pc_clk_set_rate(clk->id, rate); } EXPORT_SYMBOL(clk_set_rate); diff --git a/arch/arm/mach-msm/clock.h b/arch/arm/mach-msm/clock.h index 51e7ed7bdc1a..af9a5a76af80 100644 --- a/arch/arm/mach-msm/clock.h +++ b/arch/arm/mach-msm/clock.h @@ -19,8 +19,9 @@ #include -#define CLKFLAG_USE_MIN_MAX_TO_SET (0x00000001) +#define CLKFLAG_USE_MAX_TO_SET (0x00000001) #define CLKFLAG_AUTO_OFF (0x00000002) +#define CLKFLAG_USE_MIN_TO_SET (0x00000004) #define CLKFLAG_ARCH_MSM7X00A (0x00010000) #define CLKFLAG_ARCH_ALL (0xffff0000) diff --git a/arch/arm/mach-msm/devices.c b/arch/arm/mach-msm/devices.c index 42ca4a6ed0c3..928a2290741b 100644 --- a/arch/arm/mach-msm/devices.c +++ b/arch/arm/mach-msm/devices.c @@ -302,12 +302,13 @@ int __init msm_add_sdcc(unsigned int controller, struct mmc_platform_data *plat) CLOCK(name, id, dev, flags, CLKFLAG_ARCH_MSM7X00A) #define OFF CLKFLAG_AUTO_OFF -#define MINMAX CLKFLAG_USE_MIN_MAX_TO_SET +#define MINMAX (CLKFLAG_USE_MIN_TO_SET | CLKFLAG_USE_MAX_TO_SET) +#define USE_MIN CLKFLAG_USE_MIN_TO_SET struct clk msm_clocks[] = { CLK_ALL("adm_clk", ADM_CLK, NULL, 0), CLK_ALL("adsp_clk", ADSP_CLK, NULL, 0), - CLK_ALL("ebi1_clk", EBI1_CLK, NULL, 0), + CLK_ALL("ebi1_clk", EBI1_CLK, NULL, USE_MIN), CLK_ALL("ebi2_clk", EBI2_CLK, NULL, 0), CLK_ALL("ecodec_clk", ECODEC_CLK, NULL, 0), CLK_ALL("mddi_clk", EMDH_CLK, &msm_device_mddi1.dev, OFF), -- cgit v1.2.3 From 74cb3b4c43376966e971ed8f057a2cb3b7efb0c9 Mon Sep 17 00:00:00 2001 From: Mike Chan Date: Tue, 6 Jan 2009 17:09:30 -0700 Subject: [ARM] msm: Move cpufreq code from acpuclk.c to cpufreq.c The acpuclk.c has function calls used to notify the cpufreq framework when the acpuclk frequency is changed. These notifications are cpufreq specific and independent of acpu clk. Signed-off-by: Mike Chan --- arch/arm/mach-msm/acpuclock.c | 12 ------------ arch/arm/mach-msm/cpufreq.c | 10 ++++++++-- 2 files changed, 8 insertions(+), 14 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/acpuclock.c b/arch/arm/mach-msm/acpuclock.c index 9a554ac8350e..5b88f40b8251 100644 --- a/arch/arm/mach-msm/acpuclock.c +++ b/arch/arm/mach-msm/acpuclock.c @@ -271,9 +271,6 @@ int acpuclk_set_rate(unsigned long rate, int for_power_collapse) uint32_t reg_clkctl; struct clkctl_acpu_speed *cur_s, *tgt_s, *strt_s; int rc = 0; -#ifdef CONFIG_MSM_CPU_FREQ_ONDEMAND - struct cpufreq_freqs freqs; -#endif strt_s = cur_s = drv_state.current_speed; @@ -300,12 +297,6 @@ int acpuclk_set_rate(unsigned long rate, int for_power_collapse) if (!for_power_collapse) { mutex_lock(&drv_state.lock); -#ifdef CONFIG_MSM_CPU_FREQ_ONDEMAND - freqs.old = cur_s->a11clk_khz; - freqs.new = tgt_s->a11clk_khz; - freqs.cpu = smp_processor_id(); - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); -#endif if (strt_s->pll != tgt_s->pll && tgt_s->pll != ACPU_PLL_TCXO) { if ((rc = pc_pll_request(tgt_s->pll, 1)) < 0) { printk(KERN_ERR "PLL enable failed (%d)\n", rc); @@ -388,9 +379,6 @@ int acpuclk_set_rate(unsigned long rate, int for_power_collapse) printk(KERN_ERR "acpuclock: Unable to drop ACPU vdd\n"); } -#ifdef CONFIG_MSM_CPU_FREQ_ONDEMAND - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); -#endif #if PERF_SWITCH_DEBUG printk(KERN_DEBUG "%s: ACPU speed change complete\n", __FUNCTION__); #endif diff --git a/arch/arm/mach-msm/cpufreq.c b/arch/arm/mach-msm/cpufreq.c index 2e5f119160a0..729391c64424 100644 --- a/arch/arm/mach-msm/cpufreq.c +++ b/arch/arm/mach-msm/cpufreq.c @@ -53,6 +53,7 @@ static int msm_cpufreq_target(struct cpufreq_policy *policy, unsigned int relation) { int index; + struct cpufreq_freqs freqs; struct cpufreq_frequency_table *table = cpufreq_frequency_get_table(smp_processor_id()); @@ -66,7 +67,12 @@ static int msm_cpufreq_target(struct cpufreq_policy *policy, printk("msm_cpufreq_target %d r %d (%d-%d) selected %d\n", target_freq, relation, policy->min, policy->max, table[index].frequency); #endif + freqs.old = policy->cur; + freqs.new = table[index].frequency; + freqs.cpu = smp_processor_id(); + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); acpuclk_set_rate(table[index].frequency * 1000, 0); + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); return 0; } @@ -74,7 +80,7 @@ static int msm_cpufreq_verify(struct cpufreq_policy *policy) { cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, policy->cpuinfo.max_freq); -return 0; + return 0; } static int __init msm_cpufreq_init(struct cpufreq_policy *policy) @@ -96,7 +102,7 @@ static int __init msm_cpufreq_init(struct cpufreq_policy *policy) } static struct cpufreq_driver msm_cpufreq_driver = { - /* lps calculstaions are handled here. */ + /* lps calculations are handled here. */ .flags = CPUFREQ_STICKY | CPUFREQ_CONST_LOOPS, .init = msm_cpufreq_init, .verify = msm_cpufreq_verify, -- cgit v1.2.3 From 5584b4f95674fc7ef5a61e309e1ee1926ac8b82e Mon Sep 17 00:00:00 2001 From: Mike Chan Date: Mon, 5 Jan 2009 23:00:02 -0800 Subject: [ARM] msm: acpuclock: Enable PLLs of stepping freqs when necessary. Signed-off-by: Mike Chan --- arch/arm/mach-msm/acpuclock.c | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/acpuclock.c b/arch/arm/mach-msm/acpuclock.c index 5b88f40b8251..7a413e3ef308 100644 --- a/arch/arm/mach-msm/acpuclock.c +++ b/arch/arm/mach-msm/acpuclock.c @@ -271,6 +271,7 @@ int acpuclk_set_rate(unsigned long rate, int for_power_collapse) uint32_t reg_clkctl; struct clkctl_acpu_speed *cur_s, *tgt_s, *strt_s; int rc = 0; + unsigned int plls_enabled = 0, pll; strt_s = cur_s = drv_state.current_speed; @@ -295,13 +296,19 @@ int acpuclk_set_rate(unsigned long rate, int for_power_collapse) tgt_s--; } + if (strt_s->pll != ACPU_PLL_TCXO) + plls_enabled |= 1 << strt_s->pll; + if (!for_power_collapse) { mutex_lock(&drv_state.lock); if (strt_s->pll != tgt_s->pll && tgt_s->pll != ACPU_PLL_TCXO) { - if ((rc = pc_pll_request(tgt_s->pll, 1)) < 0) { - printk(KERN_ERR "PLL enable failed (%d)\n", rc); + rc = pc_pll_request(tgt_s->pll, 1); + if (rc < 0) { + pr_err("PLL%d enable failed (%d)\n", + tgt_s->pll, rc); goto out; } + plls_enabled |= 1 << tgt_s->pll; } /* Increase VDD if needed. */ if (tgt_s->vdd > cur_s->vdd) { @@ -347,6 +354,17 @@ int acpuclk_set_rate(unsigned long rate, int for_power_collapse) printk(KERN_DEBUG "%s: STEP khz = %u, pll = %d\n", __FUNCTION__, cur_s->a11clk_khz, cur_s->pll); #endif + if (!for_power_collapse&& cur_s->pll != ACPU_PLL_TCXO + && !(plls_enabled & (1 << cur_s->pll))) { + rc = pc_pll_request(cur_s->pll, 1); + if (rc < 0) { + pr_err("PLL%d enable failed (%d)\n", + cur_s->pll, rc); + goto out; + } + plls_enabled |= 1 << cur_s->pll; + } + acpuclk_set_div(cur_s); drv_state.current_speed = cur_s; /* Re-adjust lpj for the new clock speed. */ @@ -358,13 +376,16 @@ int acpuclk_set_rate(unsigned long rate, int for_power_collapse) if (for_power_collapse) return 0; - /* Disable PLL we are not using anymore. */ - if (strt_s->pll != tgt_s->pll && tgt_s->pll != ACPU_PLL_TCXO) { - if ((rc = pc_pll_request(strt_s->pll, 0)) < 0) { - printk(KERN_ERR "PLL disable failed (%d)\n", rc); - goto out; + /* Disable PLLs we are not using anymore. */ + plls_enabled &= ~(1 << tgt_s->pll); + for (pll = ACPU_PLL_0; pll <= ACPU_PLL_2; pll++) + if (plls_enabled & (1 << pll)) { + rc = pc_pll_request(pll, 0); + if (rc < 0) { + pr_err("PLL%d disable failed (%d)\n", pll, rc); + goto out; + } } - } /* Change the AXI bus frequency if we can. */ if (strt_s->axiclk_khz != tgt_s->axiclk_khz) { -- cgit v1.2.3 From 579389b45ab053b2554750be5384437dede37c44 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Thu, 17 Dec 2009 11:28:23 -0800 Subject: Large update patch for arch/arm/mach-msm --- arch/arm/mach-msm/Kconfig | 269 ++- arch/arm/mach-msm/Makefile | 48 +- arch/arm/mach-msm/Makefile.boot | 12 + arch/arm/mach-msm/acpuclock-8x50.c | 589 +++++++ arch/arm/mach-msm/acpuclock.c | 647 +++++-- arch/arm/mach-msm/acpuclock.h | 28 +- arch/arm/mach-msm/board-comet.c | 1018 +++++++++++ arch/arm/mach-msm/board-halibut.c | 677 +++++++- arch/arm/mach-msm/board-msm7x27.c | 1093 ++++++++++++ arch/arm/mach-msm/board-qsd8x50.c | 1471 ++++++++++++++++ arch/arm/mach-msm/board-sapphire.c | 8 + arch/arm/mach-msm/board-trout.c | 16 +- arch/arm/mach-msm/clock.c | 254 ++- arch/arm/mach-msm/clock.h | 54 +- arch/arm/mach-msm/cpufreq.c | 50 +- arch/arm/mach-msm/dal.c | 1363 +++++++++++++++ arch/arm/mach-msm/dal_remotetest.c | 454 +++++ arch/arm/mach-msm/dal_remotetest.h | 216 +++ arch/arm/mach-msm/devices.c | 369 +++- arch/arm/mach-msm/devices.h | 20 +- arch/arm/mach-msm/dma.c | 2 + arch/arm/mach-msm/dma_test.c | 405 +++++ arch/arm/mach-msm/gpio.c | 129 +- arch/arm/mach-msm/gpio.h | 64 + arch/arm/mach-msm/gpio_hw-7xxx.h | 73 + arch/arm/mach-msm/gpio_hw-8xxx.h | 141 ++ arch/arm/mach-msm/gpio_hw.h | 72 +- arch/arm/mach-msm/idle-v6.S | 140 ++ arch/arm/mach-msm/idle-v7.S | 150 ++ arch/arm/mach-msm/idle.S | 106 -- arch/arm/mach-msm/idle.h | 65 + arch/arm/mach-msm/include/mach/board.h | 11 +- arch/arm/mach-msm/include/mach/camera.h | 326 ++++ arch/arm/mach-msm/include/mach/clk.h | 68 + arch/arm/mach-msm/include/mach/dal.h | 184 ++ arch/arm/mach-msm/include/mach/dma.h | 3 + arch/arm/mach-msm/include/mach/dma_test.h | 96 + arch/arm/mach-msm/include/mach/gpio.h | 45 + arch/arm/mach-msm/include/mach/htc_pwrsink.h | 1 - arch/arm/mach-msm/include/mach/io.h | 2 +- arch/arm/mach-msm/include/mach/irqs-7xxx.h | 74 + arch/arm/mach-msm/include/mach/irqs-8xxx.h | 131 ++ arch/arm/mach-msm/include/mach/irqs.h | 74 +- arch/arm/mach-msm/include/mach/memory.h | 29 +- arch/arm/mach-msm/include/mach/mpp.h | 90 + arch/arm/mach-msm/include/mach/msm_handset.h | 36 + arch/arm/mach-msm/include/mach/msm_i2ckbd.h | 70 + arch/arm/mach-msm/include/mach/msm_iomap.h | 53 +- arch/arm/mach-msm/include/mach/msm_otg.h | 72 + arch/arm/mach-msm/include/mach/msm_rpcrouter.h | 26 +- arch/arm/mach-msm/include/mach/msm_smd.h | 31 +- arch/arm/mach-msm/include/mach/msm_touch.h | 26 + arch/arm/mach-msm/include/mach/msm_touchpad.h | 66 + arch/arm/mach-msm/include/mach/pmic.h | 140 ++ arch/arm/mach-msm/include/mach/remote_spinlock.h | 75 + arch/arm/mach-msm/include/mach/rpc_hsusb.h | 45 + arch/arm/mach-msm/include/mach/sirc.h | 132 ++ arch/arm/mach-msm/include/mach/smem_log.h | 261 +++ arch/arm/mach-msm/include/mach/usbdiag.h | 44 + arch/arm/mach-msm/include/mach/vmalloc.h | 2 +- arch/arm/mach-msm/include/mach/vreg.h | 2 +- arch/arm/mach-msm/io.c | 98 +- arch/arm/mach-msm/irq.c | 174 +- arch/arm/mach-msm/irq.h | 72 + arch/arm/mach-msm/keypad-surf-ffa.c | 316 ++++ arch/arm/mach-msm/keypad-surf-ffa.h | 29 + arch/arm/mach-msm/memory.c | 86 + arch/arm/mach-msm/modem_notifier.c | 237 +++ arch/arm/mach-msm/modem_notifier.h | 77 + arch/arm/mach-msm/mpp.c | 163 ++ arch/arm/mach-msm/msm-keypad-devices.h | 22 + arch/arm/mach-msm/nand_partitions.c | 106 +- arch/arm/mach-msm/nohlt.c | 86 + arch/arm/mach-msm/pm.c | 594 +++++-- arch/arm/mach-msm/pm.h | 29 +- arch/arm/mach-msm/pm2.c | 1606 +++++++++++++++++ arch/arm/mach-msm/pmic.c | 820 +++++++++ arch/arm/mach-msm/proc_comm.c | 85 +- arch/arm/mach-msm/proc_comm.h | 180 +- arch/arm/mach-msm/remote_spinlock.c | 111 ++ arch/arm/mach-msm/reset_modem.c | 226 +++ arch/arm/mach-msm/rpc_hsusb.c | 574 ++++++ arch/arm/mach-msm/rpc_server_dog_keepalive.c | 31 +- arch/arm/mach-msm/rpc_server_handset.c | 188 ++ arch/arm/mach-msm/rpc_server_time_remote.c | 31 +- arch/arm/mach-msm/rpc_server_time_remote.h | 21 + arch/arm/mach-msm/sirc.c | 239 +++ arch/arm/mach-msm/smd.c | 1219 +++++++++---- arch/arm/mach-msm/smd_ctl2.c | 689 ++++++++ arch/arm/mach-msm/smd_loopback.c | 306 ++++ arch/arm/mach-msm/smd_nmea.c | 249 +++ arch/arm/mach-msm/smd_private.h | 153 +- arch/arm/mach-msm/smd_rpcrouter.c | 1283 ++++++++++++-- arch/arm/mach-msm/smd_rpcrouter.h | 42 +- arch/arm/mach-msm/smd_rpcrouter_device.c | 53 +- arch/arm/mach-msm/smd_rpcrouter_servers.c | 17 +- arch/arm/mach-msm/smd_tty.c | 164 +- arch/arm/mach-msm/smem_log.c | 2019 ++++++++++++++++++++++ arch/arm/mach-msm/socinfo.c | 326 ++++ arch/arm/mach-msm/socinfo.h | 116 ++ arch/arm/mach-msm/timer.c | 400 ++++- arch/arm/mach-msm/timer.h | 67 + arch/arm/mach-msm/vreg.c | 108 +- 103 files changed, 24054 insertions(+), 1576 deletions(-) create mode 100644 arch/arm/mach-msm/acpuclock-8x50.c create mode 100644 arch/arm/mach-msm/board-comet.c create mode 100644 arch/arm/mach-msm/board-msm7x27.c create mode 100644 arch/arm/mach-msm/board-qsd8x50.c create mode 100644 arch/arm/mach-msm/dal.c create mode 100644 arch/arm/mach-msm/dal_remotetest.c create mode 100644 arch/arm/mach-msm/dal_remotetest.h create mode 100644 arch/arm/mach-msm/dma_test.c create mode 100644 arch/arm/mach-msm/gpio.h create mode 100644 arch/arm/mach-msm/gpio_hw-7xxx.h create mode 100644 arch/arm/mach-msm/gpio_hw-8xxx.h create mode 100644 arch/arm/mach-msm/idle-v6.S create mode 100644 arch/arm/mach-msm/idle-v7.S delete mode 100644 arch/arm/mach-msm/idle.S create mode 100644 arch/arm/mach-msm/idle.h create mode 100644 arch/arm/mach-msm/include/mach/camera.h create mode 100644 arch/arm/mach-msm/include/mach/clk.h create mode 100644 arch/arm/mach-msm/include/mach/dal.h create mode 100644 arch/arm/mach-msm/include/mach/dma_test.h create mode 100644 arch/arm/mach-msm/include/mach/irqs-7xxx.h create mode 100644 arch/arm/mach-msm/include/mach/irqs-8xxx.h create mode 100644 arch/arm/mach-msm/include/mach/mpp.h create mode 100644 arch/arm/mach-msm/include/mach/msm_handset.h create mode 100644 arch/arm/mach-msm/include/mach/msm_i2ckbd.h create mode 100644 arch/arm/mach-msm/include/mach/msm_otg.h create mode 100644 arch/arm/mach-msm/include/mach/msm_touch.h create mode 100644 arch/arm/mach-msm/include/mach/msm_touchpad.h create mode 100644 arch/arm/mach-msm/include/mach/pmic.h create mode 100644 arch/arm/mach-msm/include/mach/remote_spinlock.h create mode 100644 arch/arm/mach-msm/include/mach/rpc_hsusb.h create mode 100644 arch/arm/mach-msm/include/mach/sirc.h create mode 100644 arch/arm/mach-msm/include/mach/smem_log.h create mode 100644 arch/arm/mach-msm/include/mach/usbdiag.h create mode 100644 arch/arm/mach-msm/irq.h create mode 100644 arch/arm/mach-msm/keypad-surf-ffa.c create mode 100644 arch/arm/mach-msm/keypad-surf-ffa.h create mode 100644 arch/arm/mach-msm/memory.c create mode 100644 arch/arm/mach-msm/modem_notifier.c create mode 100644 arch/arm/mach-msm/modem_notifier.h create mode 100644 arch/arm/mach-msm/mpp.c create mode 100644 arch/arm/mach-msm/msm-keypad-devices.h create mode 100644 arch/arm/mach-msm/nohlt.c create mode 100644 arch/arm/mach-msm/pm2.c create mode 100644 arch/arm/mach-msm/pmic.c create mode 100644 arch/arm/mach-msm/remote_spinlock.c create mode 100644 arch/arm/mach-msm/reset_modem.c create mode 100644 arch/arm/mach-msm/rpc_hsusb.c create mode 100644 arch/arm/mach-msm/rpc_server_handset.c create mode 100644 arch/arm/mach-msm/rpc_server_time_remote.h create mode 100644 arch/arm/mach-msm/sirc.c create mode 100644 arch/arm/mach-msm/smd_ctl2.c create mode 100644 arch/arm/mach-msm/smd_loopback.c create mode 100644 arch/arm/mach-msm/smd_nmea.c create mode 100644 arch/arm/mach-msm/smem_log.c create mode 100644 arch/arm/mach-msm/socinfo.c create mode 100644 arch/arm/mach-msm/socinfo.h create mode 100644 arch/arm/mach-msm/timer.h (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index 407ca114ea4e..d065cf586a8a 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -1,4 +1,12 @@ -if ARCH_MSM +if ARCH_MSM || ARCH_QSD + +config MSM_STACKED_MEMORY + bool "Stacked Memory" + default y + help + This option is used to indicate the presence of on-die stacked + memory. When present this memory bank is used for a high speed + shared memory interface. When not present regular RAM is used. config MSM_AMSS_VERSION int @@ -51,21 +59,57 @@ endchoice config MACH_HALIBUT depends on ARCH_MSM select CPU_V6 + depends on MSM_STACKED_MEMORY default y bool "Halibut Board (QCT SURF7201A)" help Support for the Qualcomm SURF7201A eval board. +config MACH_MSM7201A_SURF + depends on ARCH_MSM + depends on MSM_STACKED_MEMORY + default y + bool "MSM7201A SURF" + help + Support for the Qualcomm MSM7201A SURF eval board. + +config MACH_MSM7201A_FFA + depends on ARCH_MSM + depends on MSM_STACKED_MEMORY + default y + bool "MSM7201A FFA" + help + Support for the Qualcomm MSM7201A FFA eval board. + config MACH_TROUT select CPU_V6 + depends on MSM_STACKED_MEMORY default y bool "HTC Dream (aka trout)" help Support for the HTC Dream, T-Mobile G1, Android ADP1 devices. -config MACH_SAPPHIRE +config MACH_MSM7X27_SURF depends on ARCH_MSM + depends on !MSM_STACKED_MEMORY default y + bool "MSM7x27 SURF" + help + Support for the Qualcomm MSM7x27 SURF eval board. + +config MACH_MSM7X27_FFA + depends on ARCH_MSM + depends on !MSM_STACKED_MEMORY + default y + bool "MSM7x27 FFA" + help + Support for the Qualcomm MSM7x27 FFA eval board. + +# config TROUT_H2W + +config MACH_SAPPHIRE + depends on ARCH_MSM + default n bool "Sapphire" config HTC_HEADSET @@ -83,9 +127,36 @@ config TROUT_BATTCHG config HTC_PWRSINK depends on MSM_SMD - default y + default n bool "HTC Power Sink Driver" +comment "QSD Board Type" + depends on ARCH_QSD + +config MACH_QSD8X50_SURF + depends on ARCH_QSD + depends on MSM_STACKED_MEMORY + default y + bool "QSD8x50 SURF" + help + Support for the Qualcomm QSD8x50 SURF eval board. + +config MACH_QSD8X50_FFA + depends on ARCH_QSD + depends on MSM_STACKED_MEMORY + default y + bool "QSD8x50 FFA" + help + Support for the Qualcomm QSD8x50 FFA eval board. + +config MACH_QSD8X50_COMET + depends on ARCH_QSD + depends on MSM_STACKED_MEMORY + default n + bool "QSD8x50 Comet" + help + Support for the Qualcomm Comet eval board. + choice prompt "Default Timer" default MSM7X00A_USE_GP_TIMER @@ -196,7 +267,7 @@ config MSM_IDLE_STATS_FIRST_BUCKET int "First bucket time" default 62500 help - Upper time limit in nanosconds of first bucket. + Upper time limit in nanoseconds of first bucket. config MSM_IDLE_STATS_BUCKET_SHIFT int "Bucket shift" @@ -206,8 +277,23 @@ config MSM_IDLE_STATS_BUCKET_COUNT int "Bucket count" default 10 +config MSM_SUSPEND_STATS_FIRST_BUCKET + int "First bucket time for suspend" + default 1000000000 + help + Upper time limit in nanoseconds of first bucket of the + histogram. This is for collecting statistics on suspend. + endif # MSM_IDLE_STATS +config QSD_SVS + bool "QSD Static Voltage Scaling" + depends on (MACH_QSD8X50_SURF || MACH_QSD8X50_FFA || MACH_QSD8X50_COMET) + default y + select TPS65023 + help + Enables static voltage scaling using the TPS65023 PMIC. + config MSM_FIQ_SUPPORT default y bool "Enable installation of an FIQ handler." @@ -222,6 +308,42 @@ config MSM_SMD used to communicate with various services on the baseband processor. +choice + prompt "MSM Shared memory interface version" + depends on MSM_SMD + default MSM_SMD_PKG3 if ARCH_MSM + default MSM_SMD_PKG4 if ARCH_QSD + + config MSM_SMD_PKG3 + bool "Package 3" + + config MSM_SMD_PKG4 + bool "Package 4" +endchoice + +config MSM_N_WAY_SMD + depends on (MSM_SMD && (ARCH_QSD || MACH_MSM7X27_SURF || MACH_MSM7X27_FFA)) + default y + bool "MSM N-WAY SMD support" + help + Supports APPS-QDSP SMD communication along with + normal APPS-MODEM SMD communication. + +config MSM_N_WAY_SMSM + depends on (MSM_SMD && (ARCH_QSD || MACH_MSM7X27_SURF || MACH_MSM7X27_FFA)) + default y + bool "MSM N-WAY SMSM support" + help + Supports APPS-QDSP SMSM communication along with + normal APPS-MODEM SMSM communication. + +config MSM_RESET_MODEM + tristate "Reset Modem Driver" + depends on MSM_SMD + default m + help + Allows the user to reset the modem through a device node. + config MSM_ONCRPCROUTER depends on MSM_SMD default y @@ -230,33 +352,50 @@ config MSM_ONCRPCROUTER Support for the MSM ONCRPC router for communication between the ARM9 and ARM11 +config MSM_ONCRPCROUTER_DEBUG + depends on MSM_ONCRPCROUTER + default y + bool "MSM debug ONCRPC router support" + help + Support for debugging the ONCRPC router for communication + between the ARM9 and ARM11 + config MSM_RPCSERVERS depends on MSM_ONCRPCROUTER + select RTC_HCTOSYS default y bool "Kernel side RPC server bundle" help none -config MSM_CPU_FREQ - bool - default y if MSM_CPU_FREQ_ONDEMAND || MSM_CPU_FREQ_SCREEN - -choice - prompt "Cpufreq mode" - default MSM_CPU_FREQ_ONDEMAND - default MSM_CPU_FREQ_SCREEN +config MSM_RPCSERVER_HANDSET + depends on MSM_ONCRPCROUTER + default y + bool "Handset events RPC server" + help + Support for receiving handset events like headset detect, + headset switch and clamshell state. - config MSM_CPU_FREQ_ONDEMAND - depends on CPU_FREQ_DEFAULT_GOV_ONDEMAND - bool "Enable ONDEMAND cpufreq govoner for" +config MSM_DALRPC + bool "DAL RPC support" + depends on ARCH_QSD + default y + help + Supports RPC calls to DAL devices on remote processor cores. - config MSM_CPU_FREQ_SCREEN - depends on HAS_EARLYSUSPEND - bool "Enable simple cpu frequency scaling" - help - Simple cpufreq scaling based on screen ON/OFF. +config MSM_DALRPC_TEST + tristate "DAL RPC test module" + depends on (MSM_DALRPC && DEBUG_FS) + default m + help + Exercises DAL RPC calls to QDSP6. -endchoice +config MSM_CPU_FREQ_SCREEN + depends on (HAS_EARLYSUSPEND && !CPU_FREQ_MSM) + default n + bool "Enable simple cpu frequency scaling" + help + Simple cpufreq scaling based on screen ON/OFF. if MSM_CPU_FREQ_SCREEN @@ -270,17 +409,40 @@ config MSM_CPU_FREQ_SCREEN_ON endif # MSM_CPU_FREQ_SCREEN -if MSM_CPU_FREQ_ONDEMAND +if CPU_FREQ_MSM + +config MSM_CPU_FREQ_SET_MIN_MAX + bool "Set Min/Max CPU frequencies." + default n + help + Allow setting min and max CPU frequencies. Sysfs can be used + to override these values. -config MSM_CPU_FREQ_ONDEMAND_MAX - int "Max" +config MSM_CPU_FREQ_MAX + int "Max CPU Frequency" + depends on MSM_CPU_FREQ_SET_MIN_MAX default 384000 -config MSM_CPU_FREQ_ONDEMAND_MIN - int "Min" +config MSM_CPU_FREQ_MIN + int "Min CPU Frequency" + depends on MSM_CPU_FREQ_SET_MIN_MAX default 245760 -endif # MSM_CPU_FREQ_ONDEMAND +endif # CPU_FREQ_MSM + +config MSM_VREG_SWITCH_INVERTED + bool "Reverse vreg switch polarity" + default n + help + Reverses the enable and disable for vreg switch. + +config MSM_DMA_TEST + tristate "MSM DMA test module" + depends on (ARCH_MSM || ARCH_QSD) + default m + help + Intended to be compiled as a module. Provides a device node + and ioctls for testing the MSM dma system. config WIFI_CONTROL_FUNC bool "Enable WiFi control function abstraction" @@ -292,4 +454,57 @@ config WIFI_MEM_PREALLOC bool "Preallocate memory for WiFi buffers" help Preallocates memory buffers for WiFi driver + +config QSD_AUDIO + bool "QSD audio" + depends on (ARCH_QSD && MSM_DALRPC) + default y + help + Provides PCM, MP3, and AAC audio playback. + +config AUDIO_AAC_PLUS + depends on (MSM_ADSP || QSD_AUDIO) + bool "AAC+ Audio" + default y + help + Provides AAC+ decoding + +config AUDIO_ENHANCED_AAC_PLUS + depends on AUDIO_AAC_PLUS + bool "Enhanced AAC+ Audio" + default y + help + Provides Enhanced AAC+ decoding + +config SURF_FFA_GPIO_KEYPAD + bool "MSM SURF/FFA GPIO keypad" + depends on (ARCH_QSD || ARCH_MSM) && INPUT_GPIO = "y" + default y + help + Select if the GPIO keypad is attached. + +config CLOCK_BASED_SLEEP_LIMIT + default y + bool "Set sleep limitation based on clock usage" + help + The application processor checks for enabled clocks and + decides accordingly the sleep limitation which it informs + the modem to use. + +config MSM_ADM_OFF_AT_POWER_COLLAPSE + bool "Turn off ADM clock during power collapse" + default n + help + The application processor turns off the ADM clock before + entering power collapse and turns it back on after exiting + power collapse. + +config MSM_SLEEP_TIME_OVERRIDE + bool "Allow overriding suspend/sleep time with PM module parameter" + default y + help + Enable the module parameter sleep_time_override. Specified + in units of seconds, it overwrites the normal sleep time of + suspend. The feature is required for automated power management + testing. endif diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 1618d2929177..44db40cbb6e6 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -1,29 +1,61 @@ -obj-y += io.o idle.o irq.o timer.o dma.o +obj-y += io.o irq.o timer.o dma.o obj-y += devices.o -obj-y += devices_htc.o obj-y += proc_comm.o +obj-y += vreg.o mpp.o obj-y += vreg.o -obj-y += acpuclock.o obj-y += clock.o obj-y += gpio.o generic_gpio.o obj-y += nand_partitions.o +obj-y += remote_spinlock.o modem_notifier.o +obj-y += rpc_hsusb.o +obj-y += socinfo.o +obj-y += cpufreq.o +obj-y += nohlt.o + +obj-$(CONFIG_ARCH_MSM) += acpuclock.o +obj-$(CONFIG_ARCH_MSM) += pmic.o +obj-$(CONFIG_ARCH_QSD) += acpuclock-8x50.o sirc.o +obj-$(CONFIG_ARCH_QSD) += pmic.o +obj-$(CONFIG_CPU_V6) += idle-v6.o +obj-$(CONFIG_CPU_V7) += idle-v7.o obj-$(CONFIG_MSM_FIQ_SUPPORT) += fiq_glue.o obj-$(CONFIG_MACH_TROUT) += board-trout-rfkill.o -obj-$(CONFIG_MSM_SMD) += smd.o smd_tty.o smd_qmi.o +obj-$(CONFIG_MSM_SMD) += smd.o smd_tty.o smd_qmi.o smem_log.o +obj-$(CONFIG_MSM_SMD) += smd_ctl2.o smd_loopback.o smd_nmea.o +obj-$(CONFIG_MSM_RESET_MODEM) += reset_modem.o obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter.o obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_device.o obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_servers.o obj-$(CONFIG_MSM_RPCSERVERS) += rpc_server_dog_keepalive.o obj-$(CONFIG_MSM_RPCSERVERS) += rpc_server_time_remote.o -obj-$(CONFIG_PM) += pm.o -obj-$(CONFIG_MSM_CPU_FREQ) += cpufreq.o - +obj-$(CONFIG_MSM_DALRPC) += dal.o +obj-$(CONFIG_MSM_DALRPC_TEST) += dal_remotetest.o +obj-$(CONFIG_MSM_RPCSERVER_HANDSET) += rpc_server_handset.o +ifdef CONFIG_MSM_N_WAY_SMSM + obj-$(CONFIG_PM) += pm2.o +else + obj-$(CONFIG_PM) += pm.o +endif +obj-$(CONFIG_MSM_DMA_TEST) += dma_test.o +obj-$(CONFIG_SURF_FFA_GPIO_KEYPAD) += keypad-surf-ffa.o obj-$(CONFIG_MACH_TROUT) += board-dream.o -obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o board-halibut-keypad.o +obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o +obj-$(CONFIG_MACH_MSM7201A_FFA) += board-halibut.o obj-$(CONFIG_MACH_TROUT) += htc_akm_cal.o htc_wifi_nvs.o htc_acoustic.o obj-$(CONFIG_MACH_TROUT) += board-trout-mmc.o board-trout-wifi.o +obj-$(CONFIG_MACH_QSD8X50_SURF) += board-qsd8x50.o +obj-$(CONFIG_MACH_QSD8X50_FFA) += board-qsd8x50.o +obj-$(CONFIG_MACH_QSD8X50_COMET) += board-comet.o +obj-$(CONFIG_TROUT_H2W) += board-trout-h2w.o +obj-$(CONFIG_TROUT_BATTCHG) += htc_battery.o +obj-$(CONFIG_TROUT_PWRSINK) += htc_pwrsink.o +obj-$(CONFIG_MACH_MSM7X27_SURF) += board-msm7x27.o +obj-$(CONFIG_MACH_MSM7X27_FFA) += board-msm7x27.o + +obj-$(CONFIG_QSD_AUDIO) += qdsp6/ + obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire.o board-sapphire-gpio.o obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire-keypad.o board-sapphire-panel.o obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire-mmc.o board-sapphire-wifi.o diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot index 24dfbf8c07c4..ff5582cdddeb 100644 --- a/arch/arm/mach-msm/Makefile.boot +++ b/arch/arm/mach-msm/Makefile.boot @@ -1,3 +1,15 @@ +ifeq ($(CONFIG_ARCH_QSD),y) + zreladdr-y := 0x16008000 +params_phys-y := 0x16000100 +initrd_phys-y := 0x1A000000 +else # !CONFIG_ARCH_QSD +ifeq ($(CONFIG_MSM_STACKED_MEMORY), y) zreladdr-y := 0x10008000 params_phys-y := 0x10000100 initrd_phys-y := 0x10800000 +else # !CONFIG_MSM_STACKED_MEMORY + zreladdr-y := 0x00208000 +params_phys-y := 0x00200100 +initrd_phys-y := 0x0A000000 +endif # CONFIG_MSM_STACKED_MEMORY +endif # CONFIG_ARCH_QSD diff --git a/arch/arm/mach-msm/acpuclock-8x50.c b/arch/arm/mach-msm/acpuclock-8x50.c new file mode 100644 index 000000000000..c7dbc910c3cf --- /dev/null +++ b/arch/arm/mach-msm/acpuclock-8x50.c @@ -0,0 +1,589 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "acpuclock.h" + +#define SHOT_SWITCH 4 +#define HOP_SWITCH 5 +#define SIMPLE_SLEW 6 +#define COMPLEX_SLEW 7 + +#define SPSS_CLK_CNTL_ADDR (MSM_CSR_BASE + 0x100) +#define SPSS_CLK_SEL_ADDR (MSM_CSR_BASE + 0x104) + +/* Scorpion PLL registers */ +#define SCPLL_CTL_ADDR (MSM_SCPLL_BASE + 0x4) +#define SCPLL_STATUS_ADDR (MSM_SCPLL_BASE + 0x18) +#define SCPLL_FSM_CTL_EXT_ADDR (MSM_SCPLL_BASE + 0x10) + +struct clkctl_acpu_speed { + unsigned int use_for_scaling; + unsigned int a11clk_khz; + int pll; + unsigned int a11clk_src_sel; + unsigned int a11clk_src_div; + unsigned int ahbclk_khz; + unsigned int ahbclk_div; + unsigned int sc_core_src_sel_mask; + unsigned int sc_l_value; + int vdd; + unsigned long lpj; /* loops_per_jiffy */ +}; + +struct clkctl_acpu_speed acpu_freq_tbl[] = { + { 0, 19200, ACPU_PLL_TCXO, 0, 0, 0, 0, 0, 0, 1000}, + { 0, 48000, ACPU_PLL_1, 1, 0xF, 0, 0, 0, 0, 1000}, + { 0, 64000, ACPU_PLL_1, 1, 0xB, 0, 0, 0, 0, 1000}, + { 0, 96000, ACPU_PLL_1, 1, 7, 0, 0, 0, 0, 1000}, + { 0, 128000, ACPU_PLL_1, 1, 5, 0, 0, 2, 0, 1000}, + { 0, 192000, ACPU_PLL_1, 1, 3, 0, 0, 0, 0, 1000}, + /* 235.93 on CDMA only. */ + { 1, 245000, ACPU_PLL_0, 4, 0, 0, 0, 0, 0, 1000}, + { 0, 256000, ACPU_PLL_1, 1, 2, 0, 0, 0, 0, 1000}, + { 1, 384000, ACPU_PLL_3, 0, 0, 0, 0, 1, 0xA, 1000}, + { 0, 422400, ACPU_PLL_3, 0, 0, 0, 0, 1, 0xB, 1000}, + { 0, 460800, ACPU_PLL_3, 0, 0, 0, 0, 1, 0xC, 1000}, + { 0, 499200, ACPU_PLL_3, 0, 0, 0, 0, 1, 0xD, 1025}, + { 0, 537600, ACPU_PLL_3, 0, 0, 0, 0, 1, 0xE, 1050}, + { 1, 576000, ACPU_PLL_3, 0, 0, 0, 0, 1, 0xF, 1050}, + { 0, 614400, ACPU_PLL_3, 0, 0, 0, 0, 1, 0x10, 1075}, + { 0, 652800, ACPU_PLL_3, 0, 0, 0, 0, 1, 0x11, 1100}, + { 0, 691200, ACPU_PLL_3, 0, 0, 0, 0, 1, 0x12, 1125}, + { 0, 729600, ACPU_PLL_3, 0, 0, 0, 0, 1, 0x13, 1150}, + { 1, 768000, ACPU_PLL_3, 0, 0, 0, 0, 1, 0x14, 1150}, + { 0, 806400, ACPU_PLL_3, 0, 0, 0, 0, 1, 0x15, 1175}, + { 0, 844800, ACPU_PLL_3, 0, 0, 0, 0, 1, 0x16, 1200}, + { 0, 883200, ACPU_PLL_3, 0, 0, 0, 0, 1, 0x17, 1225}, + { 0, 921600, ACPU_PLL_3, 0, 0, 0, 0, 1, 0x18, 1250}, + { 0, 960000, ACPU_PLL_3, 0, 0, 0, 0, 1, 0x19, 1250}, + { 1, 998400, ACPU_PLL_3, 0, 0, 0, 0, 1, 0x1A, 1250}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +}; + +#ifdef CONFIG_CPU_FREQ_MSM +static struct cpufreq_frequency_table freq_table[20]; + +static void __init cpufreq_table_init(void) +{ + unsigned int i; + unsigned int freq_cnt = 0; + + /* Construct the freq_table table from acpu_freq_tbl since the + * freq_table values need to match frequencies specified in + * acpu_freq_tbl and acpu_freq_tbl needs to be fixed up during init. + */ + for (i = 0; acpu_freq_tbl[i].a11clk_khz != 0 + && freq_cnt < ARRAY_SIZE(freq_table)-1; i++) { + if (acpu_freq_tbl[i].use_for_scaling) { + freq_table[freq_cnt].index = freq_cnt; + freq_table[freq_cnt].frequency + = acpu_freq_tbl[i].a11clk_khz; + freq_cnt++; + } + } + + /* freq_table not big enough to store all usable freqs. */ + BUG_ON(acpu_freq_tbl[i].a11clk_khz != 0); + + freq_table[freq_cnt].index = freq_cnt; + freq_table[freq_cnt].frequency = CPUFREQ_TABLE_END; + + pr_info("%d scaling frequencies supported.\n", freq_cnt); +} +#endif + +struct clock_state { + struct clkctl_acpu_speed *current_speed; + struct mutex lock; + uint32_t acpu_switch_time_us; + uint32_t max_speed_delta_khz; + uint32_t vdd_switch_time_us; + unsigned long power_collapse_khz; + unsigned long wait_for_irq_khz; + unsigned int max_vdd; + int (*acpu_set_vdd) (int mvolts); +}; + +static struct clock_state drv_state = { 0 }; + +static void scpll_set_freq(uint32_t lval, unsigned freq_switch) +{ + uint32_t regval; + + if (lval > 33) + lval = 33; + if (lval < 10) + lval = 10; + + /* wait for any calibrations or frequency switches to finish */ + while (readl(SCPLL_STATUS_ADDR) & 0x3) + ; + + /* write the new L val and switch mode */ + regval = readl(SCPLL_FSM_CTL_EXT_ADDR); + regval &= ~(0x3f << 3); + regval |= (lval << 3); + if (freq_switch == SIMPLE_SLEW) + regval |= (0x1 << 9); + + regval &= ~(0x3 << 0); + regval |= (freq_switch << 0); + writel(regval, SCPLL_FSM_CTL_EXT_ADDR); + + dmb(); + + /* put in normal mode */ + regval = readl(SCPLL_CTL_ADDR); + regval |= 0x7; + writel(regval, SCPLL_CTL_ADDR); + + dmb(); + + /* wait for frequency switch to finish */ + while (readl(SCPLL_STATUS_ADDR) & 0x1) + ; + + /* status bit seems to clear early, requires at least + * ~8 microseconds to settle, using 20 to be safe */ + udelay(20); +} + +static void scpll_apps_enable(bool state) +{ + uint32_t regval; + + /* Wait for any frequency switches to finish. */ + while (readl(SCPLL_STATUS_ADDR) & 0x1) + ; + + /* put the pll in standby mode */ + regval = readl(SCPLL_CTL_ADDR); + regval &= ~(0x7); + regval |= (0x2); + writel(regval, SCPLL_CTL_ADDR); + + dmb(); + + if (state) { + /* put the pll in normal mode */ + regval = readl(SCPLL_CTL_ADDR); + regval |= (0x7); + writel(regval, SCPLL_CTL_ADDR); + } else { + /* put the pll in power down mode */ + regval = readl(SCPLL_CTL_ADDR); + regval &= ~(0x7); + writel(regval, SCPLL_CTL_ADDR); + } + udelay(drv_state.vdd_switch_time_us); +} + +static void scpll_init(void) +{ + /* power down scpll */ + writel(0x0, SCPLL_CTL_ADDR); + + dmb(); + + /* set bypassnl, put into standby */ + writel(0x00400002, SCPLL_CTL_ADDR); + + /* set bypassnl, reset_n, full calibration */ + writel(0x00600004, SCPLL_CTL_ADDR); + + /* Ensure register write to initiate calibration has taken + effect before reading status flag */ + dmb(); + + /* wait for cal_all_done */ + while (readl(SCPLL_STATUS_ADDR) & 0x2) + ; + + /* power down scpll */ + writel(0x0, SCPLL_CTL_ADDR); +} + +static void config_pll(struct clkctl_acpu_speed *s) +{ + uint32_t regval; + + if (s->pll == ACPU_PLL_3) + scpll_set_freq(s->sc_l_value, SHOT_SWITCH); + else { + /* get the current clock source selection */ + regval = readl(SPSS_CLK_SEL_ADDR) & 0x1; + + /* configure the other clock source, then switch to it, + * using the glitch free mux */ + switch (regval) { + case 0x0: + regval = readl(SPSS_CLK_CNTL_ADDR); + regval &= ~(0x7 << 4 | 0xf); + regval |= (s->a11clk_src_sel << 4); + regval |= (s->a11clk_src_div << 0); + writel(regval, SPSS_CLK_CNTL_ADDR); + + regval = readl(SPSS_CLK_SEL_ADDR); + regval |= 0x1; + writel(regval, SPSS_CLK_SEL_ADDR); + break; + + case 0x1: + regval = readl(SPSS_CLK_CNTL_ADDR); + regval &= ~(0x7 << 12 | 0xf << 8); + regval |= (s->a11clk_src_sel << 12); + regval |= (s->a11clk_src_div << 8); + writel(regval, SPSS_CLK_CNTL_ADDR); + + regval = readl(SPSS_CLK_SEL_ADDR); + regval &= ~0x1; + writel(regval, SPSS_CLK_SEL_ADDR); + break; + } + dmb(); + } + + regval = readl(SPSS_CLK_SEL_ADDR); + regval &= ~(0x3 << 1); + regval |= (s->sc_core_src_sel_mask << 1); + writel(regval, SPSS_CLK_SEL_ADDR); +} + +void config_switching_pll(void) +{ + uint32_t regval; + + /* Use AXI clock temporarily when we're changing + * scpll. PLL0 is faster, but it may not be available during + * early modem initialization, and we will only be using this + * a very short time (while scpll is reconfigured). + */ + + regval = readl(SPSS_CLK_SEL_ADDR); + regval &= ~(0x3 << 1); + regval |= (0x2 << 1); + writel(regval, SPSS_CLK_SEL_ADDR); +} + +static int acpuclk_set_vdd_level(int vdd) +{ + if (drv_state.acpu_set_vdd) + return drv_state.acpu_set_vdd(vdd); + else { + /* Assume that the PMIC supports scaling the processor + * to its maximum frequency at its default voltage. + */ + return 0; + } +} + +int acpuclk_set_rate(unsigned long rate, enum setrate_reason reason) +{ + struct clkctl_acpu_speed *tgt_s, *strt_s; + int rc = 0; + + strt_s = drv_state.current_speed; + + if (rate == (strt_s->a11clk_khz * 1000)) + return 0; + + for (tgt_s = acpu_freq_tbl; tgt_s->a11clk_khz != 0; tgt_s++) { + if (tgt_s->a11clk_khz == (rate / 1000)) + break; + } + + if (tgt_s->a11clk_khz == 0) + return -EINVAL; + + if (reason == SETRATE_CPUFREQ) { + mutex_lock(&drv_state.lock); + + /* Increase VDD if needed. */ + if (tgt_s->vdd > strt_s->vdd) { + rc = acpuclk_set_vdd_level(tgt_s->vdd); + if (rc) { + printk(KERN_ERR + "acpuclock: Unable to increase ACPU " + "vdd.\n"); + goto out; + } + } + } + + if (strt_s->pll != ACPU_PLL_3 && tgt_s->pll != ACPU_PLL_3) { + config_pll(tgt_s); + } else if (strt_s->pll != ACPU_PLL_3 && tgt_s->pll == ACPU_PLL_3) { + scpll_apps_enable(1); + config_pll(tgt_s); + } else if (strt_s->pll == ACPU_PLL_3 && tgt_s->pll != ACPU_PLL_3) { + config_pll(tgt_s); + scpll_apps_enable(0); + } else { + config_switching_pll(); + config_pll(tgt_s); + } + + /* Update the driver state with the new clock freq */ + drv_state.current_speed = tgt_s; + + /* Re-adjust lpj for the new clock speed. */ + loops_per_jiffy = tgt_s->lpj; + + /* Nothing else to do for power collapse or SWFI. */ + if (reason != SETRATE_CPUFREQ) + return 0; + + /* Drop VDD level if we can. */ + if (tgt_s->vdd < strt_s->vdd) { + rc = acpuclk_set_vdd_level(tgt_s->vdd); + if (rc) + printk(KERN_ERR + "acpuclock: Unable to drop ACPU vdd.\n"); + } +out: + if (reason == SETRATE_CPUFREQ) + mutex_unlock(&drv_state.lock); + + return rc; +} + +static void __init acpuclk_init(void) +{ + struct clkctl_acpu_speed *speed; + uint32_t div, sel, regval; + + /* Determine the source of the Scorpion clock. */ + regval = readl(SPSS_CLK_SEL_ADDR); + switch ((regval & 0x6) >> 1) { + case 0: /* raw source clock */ + case 3: /* low jitter PLL1 (768Mhz) */ + if (regval & 0x1) { + sel = ((readl(SPSS_CLK_CNTL_ADDR) >> 4) & 0x7); + div = ((readl(SPSS_CLK_CNTL_ADDR) >> 0) & 0xf); + } else { + sel = ((readl(SPSS_CLK_CNTL_ADDR) >> 12) & 0x7); + div = ((readl(SPSS_CLK_CNTL_ADDR) >> 8) & 0xf); + } + + /* Find the matching clock rate. */ + for (speed = acpu_freq_tbl; speed->a11clk_khz != 0; speed++) { + if (speed->a11clk_src_sel == sel && + speed->a11clk_src_div == div) + break; + } + break; + + case 1: /* unbuffered scorpion pll (384Mhz to 998.4Mhz) */ + sel = ((readl(SCPLL_FSM_CTL_EXT_ADDR) >> 3) & 0x3f); + + /* Find the matching clock rate. */ + for (speed = acpu_freq_tbl; speed->a11clk_khz != 0; speed++) { + if (speed->sc_l_value == sel && + speed->sc_core_src_sel_mask == 1) + break; + } + break; + + case 2: /* AXI bus clock (128Mhz) */ + default: + speed = &acpu_freq_tbl[4]; + } + + /* Initialize scpll only if it wasn't already initialized by the boot + * loader. If the CPU is already running on scpll, then the scpll was + * initialized by the boot loader. */ + if (speed->pll != ACPU_PLL_3) + scpll_init(); + + if (speed->a11clk_khz == 0) { + printk(KERN_WARNING "Warning - ACPU clock reports invalid " + "speed\n"); + return; + } + + drv_state.current_speed = speed; + + printk(KERN_INFO "ACPU running at %d KHz\n", speed->a11clk_khz); +} + +unsigned long acpuclk_get_rate(void) +{ + return drv_state.current_speed->a11clk_khz; +} + +uint32_t acpuclk_get_switch_time(void) +{ + return drv_state.acpu_switch_time_us; +} + +unsigned long acpuclk_power_collapse(void) +{ + int ret = acpuclk_get_rate(); + acpuclk_set_rate(drv_state.power_collapse_khz, SETRATE_PC); + return ret * 1000; +} + +unsigned long acpuclk_wait_for_irq(void) +{ + int ret = acpuclk_get_rate(); + acpuclk_set_rate(drv_state.wait_for_irq_khz, SETRATE_SWFI); + return ret * 1000; +} + +/* Spare register populated with efuse data on max ACPU freq. */ +#define CT_CSR_PHYS 0xA8700000 +#define TCSR_SPARE2_ADDR (ct_csr_base + 0x60) + +static void __init acpu_freq_tbl_fixup(void) +{ + void __iomem *ct_csr_base; + uint32_t tcsr_spare2; + unsigned int max_acpu_khz; + unsigned int i; + + ct_csr_base = ioremap(CT_CSR_PHYS, PAGE_SIZE); + BUG_ON(ct_csr_base == NULL); + + tcsr_spare2 = readl(TCSR_SPARE2_ADDR); + + /* Check if the register is supported and meaningful. */ + if ((tcsr_spare2 & 0xFF00) != 0xA500) { + pr_info("Efuse data on Max ACPU freq not present.\n"); + goto skip_efuse_fixup; + } + + switch (tcsr_spare2 & 0xF0) { + case 0x30: + max_acpu_khz = 768000; + break; + case 0x20: + case 0x00: + max_acpu_khz = 998400; + break; + case 0x10: + max_acpu_khz = 1267200; + break; + default: + pr_warning("Invalid efuse data (%x) on Max ACPU freq!\n", + tcsr_spare2); + goto skip_efuse_fixup; + } + + pr_info("Max ACPU freq from efuse data is %d KHz\n", max_acpu_khz); + + for (i = 0; acpu_freq_tbl[i].a11clk_khz != 0; i++) { + if (acpu_freq_tbl[i].a11clk_khz > max_acpu_khz) { + acpu_freq_tbl[i].a11clk_khz = 0; + break; + } + } + +skip_efuse_fixup: + iounmap(ct_csr_base); + BUG_ON(drv_state.max_vdd == 0); + for (i = 0; acpu_freq_tbl[i].a11clk_khz != 0; i++) { + if (acpu_freq_tbl[i].vdd > drv_state.max_vdd) { + acpu_freq_tbl[i].a11clk_khz = 0; + break; + } + } +} + +/* Initalize the lpj field in the acpu_freq_tbl. */ +static void __init lpj_init(void) +{ + int i; + const struct clkctl_acpu_speed *base_clk = drv_state.current_speed; + for (i = 0; acpu_freq_tbl[i].a11clk_khz; i++) { + acpu_freq_tbl[i].lpj = cpufreq_scale(loops_per_jiffy, + base_clk->a11clk_khz, + acpu_freq_tbl[i].a11clk_khz); + } +} + +void __init msm_acpu_clock_init(struct msm_acpu_clock_platform_data *clkdata) +{ + mutex_init(&drv_state.lock); + + drv_state.acpu_switch_time_us = clkdata->acpu_switch_time_us; + drv_state.max_speed_delta_khz = clkdata->max_speed_delta_khz; + drv_state.vdd_switch_time_us = clkdata->vdd_switch_time_us; + drv_state.power_collapse_khz = clkdata->power_collapse_khz; + drv_state.wait_for_irq_khz = clkdata->wait_for_irq_khz; + drv_state.max_vdd = clkdata->max_vdd; + drv_state.acpu_set_vdd = clkdata->acpu_set_vdd; + + acpu_freq_tbl_fixup(); + acpuclk_init(); + lpj_init(); +#ifdef CONFIG_CPU_FREQ_MSM + cpufreq_table_init(); + cpufreq_frequency_table_get_attr(freq_table, smp_processor_id()); +#endif + +} diff --git a/arch/arm/mach-msm/acpuclock.c b/arch/arm/mach-msm/acpuclock.c index 7a413e3ef308..8e19d8531ae9 100644 --- a/arch/arm/mach-msm/acpuclock.c +++ b/arch/arm/mach-msm/acpuclock.c @@ -3,7 +3,7 @@ * MSM architecture clock driver * * Copyright (C) 2007 Google, Inc. - * Copyright (c) 2007 QUALCOMM Incorporated + * Copyright (c) 2007-2009, Code Aurora Forum. All rights reserved. * Author: San Mehat * * This software is licensed under the terms of the GNU General Public @@ -27,11 +27,17 @@ #include #include #include +#include +#include #include #include +#include #include "proc_comm.h" +#include "smd_private.h" +#include "clock.h" #include "acpuclock.h" +#include "socinfo.h" #define PERF_SWITCH_DEBUG 0 #define PERF_SWITCH_STEP_DEBUG 0 @@ -45,27 +51,36 @@ struct clock_state uint32_t vdd_switch_time_us; unsigned long power_collapse_khz; unsigned long wait_for_irq_khz; + unsigned int max_axi_khz; }; -static struct clk *ebi1_clk; +#define PLL_BASE 7 + +struct shared_pll_control { + uint32_t version; + struct { + /* Denotes if the PLL is ON. Technically, this can be read + * directly from the PLL registers, but this feild is here, + * so let's use it. + */ + uint32_t on; + /* One bit for each processor core. The application processor + * is allocated bit position 1. All other bits should be + * considered as votes from other processors. + */ + uint32_t votes; + } pll[PLL_BASE + ACPU_PLL_END]; +}; + +static remote_spinlock_t pll_lock; +static struct shared_pll_control *pll_control; + static struct clock_state drv_state = { 0 }; static void __init acpuclk_init(void); -/* MSM7201A Levels 3-6 all correspond to 1.2V, level 7 corresponds to 1.325V. */ -enum { - VDD_0 = 0, - VDD_1 = 1, - VDD_2 = 2, - VDD_3 = 3, - VDD_4 = 3, - VDD_5 = 3, - VDD_6 = 3, - VDD_7 = 7, - VDD_END -}; - struct clkctl_acpu_speed { + unsigned int use_for_scaling; unsigned int a11clk_khz; int pll; unsigned int a11clk_src_sel; @@ -84,56 +99,83 @@ struct clkctl_acpu_speed { * ACPU speed table. Complete table is shown but certain speeds are commented * out to optimized speed switching. Initalize loops_per_jiffy to 0. * - * Table stepping up/down is optimized for 256mhz jumps while staying on the - * same PLL. + * Table stepping up/down is calculated during boot to choose the largest + * frequency jump that's less than max_speed_delta_khz and preferrably on the + * same PLL. If no frequencies using the same PLL are within + * max_speed_delta_khz, then the farthest frequency that is within + * max_speed_delta_khz is chosen. + * + * The table is initialized with the most common clock plan. Table fix up is + * done during boot up to match the actual clock plan supported by the + * hardware. */ -#if (0) +#if (1) static struct clkctl_acpu_speed acpu_freq_tbl[] = { - { 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, VDD_0, 30720, 0, 0, 8 }, - { 61440, ACPU_PLL_0, 4, 3, 61440, 0, VDD_0, 30720, 0, 0, 8 }, - { 81920, ACPU_PLL_0, 4, 2, 40960, 1, VDD_0, 61440, 0, 0, 8 }, - { 96000, ACPU_PLL_1, 1, 7, 48000, 1, VDD_0, 61440, 0, 0, 9 }, - { 122880, ACPU_PLL_0, 4, 1, 61440, 1, VDD_3, 61440, 0, 0, 8 }, - { 128000, ACPU_PLL_1, 1, 5, 64000, 1, VDD_3, 61440, 0, 0, 12 }, - { 176000, ACPU_PLL_2, 2, 5, 88000, 1, VDD_3, 61440, 0, 0, 11 }, - { 192000, ACPU_PLL_1, 1, 3, 64000, 2, VDD_3, 61440, 0, 0, 12 }, - { 245760, ACPU_PLL_0, 4, 0, 81920, 2, VDD_4, 61440, 0, 0, 12 }, - { 256000, ACPU_PLL_1, 1, 2, 128000, 2, VDD_5, 128000, 0, 0, 12 }, - { 264000, ACPU_PLL_2, 2, 3, 88000, 2, VDD_5, 128000, 0, 6, 13 }, - { 352000, ACPU_PLL_2, 2, 2, 88000, 3, VDD_5, 128000, 0, 6, 13 }, - { 384000, ACPU_PLL_1, 1, 1, 128000, 2, VDD_6, 128000, 0, 5, -1 }, - { 528000, ACPU_PLL_2, 2, 1, 132000, 3, VDD_7, 128000, 0, 11, -1 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 0, 30720, 0, 0, 8 }, + { 0, 61440, ACPU_PLL_0, 4, 3, 61440, 0, 0, 30720, 0, 0, 8 }, + { 0, 81920, ACPU_PLL_0, 4, 2, 40960, 1, 0, 61440, 0, 0, 8 }, + { 0, 96000, ACPU_PLL_1, 1, 7, 48000, 1, 0, 61440, 0, 0, 9 }, + { 1, 122880, ACPU_PLL_0, 4, 1, 61440, 1, 3, 61440, 0, 0, 8 }, + { 0, 128000, ACPU_PLL_1, 1, 5, 64000, 1, 3, 61440, 0, 0, 12 }, + { 0, 176000, ACPU_PLL_2, 2, 5, 88000, 1, 3, 61440, 0, 0, 11 }, + { 0, 192000, ACPU_PLL_1, 1, 3, 64000, 2, 3, 61440, 0, 0, 12 }, + { 1, 245760, ACPU_PLL_0, 4, 0, 81920, 2, 4, 61440, 0, 0, 12 }, + { 1, 256000, ACPU_PLL_1, 1, 2, 128000, 1, 5, 128000, 0, 0, 12 }, + { 0, 264000, ACPU_PLL_2, 2, 3, 88000, 2, 5, 128000, 0, 6, 13 }, + { 0, 352000, ACPU_PLL_2, 2, 2, 88000, 3, 5, 128000, 0, 6, 13 }, + { 1, 384000, ACPU_PLL_1, 1, 1, 128000, 2, 6, 128000, 0, 5, -1 }, + { 1, 528000, ACPU_PLL_2, 2, 1, 132000, 3, 7, 128000, 0, 11, -1 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, }; #else /* Table of freq we currently use. */ static struct clkctl_acpu_speed acpu_freq_tbl[] = { - { 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, VDD_0, 30720, 0, 0, 4 }, - { 122880, ACPU_PLL_0, 4, 1, 61440, 1, VDD_3, 61440, 0, 0, 4 }, - { 128000, ACPU_PLL_1, 1, 5, 64000, 1, VDD_3, 61440, 0, 0, 6 }, - { 176000, ACPU_PLL_2, 2, 5, 88000, 1, VDD_3, 61440, 0, 0, 5 }, - { 245760, ACPU_PLL_0, 4, 0, 81920, 2, VDD_4, 61440, 0, 0, 5 }, - { 352000, ACPU_PLL_2, 2, 2, 88000, 3, VDD_5, 128000, 0, 3, 7 }, - { 384000, ACPU_PLL_1, 1, 1, 128000, 2, VDD_6, 128000, 0, 2, -1 }, - { 528000, ACPU_PLL_2, 2, 1, 132000, 3, VDD_7, 128000, 0, 5, -1 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 0, 30720, 0, 0, 4 }, + { 1, 122880, ACPU_PLL_0, 4, 1, 61440, 1, 3, 61440, 0, 0, 4 }, + { 1, 128000, ACPU_PLL_1, 1, 5, 64000, 1, 3, 61440, 0, 0, 6 }, + { 0, 176000, ACPU_PLL_2, 2, 5, 88000, 1, 3, 61440, 0, 0, 5 }, + { 1, 245760, ACPU_PLL_0, 4, 0, 81920, 2, 4, 61440, 0, 0, 5 }, + { 0, 352000, ACPU_PLL_2, 2, 2, 88000, 3, 5, 128000, 0, 3, 7 }, + { 1, 384000, ACPU_PLL_1, 1, 1, 128000, 2, 6, 128000, 0, 2, -1 }, + { 1, 528000, ACPU_PLL_2, 2, 1, 132000, 3, 7, 128000, 0, 5, -1 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, }; #endif -#ifdef CONFIG_MSM_CPU_FREQ_ONDEMAND -static struct cpufreq_frequency_table freq_table[] = { - { 0, 19200 }, - { 1, 122880 }, - { 2, 128000 }, - { 3, 245760 }, - { 4, 384000 }, - { 5, 528000 }, - { 6, CPUFREQ_TABLE_END }, -}; +#ifdef CONFIG_CPU_FREQ_MSM +static struct cpufreq_frequency_table freq_table[20]; + +static void __init cpufreq_table_init(void) +{ + unsigned int i; + unsigned int freq_cnt = 0; + + /* Construct the freq_table table from acpu_freq_tbl since the + * freq_table values need to match frequencies specified in + * acpu_freq_tbl and acpu_freq_tbl needs to be fixed up during init. + */ + for (i = 0; acpu_freq_tbl[i].a11clk_khz != 0 + && freq_cnt < ARRAY_SIZE(freq_table)-1; i++) { + if (acpu_freq_tbl[i].use_for_scaling) { + freq_table[freq_cnt].index = freq_cnt; + freq_table[freq_cnt].frequency + = acpu_freq_tbl[i].a11clk_khz; + freq_cnt++; + } + } + + /* freq_table not big enough to store all usable freqs. */ + BUG_ON(acpu_freq_tbl[i].a11clk_khz != 0); + + freq_table[freq_cnt].index = freq_cnt; + freq_table[freq_cnt].frequency = CPUFREQ_TABLE_END; + + pr_info("%d scaling frequencies supported.\n", freq_cnt); +} #endif static int pc_pll_request(unsigned id, unsigned on) { - int res; + int res = 0; on = !!on; #if PERF_SWITCH_DEBUG @@ -143,9 +185,35 @@ static int pc_pll_request(unsigned id, unsigned on) printk(KERN_DEBUG "Disabling PLL %d\n", id); #endif - res = msm_proc_comm(PCOM_CLKCTL_RPC_PLL_REQUEST, &id, &on); - if (res < 0) - return res; + if (id >= ACPU_PLL_END) + return -EINVAL; + + if (pll_control) { + remote_spin_lock(&pll_lock); + if (on) { + pll_control->pll[PLL_BASE + id].votes |= 2; + if (!pll_control->pll[PLL_BASE + id].on) { + writel(6, PLLn_MODE(id)); + udelay(50); + writel(7, PLLn_MODE(id)); + pll_control->pll[PLL_BASE + id].on = 1; + } + } else { + pll_control->pll[PLL_BASE + id].votes &= ~2; + if (pll_control->pll[PLL_BASE + id].on + && !pll_control->pll[PLL_BASE + id].votes) { + writel(0, PLLn_MODE(id)); + pll_control->pll[PLL_BASE + id].on = 0; + } + } + remote_spin_unlock(&pll_lock); + } else { + res = msm_proc_comm(PCOM_CLKCTL_RPC_PLL_REQUEST, &id, &on); + if (res < 0) + return res; + else if ((int) id < 0) + return -EINVAL; + } #if PERF_SWITCH_DEBUG if (on) @@ -163,13 +231,13 @@ static int pc_pll_request(unsigned id, unsigned on) unsigned long acpuclk_power_collapse(void) { int ret = acpuclk_get_rate(); - acpuclk_set_rate(drv_state.power_collapse_khz, 1); + acpuclk_set_rate(drv_state.power_collapse_khz, SETRATE_PC); return ret * 1000; } unsigned long acpuclk_wait_for_irq(void) { int ret = acpuclk_get_rate(); - acpuclk_set_rate(drv_state.wait_for_irq_khz, 1); + acpuclk_set_rate(drv_state.wait_for_irq_khz, SETRATE_SWFI); return ret * 1000; } @@ -200,73 +268,48 @@ static int acpuclk_set_vdd_level(int vdd) /* Set proper dividers for the given clock speed. */ static void acpuclk_set_div(const struct clkctl_acpu_speed *hunt_s) { - uint32_t reg_clkctl, reg_clksel, clk_div; + uint32_t reg_clkctl, reg_clksel, clk_div, src_sel; + + reg_clksel = readl(A11S_CLK_SEL_ADDR); /* AHB_CLK_DIV */ - clk_div = (readl(A11S_CLK_SEL_ADDR) >> 1) & 0x03; + clk_div = (reg_clksel >> 1) & 0x03; + /* CLK_SEL_SRC1NO */ + src_sel = reg_clksel & 1; + /* * If the new clock divider is higher than the previous, then * program the divider before switching the clock */ if (hunt_s->ahbclk_div > clk_div) { - reg_clksel = readl(A11S_CLK_SEL_ADDR); reg_clksel &= ~(0x3 << 1); reg_clksel |= (hunt_s->ahbclk_div << 1); writel(reg_clksel, A11S_CLK_SEL_ADDR); } - if ((readl(A11S_CLK_SEL_ADDR) & 0x01) == 0) { - /* SRC0 */ - - /* Program clock source */ - reg_clkctl = readl(A11S_CLK_CNTL_ADDR); - reg_clkctl &= ~(0x07 << 4); - reg_clkctl |= (hunt_s->a11clk_src_sel << 4); - writel(reg_clkctl, A11S_CLK_CNTL_ADDR); - - /* Program clock divider */ - reg_clkctl = readl(A11S_CLK_CNTL_ADDR); - reg_clkctl &= ~0xf; - reg_clkctl |= hunt_s->a11clk_src_div; - writel(reg_clkctl, A11S_CLK_CNTL_ADDR); - - /* Program clock source selection */ - reg_clksel = readl(A11S_CLK_SEL_ADDR); - reg_clksel |= 1; /* CLK_SEL_SRC1NO == SRC1 */ - writel(reg_clksel, A11S_CLK_SEL_ADDR); - } else { - /* SRC1 */ - - /* Program clock source */ - reg_clkctl = readl(A11S_CLK_CNTL_ADDR); - reg_clkctl &= ~(0x07 << 12); - reg_clkctl |= (hunt_s->a11clk_src_sel << 12); - writel(reg_clkctl, A11S_CLK_CNTL_ADDR); - - /* Program clock divider */ - reg_clkctl = readl(A11S_CLK_CNTL_ADDR); - reg_clkctl &= ~(0xf << 8); - reg_clkctl |= (hunt_s->a11clk_src_div << 8); - writel(reg_clkctl, A11S_CLK_CNTL_ADDR); - - /* Program clock source selection */ - reg_clksel = readl(A11S_CLK_SEL_ADDR); - reg_clksel &= ~1; /* CLK_SEL_SRC1NO == SRC0 */ - writel(reg_clksel, A11S_CLK_SEL_ADDR); - } + + /* Program clock source and divider */ + reg_clkctl = readl(A11S_CLK_CNTL_ADDR); + reg_clkctl &= ~(0xFF << (8 * src_sel)); + reg_clkctl |= hunt_s->a11clk_src_sel << (4 + 8 * src_sel); + reg_clkctl |= hunt_s->a11clk_src_div << (0 + 8 * src_sel); + writel(reg_clkctl, A11S_CLK_CNTL_ADDR); + + /* Program clock source selection */ + reg_clksel ^= 1; + writel(reg_clksel, A11S_CLK_SEL_ADDR); /* * If the new clock divider is lower than the previous, then * program the divider after switching the clock */ if (hunt_s->ahbclk_div < clk_div) { - reg_clksel = readl(A11S_CLK_SEL_ADDR); reg_clksel &= ~(0x3 << 1); reg_clksel |= (hunt_s->ahbclk_div << 1); writel(reg_clksel, A11S_CLK_SEL_ADDR); } } -int acpuclk_set_rate(unsigned long rate, int for_power_collapse) +int acpuclk_set_rate(unsigned long rate, enum setrate_reason reason) { uint32_t reg_clkctl; struct clkctl_acpu_speed *cur_s, *tgt_s, *strt_s; @@ -290,8 +333,9 @@ int acpuclk_set_rate(unsigned long rate, int for_power_collapse) if (tgt_s->a11clk_khz == 0) return -EINVAL; - /* Choose the highest speed speed at or below 'rate' with same PLL. */ - if (for_power_collapse && tgt_s->a11clk_khz < cur_s->a11clk_khz) { + /* Choose the highest speed at or below 'rate' with same PLL. */ + if (reason != SETRATE_CPUFREQ + && tgt_s->a11clk_khz < cur_s->a11clk_khz) { while (tgt_s->pll != ACPU_PLL_TCXO && tgt_s->pll != cur_s->pll) tgt_s--; } @@ -299,7 +343,7 @@ int acpuclk_set_rate(unsigned long rate, int for_power_collapse) if (strt_s->pll != ACPU_PLL_TCXO) plls_enabled |= 1 << strt_s->pll; - if (!for_power_collapse) { + if (reason == SETRATE_CPUFREQ) { mutex_lock(&drv_state.lock); if (strt_s->pll != tgt_s->pll && tgt_s->pll != ACPU_PLL_TCXO) { rc = pc_pll_request(tgt_s->pll, 1); @@ -354,7 +398,7 @@ int acpuclk_set_rate(unsigned long rate, int for_power_collapse) printk(KERN_DEBUG "%s: STEP khz = %u, pll = %d\n", __FUNCTION__, cur_s->a11clk_khz, cur_s->pll); #endif - if (!for_power_collapse&& cur_s->pll != ACPU_PLL_TCXO + if (cur_s->pll != ACPU_PLL_TCXO && !(plls_enabled & (1 << cur_s->pll))) { rc = pc_pll_request(cur_s->pll, 1); if (rc < 0) { @@ -372,8 +416,19 @@ int acpuclk_set_rate(unsigned long rate, int for_power_collapse) udelay(drv_state.acpu_switch_time_us); } + /* Nothing else to do for SWFI. */ + if (reason == SETRATE_SWFI) + return 0; + + /* Change the AXI bus frequency if we can. */ + if (strt_s->axiclk_khz != tgt_s->axiclk_khz) { + rc = pc_clk_set_min_rate(EBI1_CLK, tgt_s->axiclk_khz * 1000); + if (rc < 0) + pr_err("Setting AXI min rate failed!\n"); + } + /* Nothing else to do for power collapse. */ - if (for_power_collapse) + if (reason == SETRATE_PC) return 0; /* Disable PLLs we are not using anymore. */ @@ -387,13 +442,6 @@ int acpuclk_set_rate(unsigned long rate, int for_power_collapse) } } - /* Change the AXI bus frequency if we can. */ - if (strt_s->axiclk_khz != tgt_s->axiclk_khz) { - rc = clk_set_rate(ebi1_clk, tgt_s->axiclk_khz * 1000); - if (rc < 0) - pr_err("Setting AXI min rate failed!\n"); - } - /* Drop VDD level if we can. */ if (tgt_s->vdd < strt_s->vdd) { if (acpuclk_set_vdd_level(tgt_s->vdd) < 0) @@ -404,7 +452,7 @@ int acpuclk_set_rate(unsigned long rate, int for_power_collapse) printk(KERN_DEBUG "%s: ACPU speed change complete\n", __FUNCTION__); #endif out: - if (!for_power_collapse) + if (reason == SETRATE_CPUFREQ) mutex_unlock(&drv_state.lock); return rc; } @@ -443,7 +491,7 @@ static void __init acpuclk_init(void) drv_state.current_speed = speed; - rc = clk_set_rate(ebi1_clk, speed->axiclk_khz * 1000); + rc = pc_clk_set_min_rate(EBI1_CLK, speed->axiclk_khz * 1000); if (rc < 0) pr_err("Setting AXI min rate failed!\n"); @@ -469,6 +517,244 @@ uint32_t acpuclk_get_switch_time(void) * Clock driver initialization *---------------------------------------------------------------------------*/ +static int __init cmp_acpu_speed(const void *a, const void *b) +{ + return ((struct clkctl_acpu_speed *)a)->a11clk_khz + - ((struct clkctl_acpu_speed *)b)->a11clk_khz; +} + +#define DIV2REG(n) ((n)-1) +#define REG2DIV(n) ((n)+1) +#define SLOWER_BY(div, factor) div = DIV2REG(REG2DIV(div) * factor) + +static void __init pll0_a11_ahb_fixup(unsigned long pll0_l, + struct clkctl_acpu_speed *t) +{ +#define PLL0_196608_KHZ 10 +#define PLL0_245760_KHZ 12 +#define PLL0_491520_KHZ 25 +#define PLL0_983000_KHZ 51 + + switch (pll0_l) { + case PLL0_983000_KHZ: + SLOWER_BY(t->a11clk_src_div, 4); + break; + case PLL0_491520_KHZ: + SLOWER_BY(t->a11clk_src_div, 2); + break; + case PLL0_245760_KHZ: + /* Initialization correct except for 7x27. */ + if (cpu_is_msm7x27() && t->a11clk_khz == 245760) { + t->ahbclk_div--; + t->ahbclk_khz = 122880; + } + break; + case PLL0_196608_KHZ: + t->a11clk_khz = 196608 / REG2DIV(t->a11clk_src_div); + switch (REG2DIV(t->a11clk_src_div)) { + case 4: /* 49.152 MHz */ + t->ahbclk_khz = t->a11clk_khz; + break; + case 3: /* 65.536 MHz */ + t->ahbclk_khz = t->a11clk_khz; + t->ahbclk_div = DIV2REG(1); + break; + case 2: /* 98.304 MHz */ + /* TODO: Increase AHB freq for sRoc + * and Roc 2.0 */ + t->ahbclk_khz = t->a11clk_khz >> 1; + break; + case 1: /* 196.608 MHz */ + /* TODO: Increase AHB freq for sRoc + * and Roc 2.0 */ + t->ahbclk_khz = t->a11clk_khz / 3; + break; + } + break; + default: + printk(KERN_CRIT "Unknown PLL0 speed.\n"); + BUG(); + break; + } +} + +static void __init pll1_a11_ahb_fixup(unsigned long pll1_l, + struct clkctl_acpu_speed *t) +{ +#define PLL1_768000_KHZ 40 +#define PLL1_960000_KHZ 50 + + switch (pll1_l) { + case PLL1_960000_KHZ: + t->a11clk_khz = 960000 / REG2DIV(t->a11clk_src_div); + /* XXX: Necessary for AHB freq of 128 MHz, but not + * necessary for lower AHB freqs. All ACPU freqs used + * for scaling have AHB of 128 MHz, so unconditional + * increment might be okay. + * + * 7x27 is an exception because running AHB at 160 MHz + * is meaningful (because it can run AXI at 160 MHz at + * lower CPU frequencies without impacting power + * consumption). + */ + if (!cpu_is_msm7x27()) + t->ahbclk_div++; + t->ahbclk_khz = t->a11clk_khz / REG2DIV(t->ahbclk_div); + break; + case PLL1_768000_KHZ: + /* Initialization correct. */ + break; + default: + printk(KERN_CRIT "Unknown PLL1 speed.\n"); + BUG(); + break; + } +} + +static void __init pll2_a11_ahb_fixup(unsigned long pll2_l, + struct clkctl_acpu_speed *t) +{ +#define PLL2_960000_KHZ 50 +#define PLL2_1056000_KHZ 55 +#define PLL2_1200000_KHZ 62 + + switch (pll2_l) { + case PLL2_1200000_KHZ: + t->a11clk_khz = 1200000 / REG2DIV(t->a11clk_src_div); + if (t->ahbclk_div > 2) + t->ahbclk_div--; + t->ahbclk_khz = t->a11clk_khz / REG2DIV(t->ahbclk_div); + break; + case PLL2_1056000_KHZ: + /* Initialization correct. */ + break; + case PLL2_960000_KHZ: + t->a11clk_khz = 960000 / REG2DIV(t->a11clk_src_div); + if (t->ahbclk_div > 1) + t->ahbclk_div--; + t->ahbclk_khz = t->a11clk_khz / REG2DIV(t->ahbclk_div); + break; + default: + printk(KERN_CRIT "Unknown PLL2 speed.\n"); + BUG(); + break; + } +} + +static void __init acpu_freq_tbl_fixup(void) +{ + unsigned long pll0_l, pll1_l, pll2_l; + int axi_160mhz = 0, axi_200mhz = 0; + struct clkctl_acpu_speed *t; + unsigned int n = 0; + + /* Wait for the PLLs to be initialized and then read their frequency. + */ + do { + pll0_l = readl(PLLn_L_VAL(0)) & 0x3f; + cpu_relax(); + udelay(50); + } while (pll0_l == 0); + do { + pll1_l = readl(PLLn_L_VAL(1)) & 0x3f; + cpu_relax(); + udelay(50); + } while (pll1_l == 0); + do { + pll2_l = readl(PLLn_L_VAL(2)) & 0x3f; + cpu_relax(); + udelay(50); + } while (pll2_l == 0); + + printk(KERN_INFO "L val: PLL0: %d, PLL1: %d, PLL2: %d\n", + (int)pll0_l, (int)pll1_l, (int)pll2_l); + + /* No fix up needed. */ + if (pll0_l == PLL0_245760_KHZ && pll1_l == PLL1_768000_KHZ + && pll2_l == PLL2_1056000_KHZ) + goto print_info; + + /* The AXI bus frequency is also based off the PLL frequencies. For + * the AXI bus to be able to run at 160 MHz or 200 MHz, it needs a + * PLL that runs at an integer multiple of that frequency. + */ + axi_160mhz = (pll1_l == PLL1_960000_KHZ || pll2_l == PLL2_960000_KHZ); + axi_200mhz = (pll2_l == PLL2_1200000_KHZ); + + /* Fix the dividers and the allowed clock rates based on the PLL + * frequencies. + * + * The CPU freq is based off the PLL frequencies. So if the actual + * PLL freq is different from the PLL freq assumed in the default + * table, then the dividers are adjusted to run the CPU at + * frequencies closer to the ones in the default table. + * + * The AHB freq is based off the CPU freq. Attempt is made to + * generally keep the AHB freq as close as possible to the AXI bus + * freq. But for each VDD level there is an upper limit for the AHB + * bus freq. Apart from the per VDD upper limit the AHB also has an + * absolute upper limit of 160 MHz. In most cases, these limitations + * would explain why the AHB divider is changed when a PLL freq + * changes. + */ + for (t = &acpu_freq_tbl[0]; t->a11clk_khz != 0; t++) { + n++; + + switch (t->pll) { + case ACPU_PLL_0: + pll0_a11_ahb_fixup(pll0_l, t); + break; + case ACPU_PLL_1: + pll1_a11_ahb_fixup(pll1_l, t); + break; + case ACPU_PLL_2: + pll2_a11_ahb_fixup(pll2_l, t); + break; + } + + if (pll0_l == PLL0_196608_KHZ && t->a11clk_khz <= 196608) + t->axiclk_khz = 24576; + + if (cpu_is_msm7x27() && t->a11clk_khz == 245760) + t->axiclk_khz = 122880; + + if (axi_160mhz && drv_state.max_axi_khz >= 160000 + && t->ahbclk_khz > 128000) + t->axiclk_khz = 160000; + if (axi_200mhz && drv_state.max_axi_khz >= 200000 + && t->ahbclk_khz > 160000) + t->axiclk_khz = 200000; + + /* 128 MHz is derived from PLL1 @ 768 MHz. If PLL1 @ 960 MHz + * then only 120 MHz can be derived from it. */ + if (pll1_l == PLL1_960000_KHZ && t->axiclk_khz == 128000) + t->axiclk_khz = 120000; + } + + /* The ACPU table is expected to be in ascending order by the rest + * of the code. This is the case after most fix ups. One example + * exception is when PLL1 runs at 960 MHz. In this case the entries + * corresponding to (256 and 264) need to be swapped. + */ + sort(acpu_freq_tbl, n, sizeof(struct clkctl_acpu_speed), + cmp_acpu_speed, NULL); + +print_info: + /* The default 7x27 ACPU clock plan supports running the AXI bus at + * 200 MHz. So we don't classify it as Turbo mode. + */ + if (cpu_is_msm7x27()) + return; + + t = acpu_freq_tbl + n - 1; + if (!axi_160mhz) + pr_info("Turbo mode not supported.\n"); + else if (t->axiclk_khz == 160000) + pr_info("Turbo mode supported and enabled.\n"); + else + pr_info("Turbo mode supported but not enabled.\n"); +} + /* Initalize the lpj field in the acpu_freq_tbl. */ static void __init lpj_init(void) { @@ -481,21 +767,144 @@ static void __init lpj_init(void) } } +static void __init precompute_stepping(void) +{ + int i, step_idx, step_same_pll_idx; + +#define cur_freq acpu_freq_tbl[i].a11clk_khz +#define step_freq acpu_freq_tbl[step_idx].a11clk_khz +#define cur_pll acpu_freq_tbl[i].pll +#define step_pll acpu_freq_tbl[step_idx].pll + + for (i = 0; acpu_freq_tbl[i].a11clk_khz; i++) { + + /* Calculate "Up" step. */ + step_idx = i + 1; + step_same_pll_idx = -1; + while (step_freq && (step_freq - cur_freq) + <= drv_state.max_speed_delta_khz) { + if (step_pll == cur_pll) + step_same_pll_idx = step_idx; + step_idx++; + } + + /* Highest freq within max_speed_delta_khz. No step needed. */ + if (step_freq == 0) + acpu_freq_tbl[i].up = -1; + else if (step_idx == (i + 1)) { + pr_crit("Delta between freqs %u KHz and %u KHz is" + " too high!\n", cur_freq, step_freq); + BUG(); + } else { + /* There is only one TCXO freq. So don't complain. */ + if (cur_pll == ACPU_PLL_TCXO) + step_same_pll_idx = step_idx - 1; + if (step_same_pll_idx == -1) { + pr_warning("Suboptimal up stepping for CPU " + "freq %u KHz.\n", cur_freq); + acpu_freq_tbl[i].up = step_idx - 1; + } else + acpu_freq_tbl[i].up = step_same_pll_idx; + } + + /* Calculate "Down" step. */ + step_idx = i - 1; + step_same_pll_idx = -1; + while (step_idx >= 0 && (cur_freq - step_freq) + <= drv_state.max_speed_delta_khz) { + if (step_pll == cur_pll) + step_same_pll_idx = step_idx; + step_idx--; + } + + /* Lowest freq within max_speed_delta_khz. No step needed. */ + if (step_idx == -1) + acpu_freq_tbl[i].down = -1; + else if (step_idx == (i - 1)) { + pr_crit("Delta between freqs %u KHz and %u KHz is" + " too high!\n", cur_freq, step_freq); + BUG(); + } else { + if (step_same_pll_idx == -1) { + pr_warning("Suboptimal down stepping for CPU " + "freq %u KHz.\n", cur_freq); + acpu_freq_tbl[i].down = step_idx + 1; + } else + acpu_freq_tbl[i].down = step_same_pll_idx; + } + } +} + +static void __init print_acpu_freq_tbl(void) +{ + struct clkctl_acpu_speed *t; + pr_info("CPU-Freq PLL DIV AHB-Freq ADIV AXI-Freq Dn Up\n"); + for (t = &acpu_freq_tbl[0]; t->a11clk_khz != 0; t++) + pr_info("%8d %3d %3d %8d %4d %8d %2d %2d\n", + t->a11clk_khz, t->pll, t->a11clk_src_div + 1, + t->ahbclk_khz, t->ahbclk_div + 1, t->axiclk_khz, + t->down, t->up); +} + +static void msm7x25_acpu_pll_hw_bug_fix(void) +{ + unsigned int n; + + /* The 7625 has a hardware bug and in order to select PLL2 we + * must program PLL3. Use the same table, and just fix up the + * numbers on this target. */ + for (n = 0; acpu_freq_tbl[n].a11clk_khz != 0; n++) + if (acpu_freq_tbl[n].pll == ACPU_PLL_2) + acpu_freq_tbl[n].a11clk_src_sel = 3; +} + +static void shared_pll_control_init(void) +{ +#define PLL_REMOTE_SPINLOCK_ID 7 + unsigned smem_size; + remote_spin_lock_init(&pll_lock, PLL_REMOTE_SPINLOCK_ID); + pll_control = smem_get_entry(SMEM_CLKREGIM_SOURCES, &smem_size); + + if (!pll_control) + pr_err("Unable to find shared PLL control data structure!\n"); + /* There might be more PLLs than what the application processor knows + * about. But the index used for each PLL is guaranteed to remain the + * same. */ + else if (smem_size < sizeof(struct shared_pll_control)) + pr_err("Shared PLL control data structure too small!\n"); + else if (pll_control->version != 0xCCEE0001) + pr_err("Shared PLL control version mismatch!\n"); + else { + pr_info("Shared PLL control available.\n"); + return; + } + + pll_control = NULL; + pr_err("Falling back to proc_comm PLL control.\n"); +} + void __init msm_acpu_clock_init(struct msm_acpu_clock_platform_data *clkdata) { pr_info("acpu_clock_init()\n"); - ebi1_clk = clk_get(NULL, "ebi1_clk"); - mutex_init(&drv_state.lock); drv_state.acpu_switch_time_us = clkdata->acpu_switch_time_us; drv_state.max_speed_delta_khz = clkdata->max_speed_delta_khz; drv_state.vdd_switch_time_us = clkdata->vdd_switch_time_us; drv_state.power_collapse_khz = clkdata->power_collapse_khz; drv_state.wait_for_irq_khz = clkdata->wait_for_irq_khz; + drv_state.max_axi_khz = clkdata->max_axi_khz; + acpu_freq_tbl_fixup(); + precompute_stepping(); acpuclk_init(); lpj_init(); -#ifdef CONFIG_MSM_CPU_FREQ_ONDEMAND + print_acpu_freq_tbl(); + if (cpu_is_msm7x25()) + msm7x25_acpu_pll_hw_bug_fix(); + if (cpu_is_msm7x27()) + shared_pll_control_init(); +#ifdef CONFIG_CPU_FREQ_MSM + cpufreq_table_init(); cpufreq_frequency_table_get_attr(freq_table, smp_processor_id()); #endif } diff --git a/arch/arm/mach-msm/acpuclock.h b/arch/arm/mach-msm/acpuclock.h index 9b2fcff97517..7d419ab46e7d 100644 --- a/arch/arm/mach-msm/acpuclock.h +++ b/arch/arm/mach-msm/acpuclock.h @@ -3,7 +3,7 @@ * MSM architecture clock driver header * * Copyright (C) 2007 Google, Inc. - * Copyright (c) 2007 QUALCOMM Incorporated + * Copyright (c) 2007-2009, Code Aurora Forum. All rights reserved. * Author: San Mehat * * This software is licensed under the terms of the GNU General Public @@ -27,17 +27,29 @@ #define A11S_CLK_SEL_ADDR (MSM_CSR_BASE + 0x104) #define A11S_VDD_SVS_PLEVEL_ADDR (MSM_CSR_BASE + 0x124) +#define PLLn_MODE(n) (MSM_CLK_CTL_BASE + 0x300 + 28 * (n)) +#define PLLn_L_VAL(n) (MSM_CLK_CTL_BASE + 0x304 + 28 * (n)) + /* * ARM11 clock configuration for specific ACPU speeds */ -#define ACPU_PLL_TCXO -1 -#define ACPU_PLL_0 0 -#define ACPU_PLL_1 1 -#define ACPU_PLL_2 2 -#define ACPU_PLL_3 3 - -int acpuclk_set_rate(unsigned long rate, int for_power_collapse); +enum { + ACPU_PLL_TCXO = -1, + ACPU_PLL_0 = 0, + ACPU_PLL_1, + ACPU_PLL_2, + ACPU_PLL_3, + ACPU_PLL_END, +}; + +enum setrate_reason { + SETRATE_CPUFREQ = 0, + SETRATE_SWFI, + SETRATE_PC, +}; + +int acpuclk_set_rate(unsigned long rate, enum setrate_reason reason); unsigned long acpuclk_get_rate(void); uint32_t acpuclk_get_switch_time(void); unsigned long acpuclk_wait_for_irq(void); diff --git a/arch/arm/mach-msm/board-comet.c b/arch/arm/mach-msm/board-comet.c new file mode 100644 index 000000000000..663ed1aba951 --- /dev/null +++ b/arch/arm/mach-msm/board-comet.c @@ -0,0 +1,1018 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "devices.h" +#include "timer.h" +#include "pm.h" + +#define TOUCHPAD_SUSPEND 34 +#define TOUCHPAD_IRQ 42 + +#define MSM_PMEM_MDP_SIZE 0x800000 +#define MSM_FB_SIZE 0x500000 +#define MSM_AUDIO_SIZE 0x200000 + +#define MSM_SMI_BASE 0x2b00000 +#define MSM_SMI_SIZE 0x1500000 + +#define MSM_FB_BASE MSM_SMI_BASE +#define MSM_PMEM_GPU0_BASE (MSM_FB_BASE + MSM_FB_SIZE) +#define MSM_PMEM_GPU0_SIZE (MSM_SMI_SIZE - MSM_FB_SIZE) + +#define COMET_CPLD_START 0x70004000 +#define COMET_CPLD_SIZE 0x00000020 +#define COMET_CPLD_PER_ENABLE 0x00000010 +#define COMET_CPLD_PER_RESET 0x00000018 +#define COMET_CPLD_PER_RESET_BT_RESET 0x00000001 +#define COMET_CPLD_PER_RESET_ALL_RESET 0x000000FF + +static struct resource smc911x_resources[] = { + [0] = { + .start = 0x90000000, + .end = 0x90000100, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = MSM_GPIO_TO_INT(156), + .end = 156, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device smc911x_device = { + .name = "smc911x", + .id = 0, + .num_resources = ARRAY_SIZE(smc911x_resources), + .resource = smc911x_resources, +}; + +static struct usb_mass_storage_platform_data usb_mass_storage_pdata = { + .nluns = 0x02, + .buf_size = 16384, + .vendor = "GOOGLE", + .product = "Mass storage", + .release = 0xffff, +}; + +static struct platform_device mass_storage_device = { + .name = "usb_mass_storage", + .id = -1, + .dev = { + .platform_data = &usb_mass_storage_pdata, + }, +}; + +static struct usb_function_map usb_functions_map[] = { + {"diag", 0}, + {"adb", 1}, + {"modem", 2}, + {"nmea", 3}, + {"mass_storage", 4}, + {"ethernet", 5}, +}; + +/* dynamic composition */ +static struct usb_composition usb_func_composition[] = { + { + .product_id = 0x9012, + .functions = 0x5, /* 0101 */ + }, + + { + .product_id = 0x9013, + .functions = 0x15, /* 10101 */ + }, + + { + .product_id = 0x9014, + .functions = 0x30, /* 110000 */ + }, + + { + .product_id = 0x9016, + .functions = 0xD, /* 01101 */ + }, + + { + .product_id = 0x9017, + .functions = 0x1D, /* 11101 */ + }, + + { + .product_id = 0xF000, + .functions = 0x10, /* 10000 */ + }, + + { + .product_id = 0xF009, + .functions = 0x20, /* 100000 */ + }, + + { + .product_id = 0x9018, + .functions = 0x1F, /* 011111 */ + }, + +}; +static struct msm_hsusb_platform_data msm_hsusb_pdata = { + .version = 0x0100, + .phy_info = (USB_PHY_INTEGRATED | USB_PHY_MODEL_180NM), + .vendor_id = 0x5c6, + .product_name = "Qualcomm HSUSB Device", + .serial_number = "1234567890ABCDEF", + .manufacturer_name = "Qualcomm Incorporated", + .compositions = usb_func_composition, + .num_compositions = ARRAY_SIZE(usb_func_composition), + .function_map = usb_functions_map, + .num_functions = ARRAY_SIZE(usb_functions_map), + .config_gpio = NULL, +}; + +static struct android_pmem_platform_data android_pmem_pdata = { + .name = "pmem", + .size = MSM_PMEM_MDP_SIZE, + .no_allocator = 0, + .cached = 1, +}; + +static struct android_pmem_platform_data android_pmem_gpu0_pdata = { + .name = "pmem_gpu0", + .start = MSM_PMEM_GPU0_BASE, + .size = MSM_PMEM_GPU0_SIZE, + .no_allocator = 1, + .cached = 0, +}; + +static struct platform_device android_pmem_device = { + .name = "android_pmem", + .id = 0, + .dev = { .platform_data = &android_pmem_pdata }, +}; + +static struct platform_device android_pmem_gpu0_device = { + .name = "android_pmem", + .id = 2, + .dev = { .platform_data = &android_pmem_gpu0_pdata }, +}; + +static struct resource qsd_spi_resources[] = { + { + .name = "spi_irq_in", + .start = INT_SPI_INPUT, + .end = INT_SPI_INPUT, + .flags = IORESOURCE_IRQ, + }, + { + .name = "spi_irq_out", + .start = INT_SPI_OUTPUT, + .end = INT_SPI_OUTPUT, + .flags = IORESOURCE_IRQ, + }, + { + .name = "spi_irq_err", + .start = INT_SPI_ERROR, + .end = INT_SPI_ERROR, + .flags = IORESOURCE_IRQ, + }, + { + .name = "spi_base", + .start = 0xA1200000, + .end = 0xA1200000 + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + { + .name = "spi_clk", + .start = 17, + .end = 1, + .flags = IORESOURCE_IRQ, + }, + { + .name = "spi_mosi", + .start = 18, + .end = 1, + .flags = IORESOURCE_IRQ, + }, + { + .name = "spi_miso", + .start = 19, + .end = 1, + .flags = IORESOURCE_IRQ, + }, + { + .name = "spi_cs0", + .start = 20, + .end = 1, + .flags = IORESOURCE_IRQ, + }, + { + .name = "spi_irq_cs0", + .start = 106, + .end = 0, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device qsd_device_spi = { + .name = "spi_qsd", + .id = 0, + .num_resources = ARRAY_SIZE(qsd_spi_resources), + .resource = qsd_spi_resources, +}; + +static struct spi_board_info msm_spi_board_info[] __initdata = { + { + .modalias = "bma150", + .mode = SPI_MODE_3, + .irq = MSM_GPIO_TO_INT(106), + .bus_num = 0, + .chip_select = 0, + .max_speed_hz = 10000000, + } +}; + +static struct resource msm_fb_resources[] = { + { + .flags = IORESOURCE_DMA, + } +}; + +static int msm_fb_detect_panel(const char *name) +{ + int ret; + + if (!strcmp(name, "mddi_toshiba_wvga")) + ret = 0; + else + ret = -ENODEV; + + return ret; +} + +static struct msm_fb_platform_data msm_fb_pdata = { + .detect_client = msm_fb_detect_panel, +}; + +static struct platform_device msm_fb_device = { + .name = "msm_fb", + .id = 0, + .num_resources = ARRAY_SIZE(msm_fb_resources), + .resource = msm_fb_resources, + .dev = { + .platform_data = &msm_fb_pdata, + } +}; + +static int msm_fb_mddi_sel_clk(u32 *clk_rate) +{ + *clk_rate *= 2; + return 0; +} + +static struct mddi_platform_data mddi_pdata = { + .mddi_sel_clk = msm_fb_mddi_sel_clk, +}; + +static void __init msm_fb_add_devices(void) +{ + msm_fb_register_device("mdp", 0); + msm_fb_register_device("pmdh", &mddi_pdata); + msm_fb_register_device("emdh", &mddi_pdata); + msm_fb_register_device("tvenc", 0); + msm_fb_register_device("lcdc", 0); +} + +static struct resource msm_audio_resources[] = { + { + .flags = IORESOURCE_DMA, + }, + { + .name = "aux_pcm_dout", + .start = 68, + .end = 68, + .flags = IORESOURCE_IO, + }, + { + .name = "aux_pcm_din", + .start = 69, + .end = 69, + .flags = IORESOURCE_IO, + }, + { + .name = "aux_pcm_syncout", + .start = 70, + .end = 70, + .flags = IORESOURCE_IO, + }, + { + .name = "aux_pcm_clkin_a", + .start = 71, + .end = 71, + .flags = IORESOURCE_IO, + }, +}; + +static struct platform_device msm_audio_device = { + .name = "msm_audio", + .id = 0, + .num_resources = ARRAY_SIZE(msm_audio_resources), + .resource = msm_audio_resources, +}; + +static void __iomem *comet_cpld_base(void) +{ + static void __iomem *comet_cpld_base_addr; + + if (!comet_cpld_base_addr) { + if (!request_mem_region(COMET_CPLD_START, COMET_CPLD_SIZE, + "cpld")) { + printk(KERN_ERR + "%s: request_mem_region for comet cpld failed\n", + __func__); + goto cpld_base_exit; + } + comet_cpld_base_addr = ioremap(COMET_CPLD_START, + COMET_CPLD_SIZE); + if (!comet_cpld_base_addr) { + release_mem_region(COMET_CPLD_START, + COMET_CPLD_SIZE); + printk(KERN_ERR "%s: Could not map comet cpld\n", + __func__); + } + } +cpld_base_exit: + return comet_cpld_base_addr; +} + +static struct msm_serial_hs_platform_data msm_uart_dm1_pdata = { + .wakeup_irq = MSM_GPIO_TO_INT(45), + .inject_rx_on_wakeup = 1, + .rx_to_inject = 0x32, +}; + +static struct resource bluesleep_resources[] = { + { + .name = "gpio_host_wake", + .start = 21, + .end = 21, + .flags = IORESOURCE_IO, + }, + { + .name = "gpio_ext_wake", + .start = 29, + .end = 29, + .flags = IORESOURCE_IO, + }, + { + .name = "host_wake", + .start = MSM_GPIO_TO_INT(21), + .end = MSM_GPIO_TO_INT(21), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device msm_bluesleep_device = { + .name = "bluesleep", + .id = -1, + .num_resources = ARRAY_SIZE(bluesleep_resources), + .resource = bluesleep_resources, +}; + +#ifdef CONFIG_BT +static struct platform_device msm_bt_power_device = { + .name = "bt_power", +}; + +enum { + BT_SYSRST, + BT_WAKE, + BT_HOST_WAKE, + BT_PWR_EN, + BT_RFR, + BT_CTS, + BT_RX, + BT_TX, + BT_PCM_DOUT, + BT_PCM_DIN, + BT_PCM_SYNC, + BT_PCM_CLK, +}; + +static unsigned bt_config_power_on[] = { + GPIO_CFG(29, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* WAKE */ + GPIO_CFG(21, 0, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), /* HOST_WAKE */ + GPIO_CFG(22, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* PWR_EN */ + GPIO_CFG(43, 2, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* RFR */ + GPIO_CFG(44, 2, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), /* CTS */ + GPIO_CFG(45, 2, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), /* Rx */ + GPIO_CFG(46, 2, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* Tx */ + GPIO_CFG(68, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* PCM_DOUT */ + GPIO_CFG(69, 1, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), /* PCM_DIN */ + GPIO_CFG(70, 2, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* PCM_SYNC */ + GPIO_CFG(71, 2, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* PCM_CLK */ +}; +static unsigned bt_config_power_off[] = { + GPIO_CFG(29, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* WAKE */ + GPIO_CFG(21, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* HOST_WAKE */ + GPIO_CFG(22, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* PWR_EN */ + GPIO_CFG(43, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* RFR */ + GPIO_CFG(44, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* CTS */ + GPIO_CFG(45, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* Rx */ + GPIO_CFG(46, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* Tx */ + GPIO_CFG(68, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* PCM_DOUT */ + GPIO_CFG(69, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* PCM_DIN */ + GPIO_CFG(70, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* PCM_SYNC */ + GPIO_CFG(71, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* PCM_CLK */ +}; + +static int bluetooth_power(int on) +{ + int pin, rc; + char __iomem *cpld_base; + + printk(KERN_DEBUG "%s\n", __func__); + + cpld_base = comet_cpld_base(); + if (!cpld_base) + return -ENOMEM; + + if (on) { + for (pin = 0; pin < ARRAY_SIZE(bt_config_power_on); pin++) { + rc = gpio_tlmm_config(bt_config_power_on[pin], + GPIO_ENABLE); + if (rc) { + printk(KERN_ERR + "%s: gpio_tlmm_config(%#x)=%d\n", + __func__, bt_config_power_on[pin], rc); + return -EIO; + } + } + + gpio_set_value(22, on); /* PWR_EN */ + writeb(COMET_CPLD_PER_RESET_BT_RESET, + cpld_base + COMET_CPLD_PER_RESET); /* SYSRST */ + + } else { + writeb(COMET_CPLD_PER_RESET_BT_RESET, + cpld_base + COMET_CPLD_PER_RESET); /* SYSRST */ + gpio_set_value(22, on); /* PWR_EN */ + + for (pin = 0; pin < ARRAY_SIZE(bt_config_power_off); pin++) { + rc = gpio_tlmm_config(bt_config_power_off[pin], + GPIO_ENABLE); + if (rc) { + printk(KERN_ERR + "%s: gpio_tlmm_config(%#x)=%d\n", + __func__, bt_config_power_off[pin], rc); + return -EIO; + } + } + + } + + return 0; +} + +static void __init bt_power_init(void) +{ + msm_bt_power_device.dev.platform_data = &bluetooth_power; +} +#else +#define bt_power_init(x) do {} while (0) +#endif + +static struct platform_device *devices[] __initdata = { + &msm_fb_device, + &msm_device_smd, + &smc911x_device, + &android_pmem_device, + &android_pmem_gpu0_device, + &msm_device_nand, + &msm_device_hsusb_otg, + &msm_device_hsusb_host, + &msm_device_hsusb_peripheral, + &mass_storage_device, + &msm_audio_device, + &msm_device_uart_dm1, + &msm_bluesleep_device, +#ifdef CONFIG_BT + &msm_bt_power_device, +#endif + &msm_device_i2c, + &qsd_device_spi, + &msm_device_tssc, +}; + +/* The TPS65023 PMIC outputs 1.225V as default at boot */ +#define TPS65023_DEFAULT_DCDC1 1225 +#ifdef CONFIG_QSD_SVS +#define TPS65023_MAX_DCDC1 1600 +#else +#define TPS65023_MAX_DCDC1 TPS65023_DEFAULT_DCDC1 +#endif + +static int qsd8x50_tps65023_set_dcdc1(int mVolts) +{ + int rc = 0; +#ifdef CONFIG_QSD_SVS + rc = tps65023_set_dcdc1_level(mVolts); + /* By default the TPS65023 will be initialized to 1.225V. + * So we can safely switch to any frequency within this + * voltage even if the device is not probed/ready. + */ + if (rc == -ENODEV && mVolts <= TPS65023_DEFAULT_DCDC1) + rc = 0; +#else + /* Disallow frequencies not supported in the default PMIC + * output voltage. + */ + if (mVolts > TPS65023_DEFAULT_DCDC1) + rc = -EFAULT; +#endif + return rc; +} + +static struct msm_acpu_clock_platform_data comet_clock_data = { + .acpu_switch_time_us = 20, + .max_speed_delta_khz = 256000, + .vdd_switch_time_us = 62, + .power_collapse_khz = 128000000, + .wait_for_irq_khz = 128000000, + .max_vdd = TPS65023_MAX_DCDC1, + .acpu_set_vdd = qsd8x50_tps65023_set_dcdc1, +}; + +static void touchpad_gpio_release(void) +{ + gpio_free(TOUCHPAD_IRQ); + gpio_free(TOUCHPAD_SUSPEND); +} + +static int touchpad_gpio_setup(void) +{ + int rc; + int suspend_pin = TOUCHPAD_SUSPEND; + int irq_pin = TOUCHPAD_IRQ; + unsigned suspend_cfg = + GPIO_CFG(suspend_pin, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA); + unsigned irq_cfg = + GPIO_CFG(irq_pin, 1, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA); + + rc = gpio_request(irq_pin, "msm_touchpad_irq"); + if (rc) { + pr_err("gpio_request failed on pin %d (rc=%d)\n", + irq_pin, rc); + goto err_gpioconfig; + } + rc = gpio_request(suspend_pin, "msm_touchpad_suspend"); + if (rc) { + pr_err("gpio_request failed on pin %d (rc=%d)\n", + suspend_pin, rc); + goto err_gpioconfig; + } + rc = gpio_tlmm_config(suspend_cfg, GPIO_ENABLE); + if (rc) { + pr_err("gpio_tlmm_config failed on pin %d (rc=%d)\n", + suspend_pin, rc); + goto err_gpioconfig; + } + rc = gpio_tlmm_config(irq_cfg, GPIO_ENABLE); + if (rc) { + pr_err("gpio_tlmm_config failed on pin %d (rc=%d)\n", + irq_pin, rc); + goto err_gpioconfig; + } + return rc; + +err_gpioconfig: + touchpad_gpio_release(); + return rc; +} + +static struct msm_touchpad_platform_data msm_touchpad_data = { + .gpioirq = TOUCHPAD_IRQ, + .gpiosuspend = TOUCHPAD_SUSPEND, + .gpio_setup = touchpad_gpio_setup, + .gpio_shutdown = touchpad_gpio_release +}; + + +#define KBD_RST 35 +#define KBD_IRQ 144 + +static void kbd_gpio_release(void) +{ + gpio_free(KBD_IRQ); + gpio_free(KBD_RST); +} + +static int kbd_gpio_setup(void) +{ + int rc; + int respin = KBD_RST; + int irqpin = KBD_IRQ; + unsigned rescfg = + GPIO_CFG(respin, 0, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA); + unsigned irqcfg = + GPIO_CFG(irqpin, 0, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA); + + rc = gpio_request(irqpin, "gpio_keybd_irq"); + if (rc) { + pr_err("gpio_request failed on pin %d (rc=%d)\n", + irqpin, rc); + goto err_gpioconfig; + } + rc = gpio_request(respin, "gpio_keybd_reset"); + if (rc) { + pr_err("gpio_request failed on pin %d (rc=%d)\n", + respin, rc); + goto err_gpioconfig; + } + rc = gpio_tlmm_config(rescfg, GPIO_ENABLE); + if (rc) { + pr_err("gpio_tlmm_config failed on pin %d (rc=%d)\n", + respin, rc); + goto err_gpioconfig; + } + rc = gpio_tlmm_config(irqcfg, GPIO_ENABLE); + if (rc) { + pr_err("gpio_tlmm_config failed on pin %d (rc=%d)\n", + irqpin, rc); + goto err_gpioconfig; + } + return rc; + +err_gpioconfig: + kbd_gpio_release(); + return rc; +} + +static struct msm_i2ckbd_platform_data msm_kybd_data = { + .hwrepeat = 0, + .scanset1 = 1, + .gpioreset = KBD_RST, + .gpioirq = KBD_IRQ, + .gpio_setup = kbd_gpio_setup, + .gpio_shutdown = kbd_gpio_release, +}; + +static struct i2c_board_info msm_i2c_board_info[] __initdata = { + { + I2C_BOARD_INFO("glidesensor", 0x2A), + .irq = MSM_GPIO_TO_INT(TOUCHPAD_IRQ), + .platform_data = &msm_touchpad_data + }, + { + I2C_BOARD_INFO("msm-i2ckbd", 0x3A), + .type = "msm-i2ckbd", + .irq = MSM_GPIO_TO_INT(KBD_IRQ), + .platform_data = &msm_kybd_data + }, + { + I2C_BOARD_INFO("tps65023", 0x48), + }, +}; + +static void __init comet_init_irq(void) +{ + msm_init_irq(); + msm_init_sirc(); +} + +static void sdcc_gpio_init(void) +{ + /* SDC1 GPIOs */ + if (gpio_request(51, "sdc1_data_3")) + pr_err("failed to request gpio sdc1_data_3\n"); + if (gpio_request(52, "sdc1_data_2")) + pr_err("failed to request gpio sdc1_data_2\n"); + if (gpio_request(53, "sdc1_data_1")) + pr_err("failed to request gpio sdc1_data_1\n"); + if (gpio_request(54, "sdc1_data_0")) + pr_err("failed to request gpio sdc1_data_0\n"); + if (gpio_request(55, "sdc1_cmd")) + pr_err("failed to request gpio sdc1_cmd\n"); + if (gpio_request(56, "sdc1_clk")) + pr_err("failed to request gpio sdc1_clk\n"); + + /* SDC2 GPIOs */ + if (gpio_request(62, "sdc2_clk")) + pr_err("failed to request gpio sdc2_clk\n"); + if (gpio_request(63, "sdc2_cmd")) + pr_err("failed to request gpio sdc2_cmd\n"); + if (gpio_request(64, "sdc2_data_3")) + pr_err("failed to request gpio sdc2_data_3\n"); + if (gpio_request(65, "sdc2_data_2")) + pr_err("failed to request gpio sdc2_data_2\n"); + if (gpio_request(66, "sdc2_data_1")) + pr_err("failed to request gpio sdc2_data_1\n"); + if (gpio_request(67, "sdc2_data_0")) + pr_err("failed to request gpio sdc2_data_0\n"); + + /* SDC3 GPIOs */ + if (gpio_request(88, "sdc3_clk")) + pr_err("failed to request gpio sdc3_clk\n"); + if (gpio_request(89, "sdc3_cmd")) + pr_err("failed to request gpio sdc3_cmd\n"); + if (gpio_request(90, "sdc3_data_3")) + pr_err("failed to request gpio sdc3_data_3\n"); + if (gpio_request(91, "sdc3_data_2")) + pr_err("failed to request gpio sdc3_data_2\n"); + if (gpio_request(92, "sdc3_data_1")) + pr_err("failed to request gpio sdc3_data_1\n"); + if (gpio_request(93, "sdc3_data_0")) + pr_err("failed to request gpio sdc3_data_0\n"); + +} + +static unsigned sdcc_cfg_data[][6] = { + /* SDC1 configs */ + { + GPIO_CFG(51, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(52, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(53, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(54, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(55, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(56, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA), + }, + /* SDC2 configs */ + { + GPIO_CFG(62, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA), + GPIO_CFG(63, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(64, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(65, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(66, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(67, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + }, + /* SDC3 configs */ + { + GPIO_CFG(88, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA), + GPIO_CFG(89, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(90, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(91, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(92, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(93, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + }, +}; + +static unsigned long vreg_sts, gpio_sts; +static struct vreg *vreg_mmc; + +static void msm_sdcc_setup_gpio(int dev_id, unsigned int enable) +{ + int i, rc; + + if (!(test_bit(dev_id, &gpio_sts)^enable)) + return; + + if (enable) + set_bit(dev_id, &gpio_sts); + else + clear_bit(dev_id, &gpio_sts); + + for (i = 0; i < ARRAY_SIZE(sdcc_cfg_data[dev_id - 1]); i++) { + rc = gpio_tlmm_config(sdcc_cfg_data[dev_id - 1][i], + enable ? GPIO_ENABLE : GPIO_DISABLE); + if (rc) + printk(KERN_ERR "%s: gpio_tlmm_config(%#x)=%d\n", + __func__, sdcc_cfg_data[dev_id - 1][i], rc); + } +} + +static uint32_t msm_sdcc_setup_power(struct device *dv, unsigned int vdd) +{ + int rc = 0; + struct platform_device *pdev; + + pdev = container_of(dv, struct platform_device, dev); + msm_sdcc_setup_gpio(pdev->id, !!vdd); + + if (vdd == 0) { + if (!vreg_sts) + return 0; + + clear_bit(pdev->id, &vreg_sts); + + if (!vreg_sts) { + rc = vreg_disable(vreg_mmc); + if (rc) + printk(KERN_ERR "%s: return val: %d \n", + __func__, rc); + } + return 0; + } + + if (!vreg_sts) { + rc = vreg_set_level(vreg_mmc, 2850); + if (!rc) + rc = vreg_enable(vreg_mmc); + if (rc) + printk(KERN_ERR "%s: return val: %d \n", + __func__, rc); + } + set_bit(pdev->id, &vreg_sts); + return 0; +} + +static struct mmc_platform_data comet_sdcc_data = { + .ocr_mask = MMC_VDD_27_28 | MMC_VDD_28_29, + .translate_vdd = msm_sdcc_setup_power, +}; + +static void __init comet_init_mmc(void) +{ + vreg_mmc = vreg_get(NULL, "gp6"); + if (IS_ERR(vreg_mmc)) { + printk(KERN_ERR "%s: vreg get failed (%ld)\n", + __func__, PTR_ERR(vreg_mmc)); + return; + } + sdcc_gpio_init(); + msm_add_sdcc(1, &comet_sdcc_data); + msm_add_sdcc(3, &comet_sdcc_data); +} + +static struct msm_i2c_platform_data msm_i2c_pdata = { + .clk_freq = 100000, +}; + +static void __init msm_device_i2c_init(void) +{ + msm_device_i2c.dev.platform_data = &msm_i2c_pdata; +} + +static struct msm_pm_platform_data msm_pm_data[MSM_PM_SLEEP_MODE_NR] = { + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].supported = 1, + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].suspend_enabled = 1, + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].idle_enabled = 1, + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].latency = 16000, + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].residency = 20000, + + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].supported = 1, + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].suspend_enabled = 1, + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].idle_enabled = 1, + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].latency = 12000, + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].residency = 20000, + + [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].supported = 1, + [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].suspend_enabled + = 1, + [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].idle_enabled = 0, + [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].latency = 2000, + [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].residency = 10000, + + [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].supported = 1, + [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].suspend_enabled = 1, + [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].idle_enabled = 1, + [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].latency = 500, + [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].residency = 0, +}; + +static void __init comet_init(void) +{ + char __iomem *cpld_base; + + cpld_base = comet_cpld_base(); + if (cpld_base) { + /* enable all peripherals except microphones and */ + /* reset line for i2c touchpad */ + writew(0xFFD8, cpld_base + COMET_CPLD_PER_ENABLE); + writew(COMET_CPLD_PER_RESET_ALL_RESET, + cpld_base + COMET_CPLD_PER_RESET); + } + + msm_acpu_clock_init(&comet_clock_data); + + msm_device_hsusb_peripheral.dev.platform_data = &msm_hsusb_pdata; + msm_device_hsusb_host.dev.platform_data = &msm_hsusb_pdata; + platform_add_devices(devices, ARRAY_SIZE(devices)); + msm_device_uart_dm1.dev.platform_data = &msm_uart_dm1_pdata; + bt_power_init(); + msm_fb_add_devices(); + comet_init_mmc(); + msm_device_i2c_init(); + i2c_register_board_info(0, msm_i2c_board_info, + ARRAY_SIZE(msm_i2c_board_info)); + spi_register_board_info(msm_spi_board_info, + ARRAY_SIZE(msm_spi_board_info)); + msm_pm_set_platform_data(msm_pm_data); +} + +static void __init comet_allocate_memory_regions(void) +{ + void *addr; + unsigned long size; + + addr = alloc_bootmem(android_pmem_pdata.size); + android_pmem_pdata.start = __pa(addr); + + size = MSM_FB_SIZE; + addr = (void *)MSM_FB_BASE; + msm_fb_resources[0].start = (unsigned long)addr; + msm_fb_resources[0].end = msm_fb_resources[0].start + size - 1; + printk(KERN_INFO "using %lu bytes of SMI at %lx physical for fb\n", + size, (unsigned long)addr); + + size = MSM_AUDIO_SIZE; + addr = alloc_bootmem(size); + msm_audio_resources[0].start = __pa(addr); + msm_audio_resources[0].end = __pa(addr) + MSM_AUDIO_SIZE; + printk(KERN_INFO "allocating %lu bytes at %p (%lx physical)" + "for audio\n", size, addr, __pa(addr)); +} + +static void __init comet_map_io(void) +{ + msm_map_comet_io(); + comet_allocate_memory_regions(); + msm_clock_init(msm_clocks_8x50, msm_num_clocks_8x50); +} + +MACHINE_START(QSD8X50_COMET, "QCT QSD8x50 Comet") +#ifdef CONFIG_MSM_DEBUG_UART + .phys_io = MSM_DEBUG_UART_PHYS, + .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc, +#endif + .boot_params = 0x0, + .map_io = comet_map_io, + .init_irq = comet_init_irq, + .init_machine = comet_init, + .timer = &msm_timer, +MACHINE_END diff --git a/arch/arm/mach-msm/board-halibut.c b/arch/arm/mach-msm/board-halibut.c index 4bdf17c4c3f2..93f658088f66 100644 --- a/arch/arm/mach-msm/board-halibut.c +++ b/arch/arm/mach-msm/board-halibut.c @@ -1,6 +1,7 @@ /* linux/arch/arm/mach-msm/board-halibut.c * * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. * Author: Brian Swetland * * This software is licensed under the terms of the GNU General Public @@ -13,13 +14,17 @@ * GNU General Public License for more details. * */ - #include #include #include #include #include #include +#include +#include +#include +#include +#include #include #include @@ -29,14 +34,38 @@ #include #include +#include +#include +#include +#include #include #include #include - -#include -#include +#include +#include +#include +#include +#include +#include #include "devices.h" +#include "socinfo.h" +#include "msm-keypad-devices.h" +#include "pm.h" + +#ifdef CONFIG_MSM_STACKED_MEMORY +#define MSM_SMI_BASE 0x100000 +#define MSM_SMI_SIZE 0x800000 + +#define MSM_PMEM_GPU0_BASE MSM_SMI_BASE +#define MSM_PMEM_GPU0_SIZE 0x800000 +#endif + +#define MSM_PMEM_MDP_SIZE 0x800000 +#define MSM_PMEM_CAMERA_SIZE 0xa00000 +#define MSM_PMEM_ADSP_SIZE 0x800000 +#define MSM_PMEM_GPU1_SIZE 0x800000 +#define MSM_FB_SIZE 0x200000 static struct resource smc91x_resources[] = { [0] = { @@ -51,6 +80,132 @@ static struct resource smc91x_resources[] = { }, }; +#ifdef CONFIG_USB_FUNCTION +static struct usb_mass_storage_platform_data usb_mass_storage_pdata = { + .nluns = 0x02, + .buf_size = 16384, + .vendor = "GOOGLE", + .product = "Mass storage", + .release = 0xffff, +}; + +static struct platform_device mass_storage_device = { + .name = "usb_mass_storage", + .id = -1, + .dev = { + .platform_data = &usb_mass_storage_pdata, + }, +}; +#endif + +#ifdef CONFIG_USB_ANDROID +static struct android_usb_platform_data android_usb_pdata = { + .vendor_id = 0x05C6, + .product_id = 0xF000, + .adb_product_id = 0x9015, + .version = 0x0100, + .product_name = "Qualcomm HSUSB Device", + .manufacturer_name = "Qualcomm Incorporated", + .nluns = 1, +}; + +static struct platform_device android_usb_device = { + .name = "android_usb", + .id = -1, + .dev = { + .platform_data = &android_usb_pdata, + }, +}; +#endif + +#ifdef CONFIG_USB_FUNCTION +static void hsusb_gpio_init(void) +{ + if (gpio_request(111, "ulpi_data_0")) + pr_err("failed to request gpio ulpi_data_0\n"); + if (gpio_request(112, "ulpi_data_1")) + pr_err("failed to request gpio ulpi_data_1\n"); + if (gpio_request(113, "ulpi_data_2")) + pr_err("failed to request gpio ulpi_data_2\n"); + if (gpio_request(114, "ulpi_data_3")) + pr_err("failed to request gpio ulpi_data_3\n"); + if (gpio_request(115, "ulpi_data_4")) + pr_err("failed to request gpio ulpi_data_4\n"); + if (gpio_request(116, "ulpi_data_5")) + pr_err("failed to request gpio ulpi_data_5\n"); + if (gpio_request(117, "ulpi_data_6")) + pr_err("failed to request gpio ulpi_data_6\n"); + if (gpio_request(118, "ulpi_data_7")) + pr_err("failed to request gpio ulpi_data_7\n"); + if (gpio_request(119, "ulpi_dir")) + pr_err("failed to request gpio ulpi_dir\n"); + if (gpio_request(120, "ulpi_next")) + pr_err("failed to request gpio ulpi_next\n"); + if (gpio_request(121, "ulpi_stop")) + pr_err("failed to request gpio ulpi_stop\n"); +} + +static unsigned usb_gpio_lpm_config[] = { + GPIO_CFG(111, 1, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), /* DATA 0 */ + GPIO_CFG(112, 1, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), /* DATA 1 */ + GPIO_CFG(113, 1, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), /* DATA 2 */ + GPIO_CFG(114, 1, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), /* DATA 3 */ + GPIO_CFG(115, 1, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), /* DATA 4 */ + GPIO_CFG(116, 1, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), /* DATA 5 */ + GPIO_CFG(117, 1, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), /* DATA 6 */ + GPIO_CFG(118, 1, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), /* DATA 7 */ + GPIO_CFG(119, 1, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), /* DIR */ + GPIO_CFG(120, 1, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), /* NEXT */ + GPIO_CFG(121, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* STOP */ +}; + +static unsigned usb_gpio_lpm_unconfig[] = { + GPIO_CFG(111, 1, GPIO_OUTPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DATA 0 */ + GPIO_CFG(112, 1, GPIO_OUTPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DATA 1 */ + GPIO_CFG(113, 1, GPIO_OUTPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DATA 2 */ + GPIO_CFG(114, 1, GPIO_OUTPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DATA 3 */ + GPIO_CFG(115, 1, GPIO_OUTPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DATA 4 */ + GPIO_CFG(116, 1, GPIO_OUTPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DATA 5 */ + GPIO_CFG(117, 1, GPIO_OUTPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DATA 6 */ + GPIO_CFG(118, 1, GPIO_OUTPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DATA 7 */ + GPIO_CFG(119, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DIR */ + GPIO_CFG(120, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* NEXT */ + GPIO_CFG(121, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_2MA), /* STOP */ +}; + +static int usb_config_gpio(int config) +{ + int pin, rc; + + if (config) { + for (pin = 0; pin < ARRAY_SIZE(usb_gpio_lpm_config); pin++) { + rc = gpio_tlmm_config(usb_gpio_lpm_config[pin], + GPIO_ENABLE); + if (rc) { + printk(KERN_ERR + "%s: gpio_tlmm_config(%#x)=%d\n", + __func__, usb_gpio_lpm_config[pin], rc); + return -EIO; + } + } + } else { + for (pin = 0; pin < ARRAY_SIZE(usb_gpio_lpm_unconfig); pin++) { + rc = gpio_tlmm_config(usb_gpio_lpm_unconfig[pin], + GPIO_ENABLE); + if (rc) { + printk(KERN_ERR + "%s: gpio_tlmm_config(%#x)=%d\n", + __func__, usb_gpio_lpm_config[pin], rc); + return -EIO; + } + } + } + + return 0; +} +#endif + + static struct platform_device smc91x_device = { .name = "smc91x", .id = 0, @@ -62,16 +217,185 @@ static struct platform_device *devices[] __initdata = { #if !defined(CONFIG_MSM_SERIAL_DEBUGGER) &msm_device_uart3, #endif + &msm_device_uart_dm1, &msm_device_smd, &msm_device_nand, - &msm_device_hsusb, &msm_device_i2c, &smc91x_device, + &msm_device_tssc, + &android_pmem_camera_device, + &android_pmem_device, + &android_pmem_adsp_device, +#ifdef CONFIG_MSM_STACKED_MEMORY + &android_pmem_gpu0_device, +#endif + &android_pmem_gpu1_device, + &msm_device_hsusb_otg, + &msm_device_hsusb_host, +#if defined(CONFIG_USB_FUNCTION) || defined(CONFIG_USB_ANDROID) + &msm_device_hsusb_peripheral, +#endif +#ifdef CONFIG_USB_FUNCTION + &mass_storage_device, +#endif +#ifdef CONFIG_USB_ANDROID + &android_usb_device, +#endif + +#ifdef CONFIG_BT + &msm_bt_power_device, +#endif &halibut_snd, + &msm_bluesleep_device, + &msm_fb_device, + &mddi_toshiba_device, + &mddi_sharp_device, }; extern struct sys_timer msm_timer; +static struct i2c_board_info i2c_devices[] = { + { + I2C_BOARD_INFO("mt9d112", 0x78 >> 1), + }, + { + I2C_BOARD_INFO("s5k3e2fx", 0x20 >> 1), + }, + { + I2C_BOARD_INFO("mt9p012", 0x6C >> 1), + }, + { + I2C_BOARD_INFO("mt9t013", 0x6C), + }, +}; + +static uint32_t camera_off_gpio_table[] = { + /* parallel CAMERA interfaces */ + GPIO_CFG(0, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT0 */ + GPIO_CFG(1, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT1 */ + GPIO_CFG(2, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT2 */ + GPIO_CFG(3, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT3 */ + GPIO_CFG(4, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT4 */ + GPIO_CFG(5, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT5 */ + GPIO_CFG(6, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT6 */ + GPIO_CFG(7, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT7 */ + GPIO_CFG(8, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT8 */ + GPIO_CFG(9, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT9 */ + GPIO_CFG(10, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT10 */ + GPIO_CFG(11, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT11 */ + GPIO_CFG(12, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* PCLK */ + GPIO_CFG(13, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* HSYNC_IN */ + GPIO_CFG(14, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* VSYNC_IN */ + GPIO_CFG(15, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* MCLK */ +}; + +static uint32_t camera_on_gpio_table[] = { + /* parallel CAMERA interfaces */ + GPIO_CFG(0, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT0 */ + GPIO_CFG(1, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT1 */ + GPIO_CFG(2, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT2 */ + GPIO_CFG(3, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT3 */ + GPIO_CFG(4, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT4 */ + GPIO_CFG(5, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT5 */ + GPIO_CFG(6, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT6 */ + GPIO_CFG(7, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT7 */ + GPIO_CFG(8, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT8 */ + GPIO_CFG(9, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT9 */ + GPIO_CFG(10, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT10 */ + GPIO_CFG(11, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT11 */ + GPIO_CFG(12, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_16MA), /* PCLK */ + GPIO_CFG(13, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* HSYNC_IN */ + GPIO_CFG(14, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* VSYNC_IN */ + GPIO_CFG(15, 1, GPIO_OUTPUT, GPIO_PULL_DOWN, GPIO_16MA), /* MCLK */ +}; + +static void config_gpio_table(uint32_t *table, int len) +{ + int n, rc; + for (n = 0; n < len; n++) { + rc = gpio_tlmm_config(table[n], GPIO_ENABLE); + if (rc) { + printk(KERN_ERR "%s: gpio_tlmm_config(%#x)=%d\n", + __func__, table[n], rc); + break; + } + } +} + +static void config_camera_on_gpios(void) +{ + config_gpio_table(camera_on_gpio_table, + ARRAY_SIZE(camera_on_gpio_table)); +} + +static void config_camera_off_gpios(void) +{ + config_gpio_table(camera_off_gpio_table, + ARRAY_SIZE(camera_off_gpio_table)); +} + +#define MSM_PROBE_INIT(name) name##_probe_init +static struct msm_camera_sensor_info msm_camera_sensor[] = { + { + .sensor_reset = 89, + .sensor_pwd = 85, + .vcm_pwd = 0, + .sensor_name = "mt9d112", + .flash_type = MSM_CAMERA_FLASH_NONE, +#ifdef CONFIG_MSM_CAMERA + .sensor_probe = MSM_PROBE_INIT(mt9d112), +#endif + }, + { + .sensor_reset = 89, + .sensor_pwd = 85, + .vcm_pwd = 0, + .sensor_name = "s5k3e2fx", + .flash_type = MSM_CAMERA_FLASH_NONE, +#ifdef CONFIG_MSM_CAMERA + .sensor_probe = MSM_PROBE_INIT(s5k3e2fx), +#endif + }, + { + .sensor_reset = 89, + .sensor_pwd = 85, + .vcm_pwd = 88, + .sensor_name = "mt9p012", + .flash_type = MSM_CAMERA_FLASH_LED, +#ifdef CONFIG_MSM_CAMERA + .sensor_probe = MSM_PROBE_INIT(mt9p012), +#endif + }, + { + .sensor_reset = 89, + .sensor_pwd = 85, + .vcm_pwd = 0, + .sensor_name = "mt9t013", + .flash_type = MSM_CAMERA_FLASH_NONE, +#ifdef CONFIG_MSM_CAMERA + .sensor_probe = MSM_PROBE_INIT(mt9t013), +#endif + }, +}; +#undef MSM_PROBE_INIT + +static struct msm_camera_device_platform_data msm_camera_device_data = { + .camera_gpio_on = config_camera_on_gpios, + .camera_gpio_off = config_camera_off_gpios, + .snum = ARRAY_SIZE(msm_camera_sensor), + .sinfo = &msm_camera_sensor[0], + .ioext.mdcphy = MSM_MDC_PHYS, + .ioext.mdcsz = MSM_MDC_SIZE, + .ioext.appphy = MSM_CLK_CTL_PHYS, + .ioext.appsz = MSM_CLK_CTL_SIZE, +}; + +static void __init msm_camera_add_device(void) +{ + msm_camera_register_device(NULL, 0, &msm_camera_device_data); + config_camera_off_gpios(); +} + static void __init halibut_init_irq(void) { msm_init_irq(); @@ -83,34 +407,338 @@ static struct msm_acpu_clock_platform_data halibut_clock_data = { .vdd_switch_time_us = 62, .power_collapse_khz = 19200000, .wait_for_irq_khz = 128000000, + .max_axi_khz = 128000, }; void msm_serial_debug_init(unsigned int base, int irq, struct device *clk_device, int signal_irq); +static void sdcc_gpio_init(void) +{ +#ifdef CONFIG_MMC_MSM_CARD_HW_DETECTION + int rc = 0; + if (gpio_request(49, "sdc1_status_irq")) + pr_err("failed to request gpio sdc1_status_irq\n"); + rc = gpio_tlmm_config(GPIO_CFG(49, 0, GPIO_INPUT, GPIO_PULL_UP, + GPIO_2MA), GPIO_ENABLE); + if (rc) + printk(KERN_ERR "%s: Failed to configure GPIO %d\n", + __func__, rc); +#endif + /* SDC1 GPIOs */ +#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT + if (gpio_request(51, "sdc1_data_3")) + pr_err("failed to request gpio sdc1_data_3\n"); + if (gpio_request(52, "sdc1_data_2")) + pr_err("failed to request gpio sdc1_data_2\n"); + if (gpio_request(53, "sdc1_data_1")) + pr_err("failed to request gpio sdc1_data_1\n"); + if (gpio_request(54, "sdc1_data_0")) + pr_err("failed to request gpio sdc1_data_0\n"); + if (gpio_request(55, "sdc1_cmd")) + pr_err("failed to request gpio sdc1_cmd\n"); + if (gpio_request(56, "sdc1_clk")) + pr_err("failed to request gpio sdc1_clk\n"); +#endif + + if (machine_is_msm7201a_ffa()) + return; + + /* SDC2 GPIOs */ +#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT + if (gpio_request(62, "sdc2_clk")) + pr_err("failed to request gpio sdc2_clk\n"); + if (gpio_request(63, "sdc2_cmd")) + pr_err("failed to request gpio sdc2_cmd\n"); + if (gpio_request(64, "sdc2_data_3")) + pr_err("failed to request gpio sdc2_data_3\n"); + if (gpio_request(65, "sdc2_data_2")) + pr_err("failed to request gpio sdc2_data_2\n"); + if (gpio_request(66, "sdc2_data_1")) + pr_err("failed to request gpio sdc2_data_1\n"); + if (gpio_request(67, "sdc2_data_0")) + pr_err("failed to request gpio sdc2_data_0\n"); +#endif + + /* SDC4 GPIOs */ +#ifdef CONFIG_MMC_MSM_SDC4_SUPPORT + if (gpio_request(19, "sdc4_data_3")) + pr_err("failed to request gpio sdc4_data_3\n"); + if (gpio_request(20, "sdc4_data_2")) + pr_err("failed to request gpio sdc4_data_2\n"); + if (gpio_request(21, "sdc4_data_1")) + pr_err("failed to request gpio sdc4_data_1\n"); + if (gpio_request(107, "sdc4_cmd")) + pr_err("failed to request gpio sdc4_cmd\n"); + if (gpio_request(108, "sdc4_data_0")) + pr_err("failed to request gpio sdc4_data_0\n"); + if (gpio_request(109, "sdc4_clk")) + pr_err("failed to request gpio sdc4_clk\n"); +#endif +} + +static unsigned sdcc_cfg_data[][6] = { + /* SDC1 configs */ + { + GPIO_CFG(51, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(52, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(53, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(54, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(55, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(56, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA), + }, + /* SDC2 configs */ + { + GPIO_CFG(62, 2, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA), + GPIO_CFG(63, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(64, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(65, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(66, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(67, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + }, + { + /* SDC3 configs */ + }, + /* SDC4 configs */ + { + GPIO_CFG(19, 3, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(20, 3, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(21, 3, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(107, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(108, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(109, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA), + } +}; + +static unsigned long vreg_sts, gpio_sts; +static struct mpp *mpp_mmc; +static struct vreg *vreg_mmc; + +static void msm_sdcc_setup_gpio(int dev_id, unsigned int enable) +{ + int i, rc; + + if (!(test_bit(dev_id, &gpio_sts)^enable)) + return; + + if (enable) + set_bit(dev_id, &gpio_sts); + else + clear_bit(dev_id, &gpio_sts); + + for (i = 0; i < ARRAY_SIZE(sdcc_cfg_data[dev_id - 1]); i++) { + rc = gpio_tlmm_config(sdcc_cfg_data[dev_id - 1][i], + enable ? GPIO_ENABLE : GPIO_DISABLE); + if (rc) { + printk(KERN_ERR "%s: gpio_tlmm_config(%#x)=%d\n", + __func__, sdcc_cfg_data[dev_id - 1][i], rc); + } + } +} + +static uint32_t msm_sdcc_setup_power(struct device *dv, unsigned int vdd) +{ + int rc = 0; + struct platform_device *pdev; + + pdev = container_of(dv, struct platform_device, dev); + msm_sdcc_setup_gpio(pdev->id, !!vdd); + + if (vdd == 0) { + if (!vreg_sts) + return 0; + + clear_bit(pdev->id, &vreg_sts); + + if (!vreg_sts) { + if (machine_is_msm7201a_ffa()) + rc = mpp_config_digital_out(mpp_mmc, + MPP_CFG(MPP_DLOGIC_LVL_MSMP, + MPP_DLOGIC_OUT_CTRL_LOW)); + else + rc = vreg_disable(vreg_mmc); + if (rc) + printk(KERN_ERR "%s: return val: %d \n", + __func__, rc); + } + return 0; + } + + if (!vreg_sts) { + if (machine_is_msm7201a_ffa()) + rc = mpp_config_digital_out(mpp_mmc, + MPP_CFG(MPP_DLOGIC_LVL_MSMP, + MPP_DLOGIC_OUT_CTRL_HIGH)); + else { + rc = vreg_set_level(vreg_mmc, 2850); + if (!rc) + rc = vreg_enable(vreg_mmc); + } + if (rc) + printk(KERN_ERR "%s: return val: %d \n", + __func__, rc); + } + set_bit(pdev->id, &vreg_sts); + return 0; +} + +#ifdef CONFIG_MMC_MSM_CARD_HW_DETECTION +static unsigned int halibut_sdcc_slot_status(struct device *dev) +{ + return (unsinged int) gpio_get_value(49); +} +#endif + +static struct mmc_platform_data halibut_sdcc_data = { + .ocr_mask = MMC_VDD_28_29, + .translate_vdd = msm_sdcc_setup_power, +#ifdef CONFIG_MMC_MSM_CARD_HW_DETECTION + .status = halibut_sdcc_slot_status, + .status_irq = MSM_GPIO_TO_INT(49), + .irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, +#endif +}; + +static void __init halibut_init_mmc(void) +{ + if (machine_is_msm7201a_ffa()) { + mpp_mmc = mpp_get(NULL, "mpp3"); + if (!mpp_mmc) { + printk(KERN_ERR "%s: mpp get failed (%ld)\n", + __func__, PTR_ERR(vreg_mmc)); + return; + } + } else { + vreg_mmc = vreg_get(NULL, "mmc"); + if (IS_ERR(vreg_mmc)) { + printk(KERN_ERR "%s: vreg get failed (%ld)\n", + __func__, PTR_ERR(vreg_mmc)); + return; + } + } + + sdcc_gpio_init(); +#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT + msm_add_sdcc(1, &halibut_sdcc_data); +#endif + + if (machine_is_msm7201a_surf()) { +#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT + msm_add_sdcc(2, &halibut_sdcc_data); +#endif +#ifdef CONFIG_MMC_MSM_SDC4_SUPPORT + msm_add_sdcc(4, &halibut_sdcc_data); +#endif + } +} + +static struct msm_panel_common_pdata mdp_pdata = { + .gpio = 97, +}; + +static void __init msm_fb_add_devices(void) +{ + msm_fb_register_device("mdp", &mdp_pdata); + msm_fb_register_device("ebi2", 0); + msm_fb_register_device("pmdh", &mddi_pdata); + msm_fb_register_device("emdh", 0); + msm_fb_register_device("tvenc", &tvenc_pdata); +} + +static struct msm_i2c_platform_data msm_i2c_pdata = { + .clk_freq = 100000, +}; + +static void __init msm_device_i2c_init(void) +{ + msm_device_i2c.dev.platform_data = &msm_i2c_pdata; +} + +static struct msm_pm_platform_data msm_pm_data[MSM_PM_SLEEP_MODE_NR] = { + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].latency = 16000, + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].latency = 12000, + [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].latency = 2000, +}; static void __init halibut_init(void) { + if (socinfo_init() < 0) + BUG(); + + if (machine_is_msm7201a_ffa()) { + smc91x_resources[0].start = 0x98000300; + smc91x_resources[0].end = 0x98000400; + smc91x_resources[1].start = MSM_GPIO_TO_INT(85); + smc91x_resources[1].end = MSM_GPIO_TO_INT(85); + } + + /* All 7x01 2.0 based boards are expected to have RAM chips capable + * of 160 MHz. */ + if (cpu_is_msm7x01() + && SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 2) + halibut_clock_data.max_axi_khz = 160000; + #if defined(CONFIG_MSM_SERIAL_DEBUGGER) msm_serial_debug_init(MSM_UART3_PHYS, INT_UART3, &msm_device_uart3.dev, 1); #endif + msm_hsusb_pdata.soc_version = socinfo_get_version(); msm_acpu_clock_init(&halibut_clock_data); + msm_device_hsusb_peripheral.dev.platform_data = &msm_hsusb_pdata, + msm_device_hsusb_host.dev.platform_data = &msm_hsusb_pdata, platform_add_devices(devices, ARRAY_SIZE(devices)); + halibut_init_mmc(); + msm_pm_set_platform_data(msm_pm_data); } -static void __init halibut_fixup(struct machine_desc *desc, struct tag *tags, - char **cmdline, struct meminfo *mi) +static void __init msm_halibut_allocate_memory_regions(void) { - mi->nr_banks = 1; - mi->bank[0].start = PHYS_OFFSET; - mi->bank[0].node = PHYS_TO_NID(PHYS_OFFSET); - mi->bank[0].size = (101*1024*1024); + void *addr; + unsigned long size; + + size = MSM_PMEM_MDP_SIZE; + addr = alloc_bootmem(size); + android_pmem_pdata.start = __pa(addr); + android_pmem_pdata.size = size; + printk(KERN_INFO "allocating %lu bytes at %p (%lx physical)" + "for pmem\n", size, addr, __pa(addr)); + + size = MSM_PMEM_CAMERA_SIZE; + addr = alloc_bootmem(size); + android_pmem_camera_pdata.start = __pa(addr); + android_pmem_camera_pdata.size = size; + printk(KERN_INFO "allocating %lu bytes at %p (%lx physical)" + "for camera pmem\n", size, addr, __pa(addr)); + + size = MSM_PMEM_ADSP_SIZE; + addr = alloc_bootmem(size); + android_pmem_adsp_pdata.start = __pa(addr); + android_pmem_adsp_pdata.size = size; + printk(KERN_INFO "allocating %lu bytes at %p (%lx physical)" + "for adsp pmem\n", size, addr, __pa(addr)); + + size = MSM_PMEM_GPU1_SIZE; + addr = alloc_bootmem_aligned(size, 0x100000); + android_pmem_gpu1_pdata.start = __pa(addr); + android_pmem_gpu1_pdata.size = size; + printk(KERN_INFO "allocating %lu bytes at %p (%lx physical)" + "for gpu1 pmem\n", size, addr, __pa(addr)); + + size = MSM_FB_SIZE; + addr = alloc_bootmem(size); + msm_fb_resources[0].start = __pa(addr); + msm_fb_resources[0].end = msm_fb_resources[0].start + size - 1; + printk(KERN_INFO "allocating %lu bytes at %p (%lx physical) for fb\n", + size, addr, __pa(addr)); + } static void __init halibut_map_io(void) { + msm_shared_ram_phys = 0x01F00000; + msm_map_common_io(); - msm_clock_init(); + msm_clock_init(msm_clocks_7x01a, msm_num_clocks_7x01a); + msm_halibut_allocate_memory_regions(); } MACHINE_START(HALIBUT, "Halibut Board (QCT SURF7200A)") @@ -119,7 +747,30 @@ MACHINE_START(HALIBUT, "Halibut Board (QCT SURF7200A)") .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc, #endif .boot_params = 0x10000100, - .fixup = halibut_fixup, + .map_io = halibut_map_io, + .init_irq = halibut_init_irq, + .init_machine = halibut_init, + .timer = &msm_timer, +MACHINE_END + +MACHINE_START(MSM7201A_FFA, "QCT FFA7201A Board") +#ifdef CONFIG_MSM_DEBUG_UART + .phys_io = MSM_DEBUG_UART_PHYS, + .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc, +#endif + .boot_params = 0x10000100, + .map_io = halibut_map_io, + .init_irq = halibut_init_irq, + .init_machine = halibut_init, + .timer = &msm_timer, +MACHINE_END + +MACHINE_START(MSM7201A_SURF, "QCT SURF7201A Board") +#ifdef CONFIG_MSM_DEBUG_UART + .phys_io = MSM_DEBUG_UART_PHYS, + .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc, +#endif + .boot_params = 0x10000100, .map_io = halibut_map_io, .init_irq = halibut_init_irq, .init_machine = halibut_init, diff --git a/arch/arm/mach-msm/board-msm7x27.c b/arch/arm/mach-msm/board-msm7x27.c new file mode 100644 index 000000000000..84f9d797b8f6 --- /dev/null +++ b/arch/arm/mach-msm/board-msm7x27.c @@ -0,0 +1,1093 @@ +/* + * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * Author: Brian Swetland + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 +#ifdef CONFIG_CACHE_L2X0 +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "devices.h" +#include "socinfo.h" +#include "msm-keypad-devices.h" +#include "pm.h" + +#define MSM_PMEM_MDP_SIZE 0x800000 +#define MSM_PMEM_ADSP_SIZE 0x800000 +#define MSM_PMEM_GPU1_SIZE 0x800000 +#define MSM_FB_SIZE 0x200000 + +static struct resource smc91x_resources[] = { + [0] = { + .start = 0x9C004300, + .end = 0x9C004400, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = MSM_GPIO_TO_INT(132), + .end = MSM_GPIO_TO_INT(132), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct usb_mass_storage_platform_data usb_mass_storage_pdata = { + .nluns = 0x02, + .buf_size = 16384, + .vendor = "GOOGLE", + .product = "Mass storage", + .release = 0xffff, +}; + +static struct platform_device mass_storage_device = { + .name = "usb_mass_storage", + .id = -1, + .dev = { + .platform_data = &usb_mass_storage_pdata, + }, +}; + +static struct platform_device smc91x_device = { + .name = "smc91x", + .id = 0, + .num_resources = ARRAY_SIZE(smc91x_resources), + .resource = smc91x_resources, +}; + +static struct usb_function_map usb_functions_map[] = { + {"diag", 0}, + {"adb", 1}, + {"modem", 2}, + {"nmea", 3}, + {"mass_storage", 4}, + {"ethernet", 5}, +}; + +/* dynamic composition */ +static struct usb_composition usb_func_composition[] = { + { + .product_id = 0x9012, + .functions = 0x5, /* 0101 */ + }, + + { + .product_id = 0x9013, + .functions = 0x15, /* 10101 */ + }, + + { + .product_id = 0x9014, + .functions = 0x30, /* 110000 */ + }, + + { + .product_id = 0x9016, + .functions = 0xD, /* 01101 */ + }, + + { + .product_id = 0x9017, + .functions = 0x1D, /* 11101 */ + }, + + { + .product_id = 0xF000, + .functions = 0x10, /* 10000 */ + }, + + { + .product_id = 0xF009, + .functions = 0x20, /* 100000 */ + }, + + { + .product_id = 0x9018, + .functions = 0x1F, /* 011111 */ + }, + +}; + +static struct msm_hsusb_platform_data msm_hsusb_pdata = { + .version = 0x0100, + .phy_info = (USB_PHY_INTEGRATED | USB_PHY_MODEL_65NM), + .vendor_id = 0x5c6, + .product_name = "Qualcomm HSUSB Device", + .serial_number = "1234567890ABCDEF", + .manufacturer_name = "Qualcomm Incorporated", + .compositions = usb_func_composition, + .num_compositions = ARRAY_SIZE(usb_func_composition), + .function_map = usb_functions_map, + .num_functions = ARRAY_SIZE(usb_functions_map), +}; + +#define SND(desc, num) { .name = #desc, .id = num } +static struct snd_endpoint snd_endpoints_list[] = { + SND(HANDSET, 0), + SND(HEADSET, 2), + SND(SPEAKER, 6), + SND(BT, 12), + SND(CURRENT, 27), +}; +#undef SND + +static struct msm_snd_endpoints msm_device_snd_endpoints = { + .endpoints = snd_endpoints_list, + .num = sizeof(snd_endpoints_list) / sizeof(struct snd_endpoint) +}; + +static struct platform_device msm_device_snd = { + .name = "msm_snd", + .id = -1, + .dev = { + .platform_data = &msm_device_snd_endpoints + }, +}; +static struct android_pmem_platform_data android_pmem_pdata = { + .name = "pmem", + .no_allocator = 0, + .cached = 1, +}; + +static struct android_pmem_platform_data android_pmem_adsp_pdata = { + .name = "pmem_adsp", + .no_allocator = 0, + .cached = 0, +}; + +static struct android_pmem_platform_data android_pmem_gpu1_pdata = { + .name = "pmem_gpu1", + .no_allocator = 1, + .cached = 0, +}; + +static struct platform_device android_pmem_device = { + .name = "android_pmem", + .id = 0, + .dev = { .platform_data = &android_pmem_pdata }, +}; + +static struct platform_device android_pmem_adsp_device = { + .name = "android_pmem", + .id = 1, + .dev = { .platform_data = &android_pmem_adsp_pdata }, +}; + +static struct platform_device android_pmem_gpu1_device = { + .name = "android_pmem", + .id = 3, + .dev = { .platform_data = &android_pmem_gpu1_pdata }, +}; + +#define LCDC_CONFIG_PROC 21 +#define LCDC_UN_CONFIG_PROC 22 +#define LCDC_API_PROG 0x30000066 +#define LCDC_API_VERS 0x00010001 + +#define GPIO_OUT_132 132 +#define GPIO_OUT_131 131 +#define GPIO_OUT_103 103 +#define GPIO_OUT_102 102 +#define GPIO_OUT_88 88 + +static struct msm_rpc_endpoint *lcdc_ep; + +static int msm_fb_lcdc_config(int on) +{ + int rc = 0; + struct rpc_request_hdr hdr; + + if (on) + printk(KERN_INFO "lcdc config\n"); + else + printk(KERN_INFO "lcdc un-config\n"); + + lcdc_ep = msm_rpc_connect_compatible(LCDC_API_PROG, LCDC_API_VERS, 0); + if (IS_ERR(lcdc_ep)) { + printk(KERN_ERR "%s: msm_rpc_connect failed! rc = %ld\n", + __func__, PTR_ERR(lcdc_ep)); + return -EINVAL; + } + + rc = msm_rpc_call(lcdc_ep, + (on) ? LCDC_CONFIG_PROC : LCDC_UN_CONFIG_PROC, + &hdr, sizeof(hdr), + 5 * HZ); + if (rc) + printk(KERN_ERR + "%s: msm_rpc_call failed! rc = %d\n", __func__, rc); + + msm_rpc_close(lcdc_ep); + return rc; +} + +static int gpio_array_num[] = { + GPIO_OUT_132, /* spi_clk */ + GPIO_OUT_131, /* spi_cs */ + GPIO_OUT_103, /* spi_sdi */ + GPIO_OUT_102, /* spi_sdoi */ + GPIO_OUT_88 + }; + +static void lcdc_gordon_gpio_init(void) +{ + if (gpio_request(GPIO_OUT_132, "spi_clk")) + pr_err("failed to request gpio spi_clk\n"); + if (gpio_request(GPIO_OUT_131, "spi_cs")) + pr_err("failed to request gpio spi_cs\n"); + if (gpio_request(GPIO_OUT_103, "spi_sdi")) + pr_err("failed to request gpio spi_sdi\n"); + if (gpio_request(GPIO_OUT_102, "spi_sdoi")) + pr_err("failed to request gpio spi_sdoi\n"); + if (gpio_request(GPIO_OUT_88, "gpio_dac")) + pr_err("failed to request gpio_dac\n"); +} + +static uint32_t lcdc_gpio_table[] = { + GPIO_CFG(GPIO_OUT_132, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), + GPIO_CFG(GPIO_OUT_131, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), + GPIO_CFG(GPIO_OUT_103, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), + GPIO_CFG(GPIO_OUT_102, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), + GPIO_CFG(GPIO_OUT_88, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), +}; + +static void config_lcdc_gpio_table(uint32_t *table, int len, unsigned enable) +{ + int n, rc; + for (n = 0; n < len; n++) { + rc = gpio_tlmm_config(table[n], + enable ? GPIO_ENABLE : GPIO_DISABLE); + if (rc) { + printk(KERN_ERR "%s: gpio_tlmm_config(%#x)=%d\n", + __func__, table[n], rc); + break; + } + } +} + +static void lcdc_gordon_config_gpios(int enable) +{ + config_lcdc_gpio_table(lcdc_gpio_table, + ARRAY_SIZE(lcdc_gpio_table), enable); +} + +static struct lcdc_platform_data lcdc_pdata = { + .lcdc_gpio_config = msm_fb_lcdc_config +}; + +static struct msm_panel_common_pdata lcdc_gordon_panel_data = { + .panel_config_gpio = lcdc_gordon_config_gpios, + .gpio_num = gpio_array_num, +}; + +static struct platform_device lcdc_gordon_panel_device = { + .name = "lcdc_gordon_vga", + .id = 0, + .dev = { + .platform_data = &lcdc_gordon_panel_data, + } +}; + +static struct resource msm_fb_resources[] = { + { + .flags = IORESOURCE_DMA, + } +}; + +static int msm_fb_detect_panel(const char *name) +{ + int ret = -EPERM; + + if (machine_is_msm7x27_ffa() || machine_is_msm7x27_ffa()) { + if (!strcmp(name, "lcdc_gordon_vga")) + ret = 0; + else + ret = -ENODEV; + } + + return ret; +} + +static struct msm_fb_platform_data msm_fb_pdata = { + .detect_client = msm_fb_detect_panel, +}; + +static struct platform_device msm_fb_device = { + .name = "msm_fb", + .id = 0, + .num_resources = ARRAY_SIZE(msm_fb_resources), + .resource = msm_fb_resources, + .dev = { + .platform_data = &msm_fb_pdata, + } +}; + +#ifdef CONFIG_BT +static struct platform_device msm_bt_power_device = { + .name = "bt_power", +}; + +enum { + BT_WAKE, + BT_RFR, + BT_CTS, + BT_RX, + BT_TX, + BT_PCM_DOUT, + BT_PCM_DIN, + BT_PCM_SYNC, + BT_PCM_CLK, + BT_HOST_WAKE, +}; + +static unsigned bt_config_power_on[] = { + GPIO_CFG(42, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* WAKE */ + GPIO_CFG(43, 2, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* RFR */ + GPIO_CFG(44, 2, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), /* CTS */ + GPIO_CFG(45, 2, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), /* Rx */ + GPIO_CFG(46, 3, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* Tx */ + GPIO_CFG(68, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* PCM_DOUT */ + GPIO_CFG(69, 1, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), /* PCM_DIN */ + GPIO_CFG(70, 2, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* PCM_SYNC */ + GPIO_CFG(71, 2, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* PCM_CLK */ + GPIO_CFG(83, 0, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), /* HOST_WAKE */ +}; +static unsigned bt_config_power_off[] = { + GPIO_CFG(42, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* WAKE */ + GPIO_CFG(43, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* RFR */ + GPIO_CFG(44, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* CTS */ + GPIO_CFG(45, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* Rx */ + GPIO_CFG(46, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* Tx */ + GPIO_CFG(68, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* PCM_DOUT */ + GPIO_CFG(69, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* PCM_DIN */ + GPIO_CFG(70, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* PCM_SYNC */ + GPIO_CFG(71, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* PCM_CLK */ + GPIO_CFG(83, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* HOST_WAKE */ +}; + +static int bluetooth_power(int on) +{ + struct vreg *vreg_bt; + int pin, rc; + + printk(KERN_DEBUG "%s\n", __func__); + + /* do not have vreg bt defined, gp6 is the same */ + /* vreg_get parameter 1 (struct device *) is ignored */ + vreg_bt = vreg_get(NULL, "gp6"); + + if (IS_ERR(vreg_bt)) { + printk(KERN_ERR "%s: vreg get failed (%ld)\n", + __func__, PTR_ERR(vreg_bt)); + return PTR_ERR(vreg_bt); + } + + if (on) { + for (pin = 0; pin < ARRAY_SIZE(bt_config_power_on); pin++) { + rc = gpio_tlmm_config(bt_config_power_on[pin], + GPIO_ENABLE); + if (rc) { + printk(KERN_ERR + "%s: gpio_tlmm_config(%#x)=%d\n", + __func__, bt_config_power_on[pin], rc); + return -EIO; + } + } + + /* units of mV, steps of 50 mV */ + rc = vreg_set_level(vreg_bt, 2600); + if (rc) { + printk(KERN_ERR "%s: vreg set level failed (%d)\n", + __func__, rc); + return -EIO; + } + rc = vreg_enable(vreg_bt); + if (rc) { + printk(KERN_ERR "%s: vreg enable failed (%d)\n", + __func__, rc); + return -EIO; + } + } else { + rc = vreg_disable(vreg_bt); + if (rc) { + printk(KERN_ERR "%s: vreg disable failed (%d)\n", + __func__, rc); + return -EIO; + } + for (pin = 0; pin < ARRAY_SIZE(bt_config_power_off); pin++) { + rc = gpio_tlmm_config(bt_config_power_off[pin], + GPIO_ENABLE); + if (rc) { + printk(KERN_ERR + "%s: gpio_tlmm_config(%#x)=%d\n", + __func__, bt_config_power_off[pin], rc); + return -EIO; + } + } + } + return 0; +} + +static void __init bt_power_init(void) +{ + msm_bt_power_device.dev.platform_data = &bluetooth_power; +} +#else +#define bt_power_init(x) do {} while (0) +#endif + +static struct resource bluesleep_resources[] = { + { + .name = "gpio_host_wake", + .start = 83, + .end = 83, + .flags = IORESOURCE_IO, + }, + { + .name = "gpio_ext_wake", + .start = 42, + .end = 42, + .flags = IORESOURCE_IO, + }, + { + .name = "host_wake", + .start = MSM_GPIO_TO_INT(83), + .end = MSM_GPIO_TO_INT(83), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device msm_bluesleep_device = { + .name = "bluesleep", + .id = -1, + .num_resources = ARRAY_SIZE(bluesleep_resources), + .resource = bluesleep_resources, +}; + +static struct i2c_board_info i2c_devices[] = { + { + I2C_BOARD_INFO("mt9d112", 0x78 >> 1), + }, + { + I2C_BOARD_INFO("s5k3e2fx", 0x20 >> 1), + }, + { + I2C_BOARD_INFO("mt9p012", 0x6C >> 1), + }, + { + I2C_BOARD_INFO("mt9t013", 0x6C), + }, +}; + +static uint32_t camera_off_gpio_table[] = { + /* parallel CAMERA interfaces */ + GPIO_CFG(0, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT0 */ + GPIO_CFG(1, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT1 */ + GPIO_CFG(2, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT2 */ + GPIO_CFG(3, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT3 */ + GPIO_CFG(4, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT4 */ + GPIO_CFG(5, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT5 */ + GPIO_CFG(6, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT6 */ + GPIO_CFG(7, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT7 */ + GPIO_CFG(8, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT8 */ + GPIO_CFG(9, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT9 */ + GPIO_CFG(10, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT10 */ + GPIO_CFG(11, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT11 */ + GPIO_CFG(12, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* PCLK */ + GPIO_CFG(13, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* HSYNC_IN */ + GPIO_CFG(14, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* VSYNC_IN */ + GPIO_CFG(15, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* MCLK */ +}; + +static uint32_t camera_on_gpio_table[] = { + /* parallel CAMERA interfaces */ + GPIO_CFG(0, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT0 */ + GPIO_CFG(1, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT1 */ + GPIO_CFG(2, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT2 */ + GPIO_CFG(3, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT3 */ + GPIO_CFG(4, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT4 */ + GPIO_CFG(5, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT5 */ + GPIO_CFG(6, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT6 */ + GPIO_CFG(7, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT7 */ + GPIO_CFG(8, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT8 */ + GPIO_CFG(9, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT9 */ + GPIO_CFG(10, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT10 */ + GPIO_CFG(11, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT11 */ + GPIO_CFG(12, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_16MA), /* PCLK */ + GPIO_CFG(13, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* HSYNC_IN */ + GPIO_CFG(14, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* VSYNC_IN */ + GPIO_CFG(15, 1, GPIO_OUTPUT, GPIO_PULL_DOWN, GPIO_16MA), /* MCLK */ +}; + +static void config_gpio_table(uint32_t *table, int len) +{ + int n, rc; + for (n = 0; n < len; n++) { + rc = gpio_tlmm_config(table[n], GPIO_ENABLE); + if (rc) { + printk(KERN_ERR "%s: gpio_tlmm_config(%#x)=%d\n", + __func__, table[n], rc); + break; + } + } +} + +static void config_camera_on_gpios(void) +{ + config_gpio_table(camera_on_gpio_table, + ARRAY_SIZE(camera_on_gpio_table)); +} + +static void config_camera_off_gpios(void) +{ + config_gpio_table(camera_off_gpio_table, + ARRAY_SIZE(camera_off_gpio_table)); +} + +#define MSM_PROBE_INIT(name) name##_probe_init +static struct msm_camera_sensor_info msm_camera_sensor[] = { + { + .sensor_reset = 89, + .sensor_pwd = 85, + .vcm_pwd = 0, + .sensor_name = "mt9d112", + .flash_type = MSM_CAMERA_FLASH_NONE, +#ifdef CONFIG_MSM_CAMERA + .sensor_probe = MSM_PROBE_INIT(mt9d112), +#endif + }, + { + .sensor_reset = 89, + .sensor_pwd = 85, + .vcm_pwd = 0, + .sensor_name = "s5k3e2fx", + .flash_type = MSM_CAMERA_FLASH_NONE, +#ifdef CONFIG_MSM_CAMERA + .sensor_probe = MSM_PROBE_INIT(s5k3e2fx), +#endif + }, + { + .sensor_reset = 89, + .sensor_pwd = 85, + .vcm_pwd = 88, + .sensor_name = "mt9p012", + .flash_type = MSM_CAMERA_FLASH_LED, +#ifdef CONFIG_MSM_CAMERA + .sensor_probe = MSM_PROBE_INIT(mt9p012), +#endif + }, + { + .sensor_reset = 89, + .sensor_pwd = 85, + .vcm_pwd = 0, + .sensor_name = "mt9t013", + .flash_type = MSM_CAMERA_FLASH_NONE, +#ifdef CONFIG_MSM_CAMERA + .sensor_probe = MSM_PROBE_INIT(mt9t013), +#endif + }, +}; +#undef MSM_PROBE_INIT + +static struct msm_camera_device_platform_data msm_camera_device_data = { + .camera_gpio_on = config_camera_on_gpios, + .camera_gpio_off = config_camera_off_gpios, + .snum = ARRAY_SIZE(msm_camera_sensor), + .sinfo = &msm_camera_sensor[0], + .ioext.mdcphy = MSM_MDC_PHYS, + .ioext.mdcsz = MSM_MDC_SIZE, + .ioext.appphy = MSM_CLK_CTL_PHYS, + .ioext.appsz = MSM_CLK_CTL_SIZE, +}; + +static void __init msm_camera_add_device(void) +{ + msm_camera_register_device(NULL, 0, &msm_camera_device_data); + config_camera_off_gpios(); +} + +static struct platform_device *devices[] __initdata = { +#if !defined(CONFIG_MSM_SERIAL_DEBUGGER) + &msm_device_uart3, +#endif + &msm_device_smd, + &msm_device_nand, + &msm_device_hsusb_otg, + &msm_device_hsusb_host, + &msm_device_hsusb_peripheral, + &mass_storage_device, + &msm_device_i2c, + &smc91x_device, + &msm_device_tssc, + &android_pmem_device, + &android_pmem_adsp_device, + &android_pmem_gpu1_device, + &msm_fb_device, + &lcdc_gordon_panel_device, + &msm_device_uart_dm1, +#ifdef CONFIG_BT + &msm_bt_power_device, +#endif + &msm_device_snd, + &msm_bluesleep_device, +}; + +static struct msm_panel_common_pdata mdp_pdata = { + .gpio = 97, +}; + +static void __init msm_fb_add_devices(void) +{ + msm_fb_register_device("mdp", &mdp_pdata); + msm_fb_register_device("pmdh", 0); + msm_fb_register_device("lcdc", &lcdc_pdata); +} + +extern struct sys_timer msm_timer; + +static void __init msm7x27_init_irq(void) +{ + msm_init_irq(); +} + +static struct msm_acpu_clock_platform_data msm7x27_clock_data = { + .acpu_switch_time_us = 50, + .max_speed_delta_khz = 256000, + .vdd_switch_time_us = 62, + .power_collapse_khz = 19200000, + .wait_for_irq_khz = 128000000, + .max_axi_khz = 128000, +}; + +void msm_serial_debug_init(unsigned int base, int irq, + struct device *clk_device, int signal_irq); + +static void sdcc_gpio_init(void) +{ + /* SDC1 GPIOs */ +#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT + if (gpio_request(51, "sdc1_data_3")) + pr_err("failed to request gpio sdc1_data_3\n"); + if (gpio_request(52, "sdc1_data_2")) + pr_err("failed to request gpio sdc1_data_2\n"); + if (gpio_request(53, "sdc1_data_1")) + pr_err("failed to request gpio sdc1_data_1\n"); + if (gpio_request(54, "sdc1_data_0")) + pr_err("failed to request gpio sdc1_data_0\n"); + if (gpio_request(55, "sdc1_cmd")) + pr_err("failed to request gpio sdc1_cmd\n"); + if (gpio_request(56, "sdc1_clk")) + pr_err("failed to request gpio sdc1_clk\n"); +#endif + + if (machine_is_msm7x27_ffa() || machine_is_msm7x27_ffa()) + return; + + /* SDC2 GPIOs */ +#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT + if (gpio_request(62, "sdc2_clk")) + pr_err("failed to request gpio sdc2_clk\n"); + if (gpio_request(63, "sdc2_cmd")) + pr_err("failed to request gpio sdc2_cmd\n"); + if (gpio_request(64, "sdc2_data_3")) + pr_err("failed to request gpio sdc2_data_3\n"); + if (gpio_request(65, "sdc2_data_2")) + pr_err("failed to request gpio sdc2_data_2\n"); + if (gpio_request(66, "sdc2_data_1")) + pr_err("failed to request gpio sdc2_data_1\n"); + if (gpio_request(67, "sdc2_data_0")) + pr_err("failed to request gpio sdc2_data_0\n"); +#endif + + /* SDC3 GPIOs */ +#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT + if (gpio_request(88, "sdc3_clk")) + pr_err("failed to request gpio sdc3_clk\n"); + if (gpio_request(89, "sdc3_cmd")) + pr_err("failed to request gpio sdc3_cmd\n"); + if (gpio_request(90, "sdc3_data_3")) + pr_err("failed to request gpio sdc3_data_3\n"); + if (gpio_request(91, "sdc3_data_2")) + pr_err("failed to request gpio sdc3_data_2\n"); + if (gpio_request(92, "sdc3_data_1")) + pr_err("failed to request gpio sdc3_data_1\n"); + if (gpio_request(93, "sdc3_data_0")) + pr_err("failed to request gpio sdc3_data_0\n"); +#endif + + /* SDC4 GPIOs */ +#ifdef CONFIG_MMC_MSM_SDC4_SUPPORT + if (gpio_request(19, "sdc4_data_3")) + pr_err("failed to request gpio sdc4_data_3\n"); + if (gpio_request(20, "sdc4_data_2")) + pr_err("failed to request gpio sdc4_data_2\n"); + if (gpio_request(21, "sdc4_data_1")) + pr_err("failed to request gpio sdc4_data_1\n"); + if (gpio_request(107, "sdc4_cmd")) + pr_err("failed to request gpio sdc4_cmd\n"); + if (gpio_request(108, "sdc4_data_0")) + pr_err("failed to request gpio sdc4_data_0\n"); + if (gpio_request(109, "sdc4_clk")) + pr_err("failed to request gpio sdc4_clk\n"); +#endif +} + +static unsigned sdcc_cfg_data[][6] = { + /* SDC1 configs */ + { + GPIO_CFG(51, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(52, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(53, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(54, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(55, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(56, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA), + }, + /* SDC2 configs */ + { + GPIO_CFG(62, 2, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA), + GPIO_CFG(63, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(64, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(65, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(66, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(67, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + }, + /* SDC3 configs */ + { + GPIO_CFG(88, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA), + GPIO_CFG(89, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(90, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(91, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(92, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(93, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + }, + /* SDC4 configs */ + { + GPIO_CFG(19, 3, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(20, 3, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(21, 4, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(107, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(108, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(109, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA), + } +}; + +static unsigned long vreg_sts, gpio_sts; +static struct mpp *mpp_mmc; +static struct vreg *vreg_mmc; + +static void msm_sdcc_setup_gpio(int dev_id, unsigned int enable) +{ + int i, rc; + + if (!(test_bit(dev_id, &gpio_sts)^enable)) + return; + + if (enable) + set_bit(dev_id, &gpio_sts); + else + clear_bit(dev_id, &gpio_sts); + + for (i = 0; i < ARRAY_SIZE(sdcc_cfg_data[dev_id - 1]); i++) { + rc = gpio_tlmm_config(sdcc_cfg_data[dev_id - 1][i], + enable ? GPIO_ENABLE : GPIO_DISABLE); + if (rc) + printk(KERN_ERR "%s: gpio_tlmm_config(%#x)=%d\n", + __func__, sdcc_cfg_data[dev_id - 1][i], rc); + } +} + +static uint32_t msm_sdcc_setup_power(struct device *dv, unsigned int vdd) +{ + int rc = 0; + struct platform_device *pdev; + + pdev = container_of(dv, struct platform_device, dev); + msm_sdcc_setup_gpio(pdev->id, !!vdd); + + if (vdd == 0) { + if (!vreg_sts) + return 0; + + clear_bit(pdev->id, &vreg_sts); + + if (!vreg_sts) { + if (machine_is_msm7x27_ffa()) { + rc = mpp_config_digital_out(mpp_mmc, + MPP_CFG(MPP_DLOGIC_LVL_MSMP, + MPP_DLOGIC_OUT_CTRL_LOW)); + } else + rc = vreg_disable(vreg_mmc); + if (rc) + printk(KERN_ERR "%s: return val: %d \n", + __func__, rc); + } + return 0; + } + + if (!vreg_sts) { + if (machine_is_msm7x27_ffa()) { + rc = mpp_config_digital_out(mpp_mmc, + MPP_CFG(MPP_DLOGIC_LVL_MSMP, + MPP_DLOGIC_OUT_CTRL_HIGH)); + } else { + rc = vreg_set_level(vreg_mmc, 2850); + if (!rc) + rc = vreg_enable(vreg_mmc); + } + if (rc) + printk(KERN_ERR "%s: return val: %d \n", + __func__, rc); + } + set_bit(pdev->id, &vreg_sts); + return 0; +} + +static struct mmc_platform_data msm7x27_sdcc_data = { + .ocr_mask = MMC_VDD_28_29, + .translate_vdd = msm_sdcc_setup_power, +}; + +static void __init msm7x27_init_mmc(void) +{ + if (machine_is_msm7x27_ffa()) { + mpp_mmc = mpp_get(NULL, "mpp3"); + if (!mpp_mmc) { + printk(KERN_ERR "%s: mpp get failed (%ld)\n", + __func__, PTR_ERR(vreg_mmc)); + return; + } + } else { + vreg_mmc = vreg_get(NULL, "mmc"); + if (IS_ERR(vreg_mmc)) { + printk(KERN_ERR "%s: vreg get failed (%ld)\n", + __func__, PTR_ERR(vreg_mmc)); + return; + } + } + + sdcc_gpio_init(); +#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT + msm_add_sdcc(1, &msm7x27_sdcc_data); +#endif + + if (machine_is_msm7x27_surf()) { +#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT + msm_add_sdcc(2, &msm7x27_sdcc_data); +#endif +#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT + msm_add_sdcc(3, &msm7x27_sdcc_data); +#endif +#ifdef CONFIG_MMC_MSM_SDC4_SUPPORT + msm_add_sdcc(4, &msm7x27_sdcc_data); +#endif + } +} + +static struct msm_i2c_platform_data msm_i2c_pdata = { + .clk_freq = 100000, +}; + +static void __init msm_device_i2c_init(void) +{ + msm_device_i2c.dev.platform_data = &msm_i2c_pdata; +} + +static struct msm_pm_platform_data msm7x27_pm_data[MSM_PM_SLEEP_MODE_NR] = { + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].supported = 1, + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].suspend_enabled = 1, + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].idle_enabled = 1, + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].latency = 16000, + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].residency = 20000, + + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].supported = 1, + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].suspend_enabled = 1, + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].idle_enabled = 1, + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].latency = 12000, + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].residency = 20000, + + [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].supported = 1, + [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].suspend_enabled + = 1, + [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].idle_enabled = 1, + [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].latency = 2000, + [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].residency = 0, +}; + +static void __init msm7x27_init(void) +{ + if (socinfo_init() < 0) + BUG(); + +#if defined(CONFIG_MSM_SERIAL_DEBUGGER) + msm_serial_debug_init(MSM_UART3_PHYS, INT_UART3, + &msm_device_uart3.dev, 1); +#endif + if (machine_is_msm7x27_ffa()) { + smc91x_resources[0].start = 0x98000300; + smc91x_resources[0].end = 0x98000400; + smc91x_resources[1].start = MSM_GPIO_TO_INT(85); + smc91x_resources[1].end = MSM_GPIO_TO_INT(85); + if (gpio_tlmm_config(GPIO_CFG(85, 0, + GPIO_INPUT, + GPIO_PULL_DOWN, + GPIO_2MA), + GPIO_ENABLE)) { + printk(KERN_ERR + "%s: Err: Config GPIO-85 INT\n", + __func__); + } + + msm7x27_clock_data.max_axi_khz = 160000; + } + + if (cpu_is_msm7x27()) + msm7x27_clock_data.max_axi_khz = 200000; + + msm_acpu_clock_init(&msm7x27_clock_data); + msm_device_hsusb_peripheral.dev.platform_data = &msm_hsusb_pdata; + msm_device_hsusb_host.dev.platform_data = &msm_hsusb_pdata; + platform_add_devices(devices, ARRAY_SIZE(devices)); + msm_camera_add_device(); + msm_device_i2c_init(); + i2c_register_board_info(0, i2c_devices, ARRAY_SIZE(i2c_devices)); + +#ifdef CONFIG_SURF_FFA_GPIO_KEYPAD + if (machine_is_msm7x27_ffa()) + platform_device_register(&keypad_device_7k_ffa); + else + platform_device_register(&keypad_device_surf); +#endif + lcdc_gordon_gpio_init(); + msm_fb_add_devices(); + msm7x27_init_mmc(); + bt_power_init(); + + if (cpu_is_msm7x27()) + msm_pm_set_platform_data(msm7x27_pm_data); + else + msm_pm_set_platform_data(msm7x27_pm_data); +} + +static void __init msm_msm7x27_allocate_memory_regions(void) +{ + void *addr; + unsigned long size; + + size = MSM_PMEM_MDP_SIZE; + addr = alloc_bootmem(size); + android_pmem_pdata.start = __pa(addr); + android_pmem_pdata.size = size; + printk(KERN_INFO "allocating %lu bytes at %p (%lx physical)" + "for pmem\n", size, addr, __pa(addr)); + + size = MSM_PMEM_ADSP_SIZE; + addr = alloc_bootmem(size); + android_pmem_adsp_pdata.start = __pa(addr); + android_pmem_adsp_pdata.size = size; + printk(KERN_INFO "allocating %lu bytes at %p (%lx physical)" + "for adsp pmem\n", size, addr, __pa(addr)); + + size = MSM_PMEM_GPU1_SIZE; + addr = alloc_bootmem_aligned(size, 0x100000); + android_pmem_gpu1_pdata.start = __pa(addr); + android_pmem_gpu1_pdata.size = size; + printk(KERN_INFO "allocating %lu bytes at %p (%lx physical)" + "for gpu1 pmem\n", size, addr, __pa(addr)); + + size = MSM_FB_SIZE; + addr = alloc_bootmem(size); + msm_fb_resources[0].start = __pa(addr); + msm_fb_resources[0].end = msm_fb_resources[0].start + size - 1; + printk(KERN_INFO "allocating %lu bytes at %p (%lx physical) for fb\n", + size, addr, __pa(addr)); +} + +static void __init msm7x27_map_io(void) +{ + msm_map_common_io(); + /* Technically dependent on the SoC but using machine_is + * macros since socinfo is not available this early and there + * are plans to restructure the code which will eliminate the + * need for socinfo. + */ + if (machine_is_msm7x27_surf() || machine_is_msm7x27_ffa()) + msm_clock_init(msm_clocks_7x27, msm_num_clocks_7x27); + else + msm_clock_init(msm_clocks_7x27, msm_num_clocks_7x27); + msm_msm7x27_allocate_memory_regions(); + +#ifdef CONFIG_CACHE_L2X0 + if (machine_is_msm7x27_surf() || machine_is_msm7x27_ffa()) { + /* 7x27 has 256KB L2 cache: + 64Kb/Way and 4-Way Associativity; + R/W latency: 3 cycles; + evmon/parity/share disabled. */ + l2x0_init(MSM_L2CC_BASE, 0x00068012, 0xfe000000); + } +#endif +} + +MACHINE_START(MSM7X27_SURF, "QCT MSM7x27 SURF") +#ifdef CONFIG_MSM_DEBUG_UART + .phys_io = MSM_DEBUG_UART_PHYS, + .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc, +#endif + .boot_params = 0x00200100, + .map_io = msm7x27_map_io, + .init_irq = msm7x27_init_irq, + .init_machine = msm7x27_init, + .timer = &msm_timer, +MACHINE_END + +MACHINE_START(MSM7X27_FFA, "QCT MSM7x27 FFA") +#ifdef CONFIG_MSM_DEBUG_UART + .phys_io = MSM_DEBUG_UART_PHYS, + .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc, +#endif + .boot_params = 0x00200100, + .map_io = msm7x27_map_io, + .init_irq = msm7x27_init_irq, + .init_machine = msm7x27_init, + .timer = &msm_timer, +MACHINE_END diff --git a/arch/arm/mach-msm/board-qsd8x50.c b/arch/arm/mach-msm/board-qsd8x50.c new file mode 100644 index 000000000000..4bfd7ef84245 --- /dev/null +++ b/arch/arm/mach-msm/board-qsd8x50.c @@ -0,0 +1,1471 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "devices.h" +#include "timer.h" +#include "socinfo.h" +#include "msm-keypad-devices.h" +#include "pm.h" + +#define TOUCHPAD_SUSPEND 34 +#define TOUCHPAD_IRQ 38 + +#define MSM_PMEM_MDP_SIZE 0x800000 +#define MSM_PMEM_CAMERA_SIZE 0xa00000 +#define MSM_PMEM_ADSP_SIZE 0x1100000 +#define MSM_PMEM_GPU1_SIZE 0x800000 +#define MSM_FB_SIZE 0x500000 +#define MSM_AUDIO_SIZE 0x200000 +#define MSM_GPU_PHYS_SIZE SZ_2M + +#define MSM_SMI_BASE 0x2b00000 +#define MSM_SMI_SIZE 0x1500000 + +#define MSM_FB_BASE MSM_SMI_BASE +#define MSM_GPU_PHYS_BASE (MSM_FB_BASE + MSM_FB_SIZE) +#define MSM_PMEM_GPU0_BASE (MSM_GPU_PHYS_BASE + MSM_GPU_PHYS_SIZE) +#define MSM_PMEM_GPU0_SIZE (MSM_SMI_SIZE - MSM_FB_SIZE - MSM_GPU_PHYS_SIZE) + +static struct resource smc91x_resources[] = { + [0] = { + .flags = IORESOURCE_MEM, + }, + [1] = { + .flags = IORESOURCE_IRQ, + }, +}; + +static struct usb_mass_storage_platform_data usb_mass_storage_pdata = { + .nluns = 0x02, + .buf_size = 16384, + .vendor = "GOOGLE", + .product = "Mass storage", + .release = 0xffff, +}; + +static struct platform_device mass_storage_device = { + .name = "usb_mass_storage", + .id = -1, + .dev = { + .platform_data = &usb_mass_storage_pdata, + }, +}; + +static struct platform_device smc91x_device = { + .name = "smc91x", + .id = 0, + .num_resources = ARRAY_SIZE(smc91x_resources), + .resource = smc91x_resources, +}; +static struct usb_function_map usb_functions_map[] = { + {"diag", 0}, + {"adb", 1}, + {"modem", 2}, + {"nmea", 3}, + {"mass_storage", 4}, + {"ethernet", 5}, +}; + +/* dynamic composition */ +static struct usb_composition usb_func_composition[] = { + { + .product_id = 0x9012, + .functions = 0x5, /* 0101 */ + }, + + { + .product_id = 0x9013, + .functions = 0x15, /* 10101 */ + }, + + { + .product_id = 0x9014, + .functions = 0x30, /* 110000 */ + }, + + { + .product_id = 0x9015, + .functions = 0x12, /* 10010 */ + }, + + { + .product_id = 0x9016, + .functions = 0xD, /* 01101 */ + }, + + { + .product_id = 0x9017, + .functions = 0x1D, /* 11101 */ + }, + + { + .product_id = 0xF000, + .functions = 0x10, /* 10000 */ + }, + + { + .product_id = 0xF009, + .functions = 0x20, /* 100000 */ + }, + + { + .product_id = 0x9018, + .functions = 0x1F, /* 011111 */ + }, + + { + .product_id = 0x901A, + .functions = 0x0F, /* 01111 */ + }, +}; +static struct msm_hsusb_platform_data msm_hsusb_pdata = { + .version = 0x0100, + .phy_info = (USB_PHY_INTEGRATED | USB_PHY_MODEL_180NM), + .vendor_id = 0x5c6, + .product_name = "Qualcomm HSUSB Device", + .serial_number = "1234567890ABCDEF", + .manufacturer_name = "Qualcomm Incorporated", + .compositions = usb_func_composition, + .num_compositions = ARRAY_SIZE(usb_func_composition), + .function_map = usb_functions_map, + .num_functions = ARRAY_SIZE(usb_functions_map), + .config_gpio = NULL, +}; + +static struct android_pmem_platform_data android_pmem_pdata = { + .name = "pmem", + .size = MSM_PMEM_MDP_SIZE, + .no_allocator = 0, + .cached = 1, +}; + +static struct android_pmem_platform_data android_pmem_adsp_pdata = { + .name = "pmem_adsp", + .size = MSM_PMEM_ADSP_SIZE, + .no_allocator = 0, + .cached = 0, +}; + +static struct android_pmem_platform_data android_pmem_gpu0_pdata = { + .name = "pmem_gpu0", + .start = MSM_PMEM_GPU0_BASE, + .size = MSM_PMEM_GPU0_SIZE, + .no_allocator = 0, + .cached = 0, +}; + +static struct android_pmem_platform_data android_pmem_gpu1_pdata = { + .name = "pmem_gpu1", + .no_allocator = 0, + .cached = 0, +}; + +static struct android_pmem_platform_data android_pmem_camera_pdata = { + .name = "pmem_camera", + .size = MSM_PMEM_CAMERA_SIZE, + .no_allocator = 1, + .cached = 1, +}; + +static struct platform_device android_pmem_device = { + .name = "android_pmem", + .id = 0, + .dev = { .platform_data = &android_pmem_pdata }, +}; + +static struct platform_device android_pmem_adsp_device = { + .name = "android_pmem", + .id = 1, + .dev = { .platform_data = &android_pmem_adsp_pdata }, +}; + +static struct platform_device android_pmem_gpu0_device = { + .name = "android_pmem", + .id = 2, + .dev = { .platform_data = &android_pmem_gpu0_pdata }, +}; + +static struct platform_device android_pmem_gpu1_device = { + .name = "android_pmem", + .id = 3, + .dev = { .platform_data = &android_pmem_gpu1_pdata }, +}; +static struct platform_device android_pmem_camera_device = { + .name = "android_pmem", + .id = 4, + .dev = { .platform_data = &android_pmem_camera_pdata }, + }; + +static struct resource msm_fb_resources[] = { + { + .flags = IORESOURCE_DMA, + } +}; + +static int msm_fb_detect_panel(const char *name) +{ + int ret = -EPERM; + + if (machine_is_qsd8x50_ffa()) { + if (!strncmp(name, "mddi_toshiba_wvga_pt", 20)) + ret = 0; + else + ret = -ENODEV; + } + + return ret; +} + +static struct msm_fb_platform_data msm_fb_pdata = { + .detect_client = msm_fb_detect_panel, +}; + +static struct platform_device msm_fb_device = { + .name = "msm_fb", + .id = 0, + .num_resources = ARRAY_SIZE(msm_fb_resources), + .resource = msm_fb_resources, + .dev = { + .platform_data = &msm_fb_pdata, + } +}; + +static struct resource qsd_spi_resources[] = { + { + .name = "spi_irq_in", + .start = INT_SPI_INPUT, + .end = INT_SPI_INPUT, + .flags = IORESOURCE_IRQ, + }, + { + .name = "spi_irq_out", + .start = INT_SPI_OUTPUT, + .end = INT_SPI_OUTPUT, + .flags = IORESOURCE_IRQ, + }, + { + .name = "spi_irq_err", + .start = INT_SPI_ERROR, + .end = INT_SPI_ERROR, + .flags = IORESOURCE_IRQ, + }, + { + .name = "spi_base", + .start = 0xA1200000, + .end = 0xA1200000 + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + { + .name = "spi_clk", + .start = 17, + .end = 1, + .flags = IORESOURCE_IRQ, + }, + { + .name = "spi_mosi", + .start = 18, + .end = 1, + .flags = IORESOURCE_IRQ, + }, + { + .name = "spi_miso", + .start = 19, + .end = 1, + .flags = IORESOURCE_IRQ, + }, + { + .name = "spi_cs0", + .start = 20, + .end = 1, + .flags = IORESOURCE_IRQ, + }, + { + .name = "spi_pwr", + .start = 21, + .end = 0, + .flags = IORESOURCE_IRQ, + }, + { + .name = "spi_irq_cs0", + .start = 22, + .end = 0, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device qsd_device_spi = { + .name = "spi_qsd", + .id = 0, + .num_resources = ARRAY_SIZE(qsd_spi_resources), + .resource = qsd_spi_resources, +}; + +static struct spi_board_info msm_spi_board_info[] __initdata = { + { + .modalias = "bma150", + .mode = SPI_MODE_3, + .irq = MSM_GPIO_TO_INT(22), + .bus_num = 0, + .chip_select = 0, + .max_speed_hz = 10000000, + } +}; + +static int mddi_toshiba_pmic_bl(int level) +{ + int ret = -EPERM; + + if (machine_is_qsd8x50_ffa()) { + ret = set_led_intensity(LED_LCD, level); + + if (ret) + printk(KERN_WARNING "%s: can't set lcd backlight!\n", + __func__); + } + + return ret; +} + +static struct msm_panel_common_pdata mddi_toshiba_pdata = { + .pmic_backlight = mddi_toshiba_pmic_bl, +}; + +static struct platform_device mddi_toshiba_device = { + .name = "mddi_toshiba", + .id = 0, + .dev = { + .platform_data = &mddi_toshiba_pdata, + } +}; + +static void msm_fb_vreg_config(const char *name, int on) +{ + struct vreg *vreg; + int ret = 0; + + vreg = vreg_get(NULL, name); + if (IS_ERR(vreg)) { + printk(KERN_ERR "%s: vreg_get(%s) failed (%ld)\n", + __func__, name, PTR_ERR(vreg)); + return; + } + + ret = (on) ? vreg_enable(vreg) : vreg_disable(vreg); + if (ret) + printk(KERN_ERR "%s: %s(%s) failed!\n", + __func__, (on) ? "vreg_enable" : "vreg_disable", name); +} + +#define MDDI_RST_OUT_GPIO 100 + +static void msm_fb_mddi_power_save(int on) +{ + int flag_on = !!on; + + if (!flag_on && machine_is_qsd8x50_ffa()) { + gpio_set_value(MDDI_RST_OUT_GPIO, 0); + mdelay(1); + } + + msm_fb_vreg_config("gp5", flag_on); + msm_fb_vreg_config("msme2", !flag_on); + msm_fb_vreg_config("boost", flag_on); + + if (flag_on && machine_is_qsd8x50_ffa()) { + gpio_set_value(MDDI_RST_OUT_GPIO, 0); + mdelay(1); + gpio_set_value(MDDI_RST_OUT_GPIO, 1); + gpio_set_value(MDDI_RST_OUT_GPIO, 1); + mdelay(1); + } +} + +static int msm_fb_mddi_sel_clk(u32 *clk_rate) +{ + *clk_rate *= 2; + return 0; +} + +static struct mddi_platform_data mddi_pdata = { + .mddi_power_save = msm_fb_mddi_power_save, + .mddi_sel_clk = msm_fb_mddi_sel_clk, +}; + +static struct msm_panel_common_pdata mdp_pdata = { + .gpio = 98, +}; + +static void __init msm_fb_add_devices(void) +{ + msm_fb_register_device("mdp", &mdp_pdata); + msm_fb_register_device("pmdh", &mddi_pdata); + msm_fb_register_device("emdh", &mddi_pdata); + msm_fb_register_device("tvenc", 0); + msm_fb_register_device("lcdc", 0); +} + +static struct resource msm_audio_resources[] = { + { + .flags = IORESOURCE_DMA, + }, + { + .name = "aux_pcm_dout", + .start = 68, + .end = 68, + .flags = IORESOURCE_IO, + }, + { + .name = "aux_pcm_din", + .start = 69, + .end = 69, + .flags = IORESOURCE_IO, + }, + { + .name = "aux_pcm_syncout", + .start = 70, + .end = 70, + .flags = IORESOURCE_IO, + }, + { + .name = "aux_pcm_clkin_a", + .start = 71, + .end = 71, + .flags = IORESOURCE_IO, + }, + { + .name = "sdac_din", + .start = 144, + .end = 144, + .flags = IORESOURCE_IO, + }, + { + .name = "sdac_dout", + .start = 145, + .end = 145, + .flags = IORESOURCE_IO, + }, + { + .name = "sdac_wsout", + .start = 143, + .end = 143, + .flags = IORESOURCE_IO, + }, + { + .name = "cc_i2s_clk", + .start = 142, + .end = 142, + .flags = IORESOURCE_IO, + }, + { + .name = "audio_master_clkout", + .start = 146, + .end = 146, + .flags = IORESOURCE_IO, + }, + +}; + +static unsigned audio_gpio_on[] = { + GPIO_CFG(68, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* PCM_DOUT */ + GPIO_CFG(69, 1, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), /* PCM_DIN */ + GPIO_CFG(70, 2, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* PCM_SYNC */ + GPIO_CFG(71, 2, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* PCM_CLK */ + GPIO_CFG(142, 2, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* CC_I2S_CLK */ + GPIO_CFG(143, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* SADC_WSOUT */ + GPIO_CFG(144, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* SADC_DIN */ + GPIO_CFG(145, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* SDAC_DOUT */ + GPIO_CFG(146, 2, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* MA_CLK_OUT */ +}; + +static void __init audio_gpio_init(void) +{ + int pin, rc; + + for (pin = 0; pin < ARRAY_SIZE(audio_gpio_on); pin++) { + rc = gpio_tlmm_config(audio_gpio_on[pin], + GPIO_ENABLE); + if (rc) { + printk(KERN_ERR + "%s: gpio_tlmm_config(%#x)=%d\n", + __func__, audio_gpio_on[pin], rc); + return; + } + } +} + +static struct platform_device msm_audio_device = { + .name = "msm_audio", + .id = 0, + .num_resources = ARRAY_SIZE(msm_audio_resources), + .resource = msm_audio_resources, +}; + +static struct resource bluesleep_resources[] = { + { + .name = "gpio_host_wake", + .start = 21, + .end = 21, + .flags = IORESOURCE_IO, + }, + { + .name = "gpio_ext_wake", + .start = 19, + .end = 19, + .flags = IORESOURCE_IO, + }, + { + .name = "host_wake", + .start = MSM_GPIO_TO_INT(21), + .end = MSM_GPIO_TO_INT(21), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device msm_bluesleep_device = { + .name = "bluesleep", + .id = -1, + .num_resources = ARRAY_SIZE(bluesleep_resources), + .resource = bluesleep_resources, +}; + +#ifdef CONFIG_BT +static struct platform_device msm_bt_power_device = { + .name = "bt_power", +}; + +enum { + BT_SYSRST, + BT_WAKE, + BT_HOST_WAKE, + BT_PWR_EN, + BT_RFR, + BT_CTS, + BT_RX, + BT_TX, + BT_PCM_DOUT, + BT_PCM_DIN, + BT_PCM_SYNC, + BT_PCM_CLK, +}; + +static unsigned bt_config_power_on[] = { + GPIO_CFG(18, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* SYSRST */ + GPIO_CFG(19, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* WAKE */ + GPIO_CFG(21, 0, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), /* HOST_WAKE */ + GPIO_CFG(22, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* PWR_EN */ + GPIO_CFG(43, 2, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* RFR */ + GPIO_CFG(44, 2, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), /* CTS */ + GPIO_CFG(45, 2, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), /* Rx */ + GPIO_CFG(46, 2, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* Tx */ +}; +static unsigned bt_config_power_off[] = { + GPIO_CFG(18, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* SYSRST */ + GPIO_CFG(19, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* WAKE */ + GPIO_CFG(21, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* HOST_WAKE */ + GPIO_CFG(22, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* PWR_EN */ + GPIO_CFG(43, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* RFR */ + GPIO_CFG(44, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* CTS */ + GPIO_CFG(45, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* Rx */ + GPIO_CFG(46, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* Tx */ +}; + +static int bluetooth_power(int on) +{ + int pin, rc; + + printk(KERN_DEBUG "%s\n", __func__); + + if (on) { + for (pin = 0; pin < ARRAY_SIZE(bt_config_power_on); pin++) { + rc = gpio_tlmm_config(bt_config_power_on[pin], + GPIO_ENABLE); + if (rc) { + printk(KERN_ERR + "%s: gpio_tlmm_config(%#x)=%d\n", + __func__, bt_config_power_on[pin], rc); + return -EIO; + } + } + + gpio_set_value(22, on); /* PWR_EN */ + gpio_set_value(18, on); /* SYSRST */ + + } else { + gpio_set_value(18, on); /* SYSRST */ + gpio_set_value(22, on); /* PWR_EN */ + + for (pin = 0; pin < ARRAY_SIZE(bt_config_power_off); pin++) { + rc = gpio_tlmm_config(bt_config_power_off[pin], + GPIO_ENABLE); + if (rc) { + printk(KERN_ERR + "%s: gpio_tlmm_config(%#x)=%d\n", + __func__, bt_config_power_off[pin], rc); + return -EIO; + } + } + + } + + return 0; +} + +static void __init bt_power_init(void) +{ + msm_bt_power_device.dev.platform_data = &bluetooth_power; +} +#else +#define bt_power_init(x) do {} while (0) +#endif + +static struct resource kgsl_resources[] = { + { + .name = "kgsl_reg_memory", + .start = 0xA0000000, + .end = 0xA001ffff, + .flags = IORESOURCE_MEM, + }, + { + .name = "kgsl_phys_memory", + .start = MSM_GPU_PHYS_BASE, + .end = MSM_GPU_PHYS_BASE + MSM_GPU_PHYS_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = INT_GRAPHICS, + .end = INT_GRAPHICS, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device msm_device_kgsl = { + .name = "kgsl", + .id = -1, + .num_resources = ARRAY_SIZE(kgsl_resources), + .resource = kgsl_resources, +}; + +static struct platform_device msm_device_pmic_leds = { + .name = "pmic-leds", + .id = -1, +}; + +static struct platform_device *devices[] __initdata = { + &msm_fb_device, + &mddi_toshiba_device, + &smc91x_device, + &msm_device_smd, + &android_pmem_device, + &android_pmem_adsp_device, + &android_pmem_gpu0_device, + &android_pmem_gpu1_device, + &msm_device_nand, + &msm_device_i2c, + &qsd_device_spi, + &msm_device_hsusb_otg, + &msm_device_hsusb_host, + &msm_device_hsusb_peripheral, + &mass_storage_device, + &msm_device_tssc, + &android_pmem_camera_device, + &msm_audio_device, + &msm_device_uart_dm1, + &msm_bluesleep_device, +#ifdef CONFIG_BT + &msm_bt_power_device, +#endif +#if !defined(CONFIG_MSM_SERIAL_DEBUGGER) + &msm_device_uart3, +#endif + &msm_device_pmic_leds, + &msm_device_kgsl, +}; + +/* The TPS65023 PMIC outputs 1.225V as default at boot */ +#define TPS65023_DEFAULT_DCDC1 1225 +#ifdef CONFIG_QSD_SVS +#define TPS65023_MAX_DCDC1 1600 +#else +#define TPS65023_MAX_DCDC1 TPS65023_DEFAULT_DCDC1 +#endif + +static int qsd8x50_tps65023_set_dcdc1(int mVolts) +{ + int rc = 0; +#ifdef CONFIG_QSD_SVS + rc = tps65023_set_dcdc1_level(mVolts); + /* By default the TPS65023 will be initialized to 1.225V. + * So we can safely switch to any frequency within this + * voltage even if the device is not probed/ready. + */ + if (rc == -ENODEV && mVolts <= TPS65023_DEFAULT_DCDC1) + rc = 0; +#else + /* Disallow frequencies not supported in the default PMIC + * output voltage. + */ + if (mVolts > TPS65023_DEFAULT_DCDC1) + rc = -EFAULT; +#endif + return rc; +} + +static struct msm_acpu_clock_platform_data qsd8x50_clock_data = { + .acpu_switch_time_us = 20, + .max_speed_delta_khz = 256000, + .vdd_switch_time_us = 62, + .power_collapse_khz = 128000000, + .wait_for_irq_khz = 128000000, + .max_vdd = TPS65023_MAX_DCDC1, + .acpu_set_vdd = qsd8x50_tps65023_set_dcdc1, +}; + + +static void touchpad_gpio_release(void) +{ + gpio_free(TOUCHPAD_IRQ); + gpio_free(TOUCHPAD_SUSPEND); +} + +static int touchpad_gpio_setup(void) +{ + int rc; + int suspend_pin = TOUCHPAD_SUSPEND; + int irq_pin = TOUCHPAD_IRQ; + unsigned suspend_cfg = + GPIO_CFG(suspend_pin, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA); + unsigned irq_cfg = + GPIO_CFG(irq_pin, 1, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA); + + rc = gpio_request(irq_pin, "msm_touchpad_irq"); + if (rc) { + pr_err("gpio_request failed on pin %d (rc=%d)\n", + irq_pin, rc); + goto err_gpioconfig; + } + rc = gpio_request(suspend_pin, "msm_touchpad_suspend"); + if (rc) { + pr_err("gpio_request failed on pin %d (rc=%d)\n", + suspend_pin, rc); + goto err_gpioconfig; + } + rc = gpio_tlmm_config(suspend_cfg, GPIO_ENABLE); + if (rc) { + pr_err("gpio_tlmm_config failed on pin %d (rc=%d)\n", + suspend_pin, rc); + goto err_gpioconfig; + } + rc = gpio_tlmm_config(irq_cfg, GPIO_ENABLE); + if (rc) { + pr_err("gpio_tlmm_config failed on pin %d (rc=%d)\n", + irq_pin, rc); + goto err_gpioconfig; + } + return rc; + +err_gpioconfig: + touchpad_gpio_release(); + return rc; +} + +static struct msm_touchpad_platform_data msm_touchpad_data = { + .gpioirq = TOUCHPAD_IRQ, + .gpiosuspend = TOUCHPAD_SUSPEND, + .gpio_setup = touchpad_gpio_setup, + .gpio_shutdown = touchpad_gpio_release +}; + +#define KBD_RST 35 +#define KBD_IRQ 36 + +static void kbd_gpio_release(void) +{ + gpio_free(KBD_IRQ); + gpio_free(KBD_RST); +} + +static int kbd_gpio_setup(void) +{ + int rc; + int respin = KBD_RST; + int irqpin = KBD_IRQ; + unsigned rescfg = + GPIO_CFG(respin, 0, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA); + unsigned irqcfg = + GPIO_CFG(irqpin, 0, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA); + + rc = gpio_request(irqpin, "gpio_keybd_irq"); + if (rc) { + pr_err("gpio_request failed on pin %d (rc=%d)\n", + irqpin, rc); + goto err_gpioconfig; + } + rc = gpio_request(respin, "gpio_keybd_reset"); + if (rc) { + pr_err("gpio_request failed on pin %d (rc=%d)\n", + respin, rc); + goto err_gpioconfig; + } + rc = gpio_tlmm_config(rescfg, GPIO_ENABLE); + if (rc) { + pr_err("gpio_tlmm_config failed on pin %d (rc=%d)\n", + respin, rc); + goto err_gpioconfig; + } + rc = gpio_tlmm_config(irqcfg, GPIO_ENABLE); + if (rc) { + pr_err("gpio_tlmm_config failed on pin %d (rc=%d)\n", + irqpin, rc); + goto err_gpioconfig; + } + return rc; + +err_gpioconfig: + kbd_gpio_release(); + return rc; +} + +static struct msm_i2ckbd_platform_data msm_kybd_data = { + .hwrepeat = 0, + .scanset1 = 1, + .gpioreset = KBD_RST, + .gpioirq = KBD_IRQ, + .gpio_setup = kbd_gpio_setup, + .gpio_shutdown = kbd_gpio_release, +}; + +static struct i2c_board_info msm_i2c_board_info[] __initdata = { + { + I2C_BOARD_INFO("glidesensor", 0x2A), + .irq = MSM_GPIO_TO_INT(TOUCHPAD_IRQ), + .platform_data = &msm_touchpad_data + }, + { + I2C_BOARD_INFO("msm-i2ckbd", 0x3A), + .type = "msm-i2ckbd", + .irq = MSM_GPIO_TO_INT(KBD_IRQ), + .platform_data = &msm_kybd_data + }, + { + I2C_BOARD_INFO("mt9d112", 0x78 >> 1), + }, + { + I2C_BOARD_INFO("s5k3e2fx", 0x20 >> 1), + }, + { + I2C_BOARD_INFO("mt9p012", 0x6C >> 1), + }, + { + I2C_BOARD_INFO("mt9t013", 0x6C), + }, + { + I2C_BOARD_INFO("tps65023", 0x48), + }, +}; + +static uint32_t camera_off_gpio_table[] = { + /* parallel CAMERA interfaces */ + GPIO_CFG(0, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT0 */ + GPIO_CFG(1, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT1 */ + GPIO_CFG(2, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT2 */ + GPIO_CFG(3, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT3 */ + GPIO_CFG(4, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT4 */ + GPIO_CFG(5, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT5 */ + GPIO_CFG(6, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT6 */ + GPIO_CFG(7, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT7 */ + GPIO_CFG(8, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT8 */ + GPIO_CFG(9, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT9 */ + GPIO_CFG(10, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT10 */ + GPIO_CFG(11, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT11 */ + GPIO_CFG(12, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* PCLK */ + GPIO_CFG(13, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* HSYNC_IN */ + GPIO_CFG(14, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* VSYNC_IN */ + GPIO_CFG(15, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* MCLK */ +}; + +static uint32_t camera_on_gpio_table[] = { + /* parallel CAMERA interfaces */ + GPIO_CFG(0, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT0 */ + GPIO_CFG(1, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT1 */ + GPIO_CFG(2, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT2 */ + GPIO_CFG(3, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT3 */ + GPIO_CFG(4, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT4 */ + GPIO_CFG(5, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT5 */ + GPIO_CFG(6, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT6 */ + GPIO_CFG(7, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT7 */ + GPIO_CFG(8, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT8 */ + GPIO_CFG(9, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT9 */ + GPIO_CFG(10, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT10 */ + GPIO_CFG(11, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT11 */ + GPIO_CFG(12, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* PCLK */ + GPIO_CFG(13, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* HSYNC_IN */ + GPIO_CFG(14, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* VSYNC_IN */ + GPIO_CFG(15, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_16MA), /* MCLK */ +}; + +static void config_gpio_table(uint32_t *table, int len) +{ + int n, rc; + for (n = 0; n < len; n++) { + rc = gpio_tlmm_config(table[n], GPIO_ENABLE); + if (rc) { + printk(KERN_ERR "%s: gpio_tlmm_config(%#x)=%d\n", + __func__, table[n], rc); + break; + } + } +} + +static void config_camera_on_gpios(void) +{ + config_gpio_table(camera_on_gpio_table, + ARRAY_SIZE(camera_on_gpio_table)); +} + +static void config_camera_off_gpios(void) +{ + config_gpio_table(camera_off_gpio_table, + ARRAY_SIZE(camera_off_gpio_table)); +} + +#define MSM_PROBE_INIT(name) name##_probe_init +static struct msm_camera_sensor_info msm_camera_sensor[] = { + { + .sensor_reset = 17, + .sensor_pwd = 85, + .vcm_pwd = 0, + .sensor_name = "mt9d112", + .flash_type = MSM_CAMERA_FLASH_NONE, +#ifdef CONFIG_MSM_CAMERA + .sensor_probe = MSM_PROBE_INIT(mt9d112), +#endif + }, + { + .sensor_reset = 17, + .sensor_pwd = 85, + .vcm_pwd = 0, + .sensor_name = "s5k3e2fx", + .flash_type = MSM_CAMERA_FLASH_NONE, +#ifdef CONFIG_MSM_CAMERA + .sensor_probe = MSM_PROBE_INIT(s5k3e2fx), +#endif + }, + { + .sensor_reset = 17, + .sensor_pwd = 85, + .vcm_pwd = 0, + .sensor_name = "mt9p012", + .flash_type = MSM_CAMERA_FLASH_LED, +#ifdef CONFIG_MSM_CAMERA + .sensor_probe = MSM_PROBE_INIT(mt9p012), +#endif + }, + { + .sensor_reset = 17, + .sensor_pwd = 85, + .vcm_pwd = 0, + .sensor_name = "mt9t013", + .flash_type = MSM_CAMERA_FLASH_NONE, +#ifdef CONFIG_MSM_CAMERA + .sensor_probe = MSM_PROBE_INIT(mt9t013), +#endif + }, +}; +#undef MSM_PROBE_INIT + +static struct msm_camera_device_platform_data msm_camera_device_data = { + .camera_gpio_on = config_camera_on_gpios, + .camera_gpio_off = config_camera_off_gpios, + .snum = ARRAY_SIZE(msm_camera_sensor), + .sinfo = &msm_camera_sensor[0], + .ioext.mdcphy = MSM_MDC_PHYS, + .ioext.mdcsz = MSM_MDC_SIZE, + .ioext.appphy = MSM_CLK_CTL_PHYS, + .ioext.appsz = MSM_CLK_CTL_SIZE, +}; + +static struct resource msm_camera_resources[] = { + { + .start = 0xA0F00000, + .end = 0xA0F00000 + SZ_1M - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = INT_VFE, + .end = INT_VFE, + .flags = IORESOURCE_IRQ, + }, +}; + +static void __init msm_camera_add_device(void) +{ + msm_camera_register_device(&msm_camera_resources, + ARRAY_SIZE(msm_camera_resources), &msm_camera_device_data); + + config_camera_off_gpios(); +} + +static void __init qsd8x50_init_irq(void) +{ + msm_init_irq(); + msm_init_sirc(); +} + +static void sdcc_gpio_init(void) +{ + /* SDC1 GPIOs */ +#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT + if (gpio_request(51, "sdc1_data_3")) + pr_err("failed to request gpio sdc1_data_3\n"); + if (gpio_request(52, "sdc1_data_2")) + pr_err("failed to request gpio sdc1_data_2\n"); + if (gpio_request(53, "sdc1_data_1")) + pr_err("failed to request gpio sdc1_data_1\n"); + if (gpio_request(54, "sdc1_data_0")) + pr_err("failed to request gpio sdc1_data_0\n"); + if (gpio_request(55, "sdc1_cmd")) + pr_err("failed to request gpio sdc1_cmd\n"); + if (gpio_request(56, "sdc1_clk")) + pr_err("failed to request gpio sdc1_clk\n"); +#endif + + if (machine_is_qsd8x50_ffa()) + return; + + /* SDC2 GPIOs */ +#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT + if (gpio_request(62, "sdc2_clk")) + pr_err("failed to request gpio sdc2_clk\n"); + if (gpio_request(63, "sdc2_cmd")) + pr_err("failed to request gpio sdc2_cmd\n"); + if (gpio_request(64, "sdc2_data_3")) + pr_err("failed to request gpio sdc2_data_3\n"); + if (gpio_request(65, "sdc2_data_2")) + pr_err("failed to request gpio sdc2_data_2\n"); + if (gpio_request(66, "sdc2_data_1")) + pr_err("failed to request gpio sdc2_data_1\n"); + if (gpio_request(67, "sdc2_data_0")) + pr_err("failed to request gpio sdc2_data_0\n"); +#endif + + /* SDC3 GPIOs */ +#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT + if (gpio_request(88, "sdc3_clk")) + pr_err("failed to request gpio sdc3_clk\n"); + if (gpio_request(89, "sdc3_cmd")) + pr_err("failed to request gpio sdc3_cmd\n"); + if (gpio_request(90, "sdc3_data_3")) + pr_err("failed to request gpio sdc3_data_3\n"); + if (gpio_request(91, "sdc3_data_2")) + pr_err("failed to request gpio sdc3_data_2\n"); + if (gpio_request(92, "sdc3_data_1")) + pr_err("failed to request gpio sdc3_data_1\n"); + if (gpio_request(93, "sdc3_data_0")) + pr_err("failed to request gpio sdc3_data_0\n"); +#endif + + /* SDC4 GPIOs */ +#ifdef CONFIG_MMC_MSM_SDC4_SUPPORT + if (gpio_request(142, "sdc4_clk")) + pr_err("failed to request gpio sdc4_clk\n"); + if (gpio_request(143, "sdc4_cmd")) + pr_err("failed to request gpio sdc4_cmd\n"); + if (gpio_request(144, "sdc4_data_0")) + pr_err("failed to request gpio sdc4_data_0\n"); + if (gpio_request(145, "sdc4_data_1")) + pr_err("failed to request gpio sdc4_data_1\n"); + if (gpio_request(146, "sdc4_data_2")) + pr_err("failed to request gpio sdc4_data_2\n"); + if (gpio_request(147, "sdc4_data_3")) + pr_err("failed to request gpio sdc4_data_3\n"); +#endif +} + +static unsigned sdcc_cfg_data[][6] = { + /* SDC1 configs */ + { + GPIO_CFG(51, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(52, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(53, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(54, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(55, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(56, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA), + }, + /* SDC2 configs */ + { + GPIO_CFG(62, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA), + GPIO_CFG(63, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(64, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(65, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(66, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(67, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + }, + /* SDC3 configs */ + { + GPIO_CFG(88, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA), + GPIO_CFG(89, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(90, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(91, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(92, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(93, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + }, + /* SDC4 configs */ + { + GPIO_CFG(142, 3, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA), + GPIO_CFG(143, 3, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(144, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(145, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(146, 3, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + GPIO_CFG(147, 3, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), + } +}; + +static unsigned long vreg_sts, gpio_sts; +static struct vreg *vreg_mmc; + +static void msm_sdcc_setup_gpio(int dev_id, unsigned int enable) +{ + int i, rc; + + if (!(test_bit(dev_id, &gpio_sts)^enable)) + return; + + if (enable) + set_bit(dev_id, &gpio_sts); + else + clear_bit(dev_id, &gpio_sts); + + for (i = 0; i < ARRAY_SIZE(sdcc_cfg_data[dev_id - 1]); i++) { + rc = gpio_tlmm_config(sdcc_cfg_data[dev_id - 1][i], + enable ? GPIO_ENABLE : GPIO_DISABLE); + if (rc) + printk(KERN_ERR "%s: gpio_tlmm_config(%#x)=%d\n", + __func__, sdcc_cfg_data[dev_id - 1][i], rc); + } +} + +static uint32_t msm_sdcc_setup_power(struct device *dv, unsigned int vdd) +{ + int rc = 0; + struct platform_device *pdev; + + pdev = container_of(dv, struct platform_device, dev); + msm_sdcc_setup_gpio(pdev->id, !!vdd); + + if (vdd == 0) { + if (!vreg_sts) + return 0; + + clear_bit(pdev->id, &vreg_sts); + + if (!vreg_sts) { + rc = vreg_disable(vreg_mmc); + if (rc) + printk(KERN_ERR "%s: return val: %d \n", + __func__, rc); + } + return 0; + } + + if (!vreg_sts) { + rc = vreg_set_level(vreg_mmc, 2850); + if (!rc) + rc = vreg_enable(vreg_mmc); + if (rc) + printk(KERN_ERR "%s: return val: %d \n", + __func__, rc); + } + set_bit(pdev->id, &vreg_sts); + return 0; +} + +static struct mmc_platform_data qsd8x50_sdcc_data = { + .ocr_mask = MMC_VDD_27_28 | MMC_VDD_28_29, + .translate_vdd = msm_sdcc_setup_power, +}; + +static void __init qsd8x50_init_mmc(void) +{ + if (machine_is_qsd8x50_ffa()) + vreg_mmc = vreg_get(NULL, "gp6"); + else + vreg_mmc = vreg_get(NULL, "gp5"); + + if (IS_ERR(vreg_mmc)) { + printk(KERN_ERR "%s: vreg get failed (%ld)\n", + __func__, PTR_ERR(vreg_mmc)); + return; + } + + sdcc_gpio_init(); +#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT + msm_add_sdcc(1, &qsd8x50_sdcc_data); +#endif + + if (machine_is_qsd8x50_surf()) { +#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT + msm_add_sdcc(2, &qsd8x50_sdcc_data); +#endif +#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT + msm_add_sdcc(3, &qsd8x50_sdcc_data); +#endif +#ifdef CONFIG_MMC_MSM_SDC4_SUPPORT + msm_add_sdcc(4, &qsd8x50_sdcc_data); +#endif + } + +} + +static void __init qsd8x50_cfg_smc91x(void) +{ + int rc = 0; + + if (machine_is_qsd8x50_surf()) { + smc91x_resources[0].start = 0x70000300; + smc91x_resources[0].end = 0x70000400; + smc91x_resources[1].start = MSM_GPIO_TO_INT(156); + smc91x_resources[1].end = MSM_GPIO_TO_INT(156); + } else if (machine_is_qsd8x50_ffa()) { + smc91x_resources[0].start = 0x84000300; + smc91x_resources[0].end = 0x84000400; + smc91x_resources[1].start = MSM_GPIO_TO_INT(87); + smc91x_resources[1].end = MSM_GPIO_TO_INT(87); + + rc = gpio_tlmm_config(GPIO_CFG(87, 0, GPIO_INPUT, + GPIO_PULL_DOWN, GPIO_2MA), + GPIO_ENABLE); + if (rc) { + printk(KERN_ERR "%s: gpio_tlmm_config=%d\n", + __func__, rc); + } + } else + printk(KERN_ERR "%s: invalid machine type\n", __func__); +} + +static struct msm_i2c_platform_data msm_i2c_pdata = { + .clk_freq = 100000, +}; + +static void __init msm_device_i2c_init(void) +{ + msm_device_i2c.dev.platform_data = &msm_i2c_pdata; +} + +static struct msm_pm_platform_data msm_pm_data[MSM_PM_SLEEP_MODE_NR] = { + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].supported = 1, + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].suspend_enabled = 1, + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].idle_enabled = 1, + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].latency = 16000, + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].residency = 20000, + + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].supported = 1, + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].suspend_enabled = 1, + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].idle_enabled = 1, + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].latency = 12000, + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].residency = 20000, + + [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].supported = 1, + [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].suspend_enabled + = 1, + [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].idle_enabled = 0, + [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].latency = 2000, + [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].residency = 10000, + + [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].supported = 1, + [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].suspend_enabled = 1, + [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].idle_enabled = 1, + [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].latency = 500, + [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].residency = 0, +}; + +static void __init qsd8x50_init(void) +{ + if (socinfo_init() < 0) + printk(KERN_ERR "%s: socinfo_init() failed!\n", + __func__); + qsd8x50_cfg_smc91x(); + msm_acpu_clock_init(&qsd8x50_clock_data); + msm_device_hsusb_peripheral.dev.platform_data = &msm_hsusb_pdata; + msm_device_hsusb_host.dev.platform_data = &msm_hsusb_pdata; + platform_add_devices(devices, ARRAY_SIZE(devices)); + msm_fb_add_devices(); + msm_camera_add_device(); + qsd8x50_init_mmc(); + bt_power_init(); + audio_gpio_init(); + msm_device_i2c_init(); + i2c_register_board_info(0, msm_i2c_board_info, + ARRAY_SIZE(msm_i2c_board_info)); + spi_register_board_info(msm_spi_board_info, + ARRAY_SIZE(msm_spi_board_info)); + msm_pm_set_platform_data(msm_pm_data); + +#ifdef CONFIG_SURF_FFA_GPIO_KEYPAD + if (machine_is_qsd8x50_ffa()) + platform_device_register(&keypad_device_8k_ffa); + else + platform_device_register(&keypad_device_surf); +#endif +} + +static void __init qsd8x50_allocate_memory_regions(void) +{ + void *addr; + unsigned long size; + + size = MSM_PMEM_CAMERA_SIZE; + addr = alloc_bootmem(size); + android_pmem_camera_pdata.start = __pa(addr); + android_pmem_camera_pdata.size = size; + printk(KERN_INFO "allocating %lu bytes at %p (%lx physical)" + "for camera pmem\n", size, addr, __pa(addr)); + + size = MSM_PMEM_MDP_SIZE; + addr = alloc_bootmem(size); + android_pmem_pdata.start = __pa(addr); + android_pmem_pdata.size = size; + printk(KERN_INFO "allocating %lu bytes at %p (%lx physical)" + "for pmem\n", size, addr, __pa(addr)); + + size = MSM_PMEM_ADSP_SIZE; + addr = alloc_bootmem(size); + android_pmem_adsp_pdata.start = __pa(addr); + android_pmem_adsp_pdata.size = size; + printk(KERN_INFO "allocating %lu bytes at %p (%lx physical)" + "for adsp pmem\n", size, addr, __pa(addr)); + + size = MSM_PMEM_GPU1_SIZE; + addr = alloc_bootmem_aligned(size, 0x100000); + android_pmem_gpu1_pdata.start = __pa(addr); + android_pmem_gpu1_pdata.size = size; + printk(KERN_INFO "allocating %lu bytes at %p (%lx physical)" + "for gpu1 pmem\n", size, addr, __pa(addr)); + + size = MSM_FB_SIZE; + addr = (void *)MSM_FB_BASE; + msm_fb_resources[0].start = (unsigned long)addr; + msm_fb_resources[0].end = msm_fb_resources[0].start + size - 1; + printk(KERN_INFO "using %lu bytes of SMI at %lx physical for fb\n", + size, (unsigned long)addr); + + size = MSM_AUDIO_SIZE; + addr = alloc_bootmem(size); + msm_audio_resources[0].start = __pa(addr); + msm_audio_resources[0].end = __pa(addr) + MSM_AUDIO_SIZE; + printk(KERN_INFO "allocating %lu bytes at %p (%lx physical)" + "for audio\n", size, addr, __pa(addr)); +} + +static void __init qsd8x50_map_io(void) +{ + msm_map_qsd8x50_io(); + qsd8x50_allocate_memory_regions(); + msm_clock_init(msm_clocks_8x50, msm_num_clocks_8x50); +} + +MACHINE_START(QSD8X50_SURF, "QCT QSD8X50 SURF") +#ifdef CONFIG_MSM_DEBUG_UART + .phys_io = MSM_DEBUG_UART_PHYS, + .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc, +#endif + .boot_params = 0x16000100, + .map_io = qsd8x50_map_io, + .init_irq = qsd8x50_init_irq, + .init_machine = qsd8x50_init, + .timer = &msm_timer, +MACHINE_END + +MACHINE_START(QSD8X50_FFA, "QCT QSD8X50 FFA") +#ifdef CONFIG_MSM_DEBUG_UART + .phys_io = MSM_DEBUG_UART_PHYS, + .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc, +#endif + .boot_params = 0x16000100, + .map_io = qsd8x50_map_io, + .init_irq = qsd8x50_init_irq, + .init_machine = qsd8x50_init, + .timer = &msm_timer, +MACHINE_END diff --git a/arch/arm/mach-msm/board-sapphire.c b/arch/arm/mach-msm/board-sapphire.c index 7898fce517b3..a971a24d7e28 100644 --- a/arch/arm/mach-msm/board-sapphire.c +++ b/arch/arm/mach-msm/board-sapphire.c @@ -55,6 +55,7 @@ #include "gpio_chip.h" #include "board-sapphire.h" +#include "pm.h" #include #include @@ -990,6 +991,12 @@ static struct msm_serial_hs_platform_data msm_uart_dm1_pdata = { }; #endif +static struct msm_pm_platform_data msm_pm_data[MSM_PM_SLEEP_MODE_NR] = { + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].latency = 16000, + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].latency = 12000, + [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].latency = 2000, +}; + static void __init sapphire_init(void) { int rc; @@ -1052,6 +1059,7 @@ static void __init sapphire_init(void) platform_add_devices(devices, ARRAY_SIZE(devices)); i2c_register_board_info(0, i2c_devices, ARRAY_SIZE(i2c_devices)); + msm_pm_set_platform_data(msm_pm_data); } static struct map_desc sapphire_io_desc[] __initdata = { diff --git a/arch/arm/mach-msm/board-trout.c b/arch/arm/mach-msm/board-trout.c index 14cb304bade2..ac3d43e4eaa4 100644 --- a/arch/arm/mach-msm/board-trout.c +++ b/arch/arm/mach-msm/board-trout.c @@ -1,6 +1,7 @@ /* arch/arm/mach-msm/board-trout.c * * Copyright (C) 2008 Google, Inc. + * Copyright (c) 2009, Code Aurora Forum. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -23,7 +24,7 @@ #include #include #include -#include <../../../drivers/staging/android/timed_gpio.h> +#include #include #include #include @@ -56,6 +57,7 @@ #include "board-trout.h" #include "gpio_chip.h" +#include "pm.h" #include #include @@ -731,6 +733,12 @@ static struct msm_serial_hs_platform_data msm_uart_dm1_pdata = { }; #endif +static struct msm_pm_platform_data msm_pm_data[MSM_PM_SLEEP_MODE_NR] = { + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].latency = 16000, + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].latency = 12000, + [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].latency = 2000, +}; + static void __init trout_init(void) { int rc; @@ -783,6 +791,7 @@ static void __init trout_init(void) platform_add_devices(devices, ARRAY_SIZE(devices)); i2c_register_board_info(0, i2c_devices, ARRAY_SIZE(i2c_devices)); + msm_pm_set_platform_data(msm_pm_data); /* SD card door should wake the device */ set_irq_wake(TROUT_GPIO_TO_INT(TROUT_GPIO_SD_DOOR_N), 1); @@ -808,10 +817,11 @@ static void __init trout_fixup(struct machine_desc *desc, struct tag *tags, static void __init trout_map_io(void) { - printk("trout_init_map_io()\n"); + msm_shared_ram_phys = 0x01F00000; + msm_map_common_io(); iotable_init(trout_io_desc, ARRAY_SIZE(trout_io_desc)); - msm_clock_init(); + msm_clock_init(msm_clocks_7x01a, msm_num_clocks_7x01a); } MACHINE_START(TROUT, "trout") diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c index fa21e45edb60..c3f48b113009 100644 --- a/arch/arm/mach-msm/clock.c +++ b/arch/arm/mach-msm/clock.c @@ -1,7 +1,7 @@ /* arch/arm/mach-msm/clock.c * * Copyright (C) 2007 Google, Inc. - * Copyright (c) 2007 QUALCOMM Incorporated + * Copyright (c) 2007-2009, Code Aurora Forum. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -22,6 +22,9 @@ #include #include #include +#include +#include +#include #include "clock.h" #include "proc_comm.h" @@ -29,13 +32,26 @@ static DEFINE_MUTEX(clocks_mutex); static DEFINE_SPINLOCK(clocks_lock); static LIST_HEAD(clocks); +struct clk *msm_clocks; +unsigned msm_num_clocks; + +/* + * Bitmap of enabled clocks, excluding ACPU which is always + * enabled + */ +static DECLARE_BITMAP(clock_map_enabled, NR_CLKS); +static DEFINE_SPINLOCK(clock_map_lock); /* * glue for the proc_comm interface */ static inline int pc_clk_enable(unsigned id) { - return msm_proc_comm(PCOM_CLKCTL_RPC_ENABLE, &id, NULL); + int rc = msm_proc_comm(PCOM_CLKCTL_RPC_ENABLE, &id, NULL); + if (rc < 0) + return rc; + else + return (int)id < 0 ? -EINVAL : 0; } static inline void pc_clk_disable(unsigned id) @@ -45,22 +61,42 @@ static inline void pc_clk_disable(unsigned id) static inline int pc_clk_set_rate(unsigned id, unsigned rate) { - return msm_proc_comm(PCOM_CLKCTL_RPC_SET_RATE, &id, &rate); + /* The rate _might_ be rounded off to the nearest KHz value by the + * remote function. So a return value of 0 doesn't necessarily mean + * that the exact rate was set successfully. + */ + int rc = msm_proc_comm(PCOM_CLKCTL_RPC_SET_RATE, &id, &rate); + if (rc < 0) + return rc; + else + return (int)id < 0 ? -EINVAL : 0; } -static int pc_clk_set_min_rate(unsigned id, unsigned rate) +int pc_clk_set_min_rate(unsigned id, unsigned rate) { - return msm_proc_comm(PCOM_CLKCTL_RPC_MIN_RATE, &id, &rate); + int rc = msm_proc_comm(PCOM_CLKCTL_RPC_MIN_RATE, &id, &rate); + if (rc < 0) + return rc; + else + return (int)id < 0 ? -EINVAL : 0; } static inline int pc_clk_set_max_rate(unsigned id, unsigned rate) { - return msm_proc_comm(PCOM_CLKCTL_RPC_MAX_RATE, &id, &rate); + int rc = msm_proc_comm(PCOM_CLKCTL_RPC_MAX_RATE, &id, &rate); + if (rc < 0) + return rc; + else + return (int)id < 0 ? -EINVAL : 0; } static inline int pc_clk_set_flags(unsigned id, unsigned flags) { - return msm_proc_comm(PCOM_CLKCTL_RPC_SET_FLAGS, &id, &flags); + int rc = msm_proc_comm(PCOM_CLKCTL_RPC_SET_FLAGS, &id, &flags); + if (rc < 0) + return rc; + else + return (int)id < 0 ? -EINVAL : 0; } static inline unsigned pc_clk_get_rate(unsigned id) @@ -81,8 +117,13 @@ static inline unsigned pc_clk_is_enabled(unsigned id) static inline int pc_pll_request(unsigned id, unsigned on) { + int rc; on = !!on; - return msm_proc_comm(PCOM_CLKCTL_RPC_PLL_REQUEST, &id, &on); + rc = msm_proc_comm(PCOM_CLKCTL_RPC_PLL_REQUEST, &id, &on); + if (rc < 0) + return rc; + else + return (int)id < 0 ? -EINVAL : 0; } /* @@ -119,8 +160,12 @@ int clk_enable(struct clk *clk) unsigned long flags; spin_lock_irqsave(&clocks_lock, flags); clk->count++; - if (clk->count == 1) + if (clk->count == 1) { pc_clk_enable(clk->id); + spin_lock(&clock_map_lock); + clock_map_enabled[BIT_WORD(clk->id)] |= BIT_MASK(clk->id); + spin_unlock(&clock_map_lock); + } spin_unlock_irqrestore(&clocks_lock, flags); return 0; } @@ -132,8 +177,12 @@ void clk_disable(struct clk *clk) spin_lock_irqsave(&clocks_lock, flags); BUG_ON(clk->count == 0); clk->count--; - if (clk->count == 0) + if (clk->count == 0) { pc_clk_disable(clk->id); + spin_lock(&clock_map_lock); + clock_map_enabled[BIT_WORD(clk->id)] &= ~BIT_MASK(clk->id); + spin_unlock(&clock_map_lock); + } spin_unlock_irqrestore(&clocks_lock, flags); } EXPORT_SYMBOL(clk_disable); @@ -146,26 +195,22 @@ EXPORT_SYMBOL(clk_get_rate); int clk_set_rate(struct clk *clk, unsigned long rate) { - int ret; - if (clk->flags & CLKFLAG_USE_MAX_TO_SET) { - ret = pc_clk_set_max_rate(clk->id, rate); - if (ret) - return ret; - } - if (clk->flags & CLKFLAG_USE_MIN_TO_SET) { - ret = pc_clk_set_min_rate(clk->id, rate); - if (ret) - return ret; - } - - if (clk->flags & CLKFLAG_USE_MAX_TO_SET || - clk->flags & CLKFLAG_USE_MIN_TO_SET) - return ret; - return pc_clk_set_rate(clk->id, rate); } EXPORT_SYMBOL(clk_set_rate); +int clk_set_min_rate(struct clk *clk, unsigned long rate) +{ + return pc_clk_set_min_rate(clk->id, rate); +} +EXPORT_SYMBOL(clk_set_min_rate); + +int clk_set_max_rate(struct clk *clk, unsigned long rate) +{ + return pc_clk_set_max_rate(clk->id, rate); +} +EXPORT_SYMBOL(clk_set_max_rate); + int clk_set_parent(struct clk *clk, struct clk *parent) { return -ENOSYS; @@ -186,19 +231,166 @@ int clk_set_flags(struct clk *clk, unsigned long flags) } EXPORT_SYMBOL(clk_set_flags); +/* + * Find out whether any clock is enabled that needs the TCXO clock. + * + * On exit, the buffer 'reason' holds a bitmap of ids of all enabled + * clocks found that require TCXO. + * + * reason: buffer to hold the bitmap; must be compatible with + * linux/bitmap.h + * nbits: number of bits that the buffer can hold; 0 is ok + * + * Return value: + * 0: does not require the TCXO clock + * 1: requires the TCXO clock + */ +int msm_clock_require_tcxo(unsigned long *reason, int nbits) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&clock_map_lock, flags); + ret = !bitmap_empty(clock_map_enabled, NR_CLKS); + if (nbits > 0) + bitmap_copy(reason, clock_map_enabled, min(nbits, NR_CLKS)); + spin_unlock_irqrestore(&clock_map_lock, flags); -void __init msm_clock_init(void) + return ret; +} + +/* + * Find the clock matching the given id and copy its name to the + * provided buffer. + * + * Return value: + * -ENODEV: there is no clock matching the given id + * 0: success + */ +int msm_clock_get_name(uint32_t id, char *name, uint32_t size) { - struct clk *clk; + struct clk *c_clk; + int ret = -ENODEV; - spin_lock_init(&clocks_lock); mutex_lock(&clocks_mutex); - for (clk = msm_clocks; clk && clk->name; clk++) { - list_add_tail(&clk->list, &clocks); + list_for_each_entry(c_clk, &clocks, list) { + if (id == c_clk->id) { + strlcpy(name, c_clk->name, size); + ret = 0; + break; + } } mutex_unlock(&clocks_mutex); + + return ret; } +void __init msm_clock_init(struct clk *clock_tbl, unsigned num_clocks) +{ + unsigned n; + + spin_lock_init(&clocks_lock); + mutex_lock(&clocks_mutex); + msm_clocks = clock_tbl; + msm_num_clocks = num_clocks; + for (n = 0; n < msm_num_clocks; n++) + list_add_tail(&msm_clocks[n].list, &clocks); + mutex_unlock(&clocks_mutex); +} + +#if defined(CONFIG_DEBUG_FS) +static struct clk *msm_clock_get_nth(unsigned index) +{ + if (index < msm_num_clocks) + return msm_clocks + index; + else + return 0; +} + +static int clock_debug_rate_set(void *data, u64 val) +{ + struct clk *clock = data; + int ret; + + /* Only increases to max rate will succeed, but that's actually good + * for debugging purposes. So we don't check for error. */ + if (clock->flags & CLK_MAX) + clk_set_max_rate(clock, val); + if (clock->flags & CLK_MIN) + ret = clk_set_min_rate(clock, val); + else + ret = clk_set_rate(clock, val); + if (ret != 0) + printk(KERN_ERR "clk_set%s_rate failed (%d)\n", + (clock->flags & CLK_MIN) ? "_min" : "", ret); + return ret; +} + +static int clock_debug_rate_get(void *data, u64 *val) +{ + struct clk *clock = data; + *val = clk_get_rate(clock); + return 0; +} + +static int clock_debug_enable_set(void *data, u64 val) +{ + struct clk *clock = data; + int rc = 0; + + if (val) + rc = pc_clk_enable(clock->id); + else + pc_clk_disable(clock->id); + + return rc; +} + +static int clock_debug_enable_get(void *data, u64 *val) +{ + struct clk *clock = data; + + *val = pc_clk_is_enabled(clock->id); + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(clock_rate_fops, clock_debug_rate_get, + clock_debug_rate_set, "%llu\n"); +DEFINE_SIMPLE_ATTRIBUTE(clock_enable_fops, clock_debug_enable_get, + clock_debug_enable_set, "%llu\n"); + +static int __init clock_debug_init(void) +{ + struct dentry *dent_rate; + struct dentry *dent_enable; + struct clk *clock; + unsigned n = 0; + char temp[50], *ptr; + + dent_rate = debugfs_create_dir("clk_rate", 0); + if (IS_ERR(dent_rate)) + return PTR_ERR(dent_rate); + + dent_enable = debugfs_create_dir("clk_enable", 0); + if (IS_ERR(dent_enable)) + return PTR_ERR(dent_enable); + + while ((clock = msm_clock_get_nth(n++)) != 0) { + strncpy(temp, clock->dbg_name, ARRAY_SIZE(temp)-1); + for (ptr = temp; *ptr; ptr++) + *ptr = tolower(*ptr); + debugfs_create_file(temp, 0644, dent_rate, + clock, &clock_rate_fops); + debugfs_create_file(temp, 0644, dent_enable, + clock, &clock_enable_fops); + } + return 0; +} + +device_initcall(clock_debug_init); +#endif + /* The bootloader and/or AMSS may have left various clocks enabled. * Disable any clocks that belong to us (CLKFLAG_AUTO_OFF) but have * not been explicitly enabled by a clk_enable() call. diff --git a/arch/arm/mach-msm/clock.h b/arch/arm/mach-msm/clock.h index af9a5a76af80..c342ca924ab5 100644 --- a/arch/arm/mach-msm/clock.h +++ b/arch/arm/mach-msm/clock.h @@ -1,7 +1,7 @@ /* arch/arm/mach-msm/clock.h * * Copyright (C) 2007 Google, Inc. - * Copyright (c) 2007 QUALCOMM Incorporated + * Copyright (c) 2007-2009, Code Aurora Forum. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -19,18 +19,24 @@ #include -#define CLKFLAG_USE_MAX_TO_SET (0x00000001) -#define CLKFLAG_AUTO_OFF (0x00000002) -#define CLKFLAG_USE_MIN_TO_SET (0x00000004) +#define CLKFLAG_INVERT 0x00000001 +#define CLKFLAG_NOINVERT 0x00000002 +#define CLKFLAG_NONEST 0x00000004 +#define CLKFLAG_NORESET 0x00000008 -#define CLKFLAG_ARCH_MSM7X00A (0x00010000) -#define CLKFLAG_ARCH_ALL (0xffff0000) +#define CLK_FIRST_AVAILABLE_FLAG 0x00000100 +#define CLKFLAG_AUTO_OFF 0x00000200 +#define CLKFLAG_MIN 0x00000400 +#define CLKFLAG_MAX 0x00000800 struct clk { uint32_t id; uint32_t count; uint32_t flags; const char *name; +#ifdef CONFIG_DEBUG_FS + const char *dbg_name; +#endif struct list_head list; struct device *dev; }; @@ -81,12 +87,40 @@ struct clk { #define USB_HS_PCLK 37 /* High speed USB pbus clock */ #define USB_OTG_CLK 38 /* Full speed USB clock */ #define VDC_CLK 39 /* Video controller clock */ -#define VFE_CLK 40 /* Camera / Video Front End clock */ -#define VFE_MDC_CLK 41 /* VFE MDDI client clock */ +#define VFE_MDC_CLK 40 /* Camera / Video Front End clock */ +#define VFE_CLK 41 /* VFE MDDI client clock */ + +#define MDP_LCDC_PCLK_CLK 42 +#define MDP_LCDC_PAD_PCLK_CLK 43 +#define MDP_VSYNC_CLK 44 + +#define SPI_CLK 45 +#define VFE_AXI_CLK 46 + +#define NR_CLKS 47 + +#ifdef CONFIG_DEBUG_FS +#define CLOCK_DBG_NAME(x) .dbg_name = x, +#else +#define CLOCK_DBG_NAME(x) +#endif + +#define CLOCK(clk_name, clk_id, clk_dev, clk_flags) { \ + .name = clk_name, \ + .id = clk_id, \ + .flags = clk_flags, \ + .dev = clk_dev, \ + CLOCK_DBG_NAME(#clk_id) \ + } -#define NR_CLKS 42 +#define OFF CLKFLAG_AUTO_OFF +#define CLK_MIN CLKFLAG_MIN +#define CLK_MAX CLKFLAG_MAX +#define CLK_MINMAX (CLK_MIN | CLK_MAX) -extern struct clk msm_clocks[]; +int msm_clock_require_tcxo(unsigned long *reason, int nbits); +int msm_clock_get_name(uint32_t id, char *name, uint32_t size); +int pc_clk_set_min_rate(unsigned id, unsigned rate); #endif diff --git a/arch/arm/mach-msm/cpufreq.c b/arch/arm/mach-msm/cpufreq.c index 729391c64424..a0b1a06263c1 100644 --- a/arch/arm/mach-msm/cpufreq.c +++ b/arch/arm/mach-msm/cpufreq.c @@ -3,7 +3,7 @@ * MSM architecture cpufreq driver * * Copyright (C) 2007 Google, Inc. - * Copyright (c) 2007 QUALCOMM Incorporated + * Copyright (c) 2007-2009, Code Aurora Forum. All rights reserved. * Author: Mike A. Chan * * This software is licensed under the terms of the GNU General Public @@ -19,40 +19,43 @@ #include #include +#include #include "acpuclock.h" -#ifdef CONFIG_MSM_CPU_FREQ_ONDEMAND -#include -#endif +#define dprintk(msg...) \ + cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "cpufreq-msm", msg) #ifdef CONFIG_MSM_CPU_FREQ_SCREEN -static void msm_early_suspend(struct early_suspend *handler) { - acpuclk_set_rate(CONFIG_MSM_CPU_FREQ_SCREEN_OFF * 1000, 0); +static void msm_early_suspend(struct early_suspend *handler) +{ + acpuclk_set_rate(CONFIG_MSM_CPU_FREQ_SCREEN_OFF * 1000, SETRATE_CPUFREQ); } -static void msm_late_resume(struct early_suspend *handler) { - acpuclk_set_rate(CONFIG_MSM_CPU_FREQ_SCREEN_ON * 1000, 0); +static void msm_late_resume(struct early_suspend *handler) +{ + acpuclk_set_rate(CONFIG_MSM_CPU_FREQ_SCREEN_ON * 1000, SETRATE_CPUFREQ); } static struct early_suspend msm_power_suspend = { - .suspend = msm_early_suspend, - .resume = msm_late_resume, + .suspend = msm_early_suspend, + .resume = msm_late_resume, }; static int __init clock_late_init(void) { - register_early_suspend(&msm_power_suspend); - return 0; + register_early_suspend(&msm_power_suspend); + return 0; } late_initcall(clock_late_init); -#elif defined(CONFIG_MSM_CPU_FREQ_ONDEMAND) +#elif defined(CONFIG_CPU_FREQ_MSM) static int msm_cpufreq_target(struct cpufreq_policy *policy, unsigned int target_freq, unsigned int relation) { int index; + int ret = 0; struct cpufreq_freqs freqs; struct cpufreq_frequency_table *table = cpufreq_frequency_get_table(smp_processor_id()); @@ -64,16 +67,17 @@ static int msm_cpufreq_target(struct cpufreq_policy *policy, } #ifdef CONFIG_CPU_FREQ_DEBUG - printk("msm_cpufreq_target %d r %d (%d-%d) selected %d\n", target_freq, + dprintk("target %d r %d (%d-%d) selected %d\n", target_freq, relation, policy->min, policy->max, table[index].frequency); #endif freqs.old = policy->cur; freqs.new = table[index].frequency; freqs.cpu = smp_processor_id(); cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); - acpuclk_set_rate(table[index].frequency * 1000, 0); - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); - return 0; + ret = acpuclk_set_rate(table[index].frequency * 1000, SETRATE_CPUFREQ); + if (!ret) + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + return ret; } static int msm_cpufreq_verify(struct cpufreq_policy *policy) @@ -90,11 +94,15 @@ static int __init msm_cpufreq_init(struct cpufreq_policy *policy) policy->cur = acpuclk_get_rate(); if (cpufreq_frequency_table_cpuinfo(policy, table)) { - policy->cpuinfo.min_freq = CONFIG_MSM_CPU_FREQ_ONDEMAND_MIN; - policy->cpuinfo.max_freq = CONFIG_MSM_CPU_FREQ_ONDEMAND_MAX; +#ifdef CONFIG_MSM_CPU_FREQ_SET_MIN_MAX + policy->cpuinfo.min_freq = CONFIG_MSM_CPU_FREQ_MIN; + policy->cpuinfo.max_freq = CONFIG_MSM_CPU_FREQ_MAX; +#endif } - policy->min = CONFIG_MSM_CPU_FREQ_ONDEMAND_MIN; - policy->max = CONFIG_MSM_CPU_FREQ_ONDEMAND_MAX; +#ifdef CONFIG_MSM_CPU_FREQ_SET_MIN_MAX + policy->min = CONFIG_MSM_CPU_FREQ_MIN; + policy->max = CONFIG_MSM_CPU_FREQ_MAX; +#endif policy->cpuinfo.transition_latency = acpuclk_get_switch_time() * NSEC_PER_USEC; diff --git a/arch/arm/mach-msm/dal.c b/arch/arm/mach-msm/dal.c new file mode 100644 index 000000000000..cefe03c5eb24 --- /dev/null +++ b/arch/arm/mach-msm/dal.c @@ -0,0 +1,1363 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +/* + * Device access library (DAL) implementation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define DALRPC_PROTOCOL_VERSION 0x11 +#define DALRPC_SUCCESS 0 +#define DALRPC_MAX_PORTNAME_LEN 64 +#define DALRPC_MAX_ATTACH_PARAM_LEN 64 +#define DALRPC_MAX_SERVICE_NAME_LEN 32 +#define DALRPC_MAX_PARAMS 128 +#define DALRPC_MAX_PARAMS_SIZE (DALRPC_MAX_PARAMS * 4) +#define DALRPC_MAX_MSG_SIZE (sizeof(struct dalrpc_msg_hdr) + \ + DALRPC_MAX_PARAMS_SIZE) +#define DALRPC_MSGID_DDI 0x0 +#define DALRPC_MSGID_DDI_REPLY 0x80 +#define DALRPC_MSGID_ATTACH_REPLY 0x81 +#define DALRPC_MSGID_DETACH_REPLY 0x82 +#define DALRPC_MSGID_ASYNCH 0xC0 +#define ROUND_BUFLEN(x) (((x + 3) & ~0x3)) + +struct dalrpc_msg_hdr { + uint32_t len:16; + uint32_t proto_ver:8; + uint32_t prio:7; + uint32_t async:1; + uint32_t ddi_idx:16; + uint32_t proto_id:8; + uint32_t msgid:8; + void *from; + void *to; +}; + +struct dalrpc_msg { + struct dalrpc_msg_hdr hdr; + uint32_t param[DALRPC_MAX_PARAMS]; +}; + +struct dalrpc_event_handle { + struct list_head list; + + int flag; + spinlock_t lock; +}; + +struct dalrpc_cb_handle { + struct list_head list; + + void (*fn)(void *, uint32_t, void *, uint32_t); + void *context; +}; + +struct daldevice_handle {; + struct list_head list; + + void *remote_handle; + struct completion read_completion; + struct dalrpc_port *port; + struct dalrpc_msg msg; + struct mutex client_lock; +}; + +struct dalrpc_port { + struct list_head list; + + char port[DALRPC_MAX_PORTNAME_LEN+1]; + int refcount; + + struct workqueue_struct *wq; + struct work_struct port_work; + struct mutex write_lock; + + smd_channel_t *ch; + + struct dalrpc_msg msg_in; + struct daldevice_handle *msg_owner; + unsigned msg_bytes_read; + + struct list_head event_list; + struct mutex event_list_lock; + + struct list_head cb_list; + struct mutex cb_list_lock; +}; + +static LIST_HEAD(port_list); +static LIST_HEAD(client_list); +static DEFINE_MUTEX(pc_lists_lock); + +static DECLARE_WAIT_QUEUE_HEAD(event_wq); + +static int client_exists(void *handle) +{ + struct daldevice_handle *h; + + if (!handle) + return 0; + + mutex_lock(&pc_lists_lock); + + list_for_each_entry(h, &client_list, list) + if (h == handle) { + mutex_unlock(&pc_lists_lock); + return 1; + } + + mutex_unlock(&pc_lists_lock); + + return 0; +} + +static int client_exists_locked(void *handle) +{ + struct daldevice_handle *h; + + /* this function must be called with pc_lists_lock acquired */ + + if (!handle) + return 0; + + list_for_each_entry(h, &client_list, list) + if (h == handle) + return 1; + + return 0; +} + +static int port_exists(struct dalrpc_port *p) +{ + struct dalrpc_port *p_iter; + + /* this function must be called with pc_lists_lock acquired */ + + if (!p) + return 0; + + list_for_each_entry(p_iter, &port_list, list) + if (p_iter == p) + return 1; + + return 0; +} + +static struct dalrpc_port *port_name_exists(char *port) +{ + struct dalrpc_port *p; + + /* this function must be called with pc_lists_lock acquired */ + + list_for_each_entry(p, &port_list, list) + if (!strcmp(p->port, port)) + return p; + + return NULL; +} + +static void port_close(struct dalrpc_port *p) +{ + mutex_lock(&pc_lists_lock); + + p->refcount--; + if (p->refcount == 0) + list_del(&p->list); + + mutex_unlock(&pc_lists_lock); + + if (p->refcount == 0) { + destroy_workqueue(p->wq); + smd_close(p->ch); + kfree(p); + } +} + +static int event_exists(struct dalrpc_port *p, + struct dalrpc_event_handle *ev) +{ + struct dalrpc_event_handle *ev_iter; + + /* this function must be called with event_list_lock acquired */ + + list_for_each_entry(ev_iter, &p->event_list, list) + if (ev_iter == ev) + return 1; + + return 0; +} + +static int cb_exists(struct dalrpc_port *p, + struct dalrpc_cb_handle *cb) +{ + struct dalrpc_cb_handle *cb_iter; + + /* this function must be called with the cb_list_lock acquired */ + + list_for_each_entry(cb_iter, &p->cb_list, list) + if (cb_iter == cb) + return 1; + + return 0; +} + +static int check_version(struct dalrpc_msg_hdr *msg_hdr) +{ + static int version_msg = 1; + + /* disabled because asynch events currently have no version */ + return 0; + + if (msg_hdr->proto_ver != DALRPC_PROTOCOL_VERSION) { + if (version_msg) { + printk(KERN_ERR "dalrpc: incompatible verison\n"); + version_msg = 0; + } + return -1; + } + return 0; +} + +static void process_asynch(struct dalrpc_port *p) +{ + struct dalrpc_event_handle *ev; + struct dalrpc_cb_handle *cb; + + ev = (struct dalrpc_event_handle *)p->msg_in.param[0]; + cb = (struct dalrpc_cb_handle *)p->msg_in.param[0]; + + mutex_lock(&p->event_list_lock); + if (event_exists(p, ev)) { + spin_lock(&ev->lock); + ev->flag = 1; + spin_unlock(&ev->lock); + smp_mb(); + wake_up_all(&event_wq); + mutex_unlock(&p->event_list_lock); + return; + } + mutex_unlock(&p->event_list_lock); + + mutex_lock(&p->cb_list_lock); + if (cb_exists(p, cb)) { + cb->fn(cb->context, p->msg_in.param[1], + &p->msg_in.param[3], p->msg_in.param[2]); + mutex_unlock(&p->cb_list_lock); + return; + } + mutex_unlock(&p->cb_list_lock); +} + +static void process_msg(struct dalrpc_port *p) +{ + switch (p->msg_in.hdr.msgid) { + + case DALRPC_MSGID_DDI_REPLY: + case DALRPC_MSGID_ATTACH_REPLY: + case DALRPC_MSGID_DETACH_REPLY: + complete(&p->msg_owner->read_completion); + break; + + case DALRPC_MSGID_ASYNCH: + process_asynch(p); + break; + + default: + printk(KERN_ERR "process_msg: bad msgid %#x\n", + p->msg_in.hdr.msgid); + } +} + +static void flush_msg(struct dalrpc_port *p) +{ + int bytes_read, len; + + len = p->msg_in.hdr.len - sizeof(struct dalrpc_msg_hdr); + while (len > 0) { + bytes_read = smd_read(p->ch, NULL, len); + if (bytes_read <= 0) + break; + len -= bytes_read; + } + p->msg_bytes_read = 0; +} + +static int check_header(struct dalrpc_port *p) +{ + if (check_version(&p->msg_in.hdr) || + p->msg_in.hdr.len > DALRPC_MAX_MSG_SIZE || + (p->msg_in.hdr.msgid != DALRPC_MSGID_ASYNCH && + !client_exists_locked(p->msg_in.hdr.to))) { + printk(KERN_ERR "dalrpc_read_msg: bad msg\n"); + flush_msg(p); + return 1; + } + p->msg_owner = (struct daldevice_handle *)p->msg_in.hdr.to; + + if (p->msg_in.hdr.msgid != DALRPC_MSGID_ASYNCH) + memcpy(&p->msg_owner->msg.hdr, &p->msg_in.hdr, + sizeof(p->msg_in.hdr)); + + return 0; +} + +static int dalrpc_read_msg(struct dalrpc_port *p) +{ + uint8_t *read_ptr; + int bytes_read; + + /* read msg header */ + while (p->msg_bytes_read < sizeof(p->msg_in.hdr)) { + read_ptr = (uint8_t *)&p->msg_in.hdr + p->msg_bytes_read; + + bytes_read = smd_read(p->ch, read_ptr, + sizeof(p->msg_in.hdr) - + p->msg_bytes_read); + if (bytes_read <= 0) + return 0; + p->msg_bytes_read += bytes_read; + + if (p->msg_bytes_read == sizeof(p->msg_in.hdr) && + check_header(p)) + return 1; + } + + /* read remainder of msg */ + if (p->msg_in.hdr.msgid != DALRPC_MSGID_ASYNCH) + read_ptr = (uint8_t *)&p->msg_owner->msg; + else + read_ptr = (uint8_t *)&p->msg_in; + read_ptr += p->msg_bytes_read; + + while (p->msg_bytes_read < p->msg_in.hdr.len) { + bytes_read = smd_read(p->ch, read_ptr, + p->msg_in.hdr.len - p->msg_bytes_read); + if (bytes_read <= 0) + return 0; + p->msg_bytes_read += bytes_read; + read_ptr += bytes_read; + } + + process_msg(p); + p->msg_bytes_read = 0; + p->msg_owner = NULL; + + return 1; +} + +static void dalrpc_work(struct work_struct *work) +{ + struct dalrpc_port *p = container_of(work, + struct dalrpc_port, + port_work); + + /* must lock port/client lists to ensure port doesn't disappear + under an asynch event */ + mutex_lock(&pc_lists_lock); + if (port_exists(p)) + while (dalrpc_read_msg(p)) + ; + mutex_unlock(&pc_lists_lock); +} + +static void dalrpc_smd_cb(void *priv, unsigned smd_flags) +{ + struct dalrpc_port *p = priv; + + if (smd_flags != SMD_EVENT_DATA) + return; + + queue_work(p->wq, &p->port_work); +} + +static struct dalrpc_port *dalrpc_port_open(char *port, int cpu) +{ + struct dalrpc_port *p; + char wq_name[32]; + + p = port_name_exists(port); + if (p) { + p->refcount++; + return p; + } + + p = kzalloc(sizeof(struct dalrpc_port), GFP_KERNEL); + if (!p) + return NULL; + + strncpy(p->port, port, sizeof(p->port) - 1); + p->refcount = 1; + + snprintf(wq_name, sizeof(wq_name), "dalrpc_rcv_%s", port); + p->wq = create_singlethread_workqueue(wq_name); + if (!p->wq) { + printk(KERN_ERR "dalrpc_init: unable to create workqueue\n"); + goto no_wq; + } + INIT_WORK(&p->port_work, dalrpc_work); + + mutex_init(&p->write_lock); + mutex_init(&p->event_list_lock); + mutex_init(&p->cb_list_lock); + + INIT_LIST_HEAD(&p->event_list); + INIT_LIST_HEAD(&p->cb_list); + + p->msg_owner = NULL; + p->msg_bytes_read = 0; + + if (smd_named_open_on_edge(port, cpu, &p->ch, p, + dalrpc_smd_cb)) { + printk(KERN_ERR "dalrpc_port_init() failed to open port\n"); + goto no_smd; + } + + list_add(&p->list, &port_list); + + return p; + +no_smd: + destroy_workqueue(p->wq); +no_wq: + kfree(p); + return NULL; +} + +static void dalrpc_sendwait(struct daldevice_handle *h) +{ + u8 *buf = (u8 *)&h->msg; + int len = h->msg.hdr.len; + int written; + + mutex_lock(&h->port->write_lock); + do { + written = smd_write(h->port->ch, buf + (h->msg.hdr.len - len), + len); + if (written < 0) + break; + len -= written; + } while (len); + mutex_unlock(&h->port->write_lock); + + wait_for_completion(&h->read_completion); +} + +int daldevice_attach(uint32_t device_id, char *port, int cpu, + void **handle_ptr) +{ + struct daldevice_handle *h; + char dyn_port[DALRPC_MAX_PORTNAME_LEN + 1] = "DAL00"; + int ret; + int tries = 0; + + if (!port) + port = dyn_port; + + if (strlen(port) > DALRPC_MAX_PORTNAME_LEN) + return -EINVAL; + + h = kzalloc(sizeof(struct daldevice_handle), GFP_KERNEL); + if (!h) { + *handle_ptr = NULL; + return -ENOMEM; + } + + init_completion(&h->read_completion); + mutex_init(&h->client_lock); + + mutex_lock(&pc_lists_lock); + list_add(&h->list, &client_list); + mutex_unlock(&pc_lists_lock); + + /* 3 attempts, enough for one each on the user specified port, the + * dynamic discovery port, and the port recommended by the dynamic + * discovery port */ + while (tries < 3) { + tries++; + + mutex_lock(&pc_lists_lock); + h->port = dalrpc_port_open(port, cpu); + if (!h->port) { + list_del(&h->list); + mutex_unlock(&pc_lists_lock); + printk(KERN_ERR "daldevice_attach: could not " + "open port\n"); + kfree(h); + *handle_ptr = NULL; + return -EIO; + } + mutex_unlock(&pc_lists_lock); + + h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 4 + + DALRPC_MAX_ATTACH_PARAM_LEN + + DALRPC_MAX_SERVICE_NAME_LEN; + h->msg.hdr.proto_ver = DALRPC_PROTOCOL_VERSION; + h->msg.hdr.ddi_idx = 0; + h->msg.hdr.msgid = 0x1; + h->msg.hdr.prio = 0; + h->msg.hdr.async = 0; + h->msg.hdr.from = h; + h->msg.hdr.to = 0; + h->msg.param[0] = device_id; + + memset(&h->msg.param[1], 0, + DALRPC_MAX_ATTACH_PARAM_LEN + + DALRPC_MAX_SERVICE_NAME_LEN); + + dalrpc_sendwait(h); + ret = h->msg.param[0]; + + if (ret == DALRPC_SUCCESS) { + h->remote_handle = h->msg.hdr.from; + *handle_ptr = h; + break; + } else if (strnlen((char *)&h->msg.param[1], + DALRPC_MAX_PORTNAME_LEN)) { + /* another port was recommended in the response. */ + strncpy(dyn_port, (char *)&h->msg.param[1], + DALRPC_MAX_PORTNAME_LEN); + dyn_port[DALRPC_MAX_PORTNAME_LEN] = 0; + port = dyn_port; + } else if (port == dyn_port) { + /* the dynamic discovery port (or port that + * was recommended by it) did not recognize + * the device id, give up */ + daldevice_detach(h); + break; + } else + /* the user specified port did not work, try + * the dynamic discovery port */ + port = dyn_port; + + port_close(h->port); + } + + return ret; +} +EXPORT_SYMBOL(daldevice_attach); + +static void dalrpc_ddi_prologue(uint32_t ddi_idx, struct daldevice_handle *h) +{ + h->msg.hdr.proto_ver = DALRPC_PROTOCOL_VERSION; + h->msg.hdr.prio = 0; + h->msg.hdr.async = 0; + h->msg.hdr.msgid = DALRPC_MSGID_DDI; + h->msg.hdr.from = h; + h->msg.hdr.to = h->remote_handle; + h->msg.hdr.ddi_idx = ddi_idx; +} + +int daldevice_detach(void *handle) +{ + struct daldevice_handle *h = handle; + + if (!client_exists(h)) + return -EINVAL; + + dalrpc_ddi_prologue(0, h); + + if (!h->remote_handle) + goto norpc; + + h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 4; + h->msg.hdr.msgid = 0x2; + h->msg.param[0] = 0; + + dalrpc_sendwait(h); + +norpc: + mutex_lock(&pc_lists_lock); + list_del(&h->list); + mutex_unlock(&pc_lists_lock); + + port_close(h->port); + + kfree(h); + + return 0; +} +EXPORT_SYMBOL(daldevice_detach); + +uint32_t dalrpc_fcn_0(uint32_t ddi_idx, void *handle, uint32_t s1) +{ + struct daldevice_handle *h = handle; + uint32_t ret; + + if (!client_exists(h)) + return -EINVAL; + + mutex_lock(&h->client_lock); + + dalrpc_ddi_prologue(ddi_idx, h); + + h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 4; + h->msg.hdr.proto_id = 0; + h->msg.param[0] = s1; + + dalrpc_sendwait(h); + + ret = h->msg.param[0]; + mutex_unlock(&h->client_lock); + return ret; +} +EXPORT_SYMBOL(dalrpc_fcn_0); + +uint32_t dalrpc_fcn_1(uint32_t ddi_idx, void *handle, uint32_t s1, + uint32_t s2) +{ + struct daldevice_handle *h = handle; + uint32_t ret; + + if (!client_exists(h)) + return -EINVAL; + + mutex_lock(&h->client_lock); + + dalrpc_ddi_prologue(ddi_idx, h); + + h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 8; + h->msg.hdr.proto_id = 1; + h->msg.param[0] = s1; + h->msg.param[1] = s2; + + dalrpc_sendwait(h); + + ret = h->msg.param[0]; + mutex_unlock(&h->client_lock); + return ret; +} +EXPORT_SYMBOL(dalrpc_fcn_1); + +uint32_t dalrpc_fcn_2(uint32_t ddi_idx, void *handle, uint32_t s1, + uint32_t *p_s2) +{ + struct daldevice_handle *h = handle; + uint32_t ret; + + if (!client_exists(h)) + return -EINVAL; + + mutex_lock(&h->client_lock); + + dalrpc_ddi_prologue(ddi_idx, h); + + h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 4; + h->msg.hdr.proto_id = 2; + h->msg.param[0] = s1; + + dalrpc_sendwait(h); + + if (h->msg.param[0] == DALRPC_SUCCESS) + *p_s2 = h->msg.param[1]; + + ret = h->msg.param[0]; + mutex_unlock(&h->client_lock); + return ret; +} +EXPORT_SYMBOL(dalrpc_fcn_2); + +uint32_t dalrpc_fcn_3(uint32_t ddi_idx, void *handle, uint32_t s1, + uint32_t s2, uint32_t s3) +{ + struct daldevice_handle *h = handle; + uint32_t ret; + + if (!client_exists(h)) + return -EINVAL; + + mutex_lock(&h->client_lock); + + dalrpc_ddi_prologue(ddi_idx, h); + + h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 12; + h->msg.hdr.proto_id = 3; + h->msg.param[0] = s1; + h->msg.param[1] = s2; + h->msg.param[2] = s3; + + dalrpc_sendwait(h); + + ret = h->msg.param[0]; + mutex_unlock(&h->client_lock); + return ret; +} +EXPORT_SYMBOL(dalrpc_fcn_3); + +uint32_t dalrpc_fcn_4(uint32_t ddi_idx, void *handle, uint32_t s1, + uint32_t s2, uint32_t *p_s3) +{ + struct daldevice_handle *h = handle; + uint32_t ret; + + if (!client_exists(h)) + return -EINVAL; + + mutex_lock(&h->client_lock); + + dalrpc_ddi_prologue(ddi_idx, h); + + h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 8; + h->msg.hdr.proto_id = 4; + h->msg.param[0] = s1; + h->msg.param[1] = s2; + + dalrpc_sendwait(h); + + if (h->msg.param[0] == DALRPC_SUCCESS) + *p_s3 = h->msg.param[1]; + + ret = h->msg.param[0]; + mutex_unlock(&h->client_lock); + return ret; +} +EXPORT_SYMBOL(dalrpc_fcn_4); + +uint32_t dalrpc_fcn_5(uint32_t ddi_idx, void *handle, const void *ibuf, + uint32_t ilen) +{ + struct daldevice_handle *h = handle; + uint32_t ret; + + if ((ilen + 4) > DALRPC_MAX_PARAMS_SIZE) + return -EINVAL; + + if (!client_exists(h)) + return -EINVAL; + + mutex_lock(&h->client_lock); + + dalrpc_ddi_prologue(ddi_idx, h); + + h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 4 + + ROUND_BUFLEN(ilen); + h->msg.hdr.proto_id = 5; + h->msg.param[0] = ilen; + memcpy(&h->msg.param[1], ibuf, ilen); + + dalrpc_sendwait(h); + + ret = h->msg.param[0]; + mutex_unlock(&h->client_lock); + return ret; +} +EXPORT_SYMBOL(dalrpc_fcn_5); + +uint32_t dalrpc_fcn_6(uint32_t ddi_idx, void *handle, uint32_t s1, + const void *ibuf, uint32_t ilen) +{ + struct daldevice_handle *h = handle; + uint32_t ret; + + if ((ilen + 8) > DALRPC_MAX_PARAMS_SIZE) + return -EINVAL; + + if (!client_exists(h)) + return -EINVAL; + + mutex_lock(&h->client_lock); + + dalrpc_ddi_prologue(ddi_idx, h); + + h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 8 + + ROUND_BUFLEN(ilen); + h->msg.hdr.proto_id = 6; + h->msg.param[0] = s1; + h->msg.param[1] = ilen; + memcpy(&h->msg.param[2], ibuf, ilen); + + dalrpc_sendwait(h); + + ret = h->msg.param[0]; + mutex_unlock(&h->client_lock); + return ret; +} +EXPORT_SYMBOL(dalrpc_fcn_6); + +uint32_t dalrpc_fcn_7(uint32_t ddi_idx, void *handle, const void *ibuf, + uint32_t ilen, void *obuf, uint32_t olen, + uint32_t *oalen) +{ + struct daldevice_handle *h = handle; + uint32_t ret; + int param_idx; + + if ((ilen + 8) > DALRPC_MAX_PARAMS_SIZE || + (olen + 4) > DALRPC_MAX_PARAMS_SIZE) + return -EINVAL; + + + if (!client_exists(h)) + return -EINVAL; + + mutex_lock(&h->client_lock); + + dalrpc_ddi_prologue(ddi_idx, h); + + h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 8 + + ROUND_BUFLEN(ilen); + h->msg.hdr.proto_id = 7; + h->msg.param[0] = ilen; + memcpy(&h->msg.param[1], ibuf, ilen); + param_idx = (ROUND_BUFLEN(ilen) / 4) + 1; + h->msg.param[param_idx] = olen; + + dalrpc_sendwait(h); + + if (h->msg.param[0] == DALRPC_SUCCESS) { + if (h->msg.param[1] > olen) { + mutex_unlock(&h->client_lock); + return -EIO; + } + *oalen = h->msg.param[1]; + memcpy(obuf, &h->msg.param[2], h->msg.param[1]); + } + + ret = h->msg.param[0]; + mutex_unlock(&h->client_lock); + return ret; +} +EXPORT_SYMBOL(dalrpc_fcn_7); + +uint32_t dalrpc_fcn_8(uint32_t ddi_idx, void *handle, const void *ibuf, + uint32_t ilen, void *obuf, uint32_t olen) +{ + struct daldevice_handle *h = handle; + uint32_t ret; + int param_idx; + + if ((ilen + 8) > DALRPC_MAX_PARAMS_SIZE || + (olen + 4) > DALRPC_MAX_PARAMS_SIZE) + return -EINVAL; + + if (!client_exists(h)) + return -EINVAL; + + mutex_lock(&h->client_lock); + + dalrpc_ddi_prologue(ddi_idx, h); + + h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 8 + + ROUND_BUFLEN(ilen); + h->msg.hdr.proto_id = 8; + h->msg.param[0] = ilen; + memcpy(&h->msg.param[1], ibuf, ilen); + param_idx = (ROUND_BUFLEN(ilen) / 4) + 1; + h->msg.param[param_idx] = olen; + + dalrpc_sendwait(h); + + if (h->msg.param[0] == DALRPC_SUCCESS) { + if (h->msg.param[1] > olen) { + mutex_unlock(&h->client_lock); + return -EIO; + } + memcpy(obuf, &h->msg.param[2], h->msg.param[1]); + } + + ret = h->msg.param[0]; + mutex_unlock(&h->client_lock); + return ret; +} +EXPORT_SYMBOL(dalrpc_fcn_8); + +uint32_t dalrpc_fcn_9(uint32_t ddi_idx, void *handle, void *obuf, + uint32_t olen) +{ + struct daldevice_handle *h = handle; + uint32_t ret; + + if ((olen + 4) > DALRPC_MAX_PARAMS_SIZE) + return -EINVAL; + + if (!client_exists(h)) + return -EINVAL; + + mutex_lock(&h->client_lock); + + dalrpc_ddi_prologue(ddi_idx, h); + + h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 4; + h->msg.hdr.proto_id = 9; + h->msg.param[0] = olen; + + dalrpc_sendwait(h); + + if (h->msg.param[0] == DALRPC_SUCCESS) { + if (h->msg.param[1] > olen) { + mutex_unlock(&h->client_lock); + return -EIO; + } + memcpy(obuf, &h->msg.param[2], h->msg.param[1]); + } + + ret = h->msg.param[0]; + mutex_unlock(&h->client_lock); + return ret; +} +EXPORT_SYMBOL(dalrpc_fcn_9); + +uint32_t dalrpc_fcn_10(uint32_t ddi_idx, void *handle, uint32_t s1, + const void *ibuf, uint32_t ilen, void *obuf, + uint32_t olen, uint32_t *oalen) +{ + struct daldevice_handle *h = handle; + uint32_t ret; + int param_idx; + + if ((ilen + 12) > DALRPC_MAX_PARAMS_SIZE || + (olen + 4) > DALRPC_MAX_PARAMS_SIZE) + return -EINVAL; + + if (!client_exists(h)) + return -EINVAL; + + mutex_lock(&h->client_lock); + + dalrpc_ddi_prologue(ddi_idx, h); + + h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 12 + + ROUND_BUFLEN(ilen); + h->msg.hdr.proto_id = 10; + h->msg.param[0] = s1; + h->msg.param[1] = ilen; + memcpy(&h->msg.param[2], ibuf, ilen); + param_idx = (ROUND_BUFLEN(ilen) / 4) + 2; + h->msg.param[param_idx] = olen; + + dalrpc_sendwait(h); + + if (h->msg.param[0] == DALRPC_SUCCESS) { + if (h->msg.param[1] > olen) { + mutex_unlock(&h->client_lock); + return -EIO; + } + *oalen = h->msg.param[1]; + memcpy(obuf, &h->msg.param[2], h->msg.param[1]); + } + + ret = h->msg.param[0]; + mutex_unlock(&h->client_lock); + return ret; +} +EXPORT_SYMBOL(dalrpc_fcn_10); + +uint32_t dalrpc_fcn_11(uint32_t ddi_idx, void *handle, uint32_t s1, + void *obuf, uint32_t olen) +{ + struct daldevice_handle *h = handle; + uint32_t ret; + + if ((olen + 4) > DALRPC_MAX_PARAMS_SIZE) + return -EINVAL; + + if (!client_exists(h)) + return -EINVAL; + + mutex_lock(&h->client_lock); + + dalrpc_ddi_prologue(ddi_idx, h); + + h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 8; + h->msg.hdr.proto_id = 11; + h->msg.param[0] = s1; + h->msg.param[1] = olen; + + dalrpc_sendwait(h); + + if (h->msg.param[0] == DALRPC_SUCCESS) { + if (h->msg.param[1] > olen) { + mutex_unlock(&h->client_lock); + return -EIO; + } + memcpy(obuf, &h->msg.param[2], h->msg.param[1]); + } + + ret = h->msg.param[0]; + mutex_unlock(&h->client_lock); + return ret; +} +EXPORT_SYMBOL(dalrpc_fcn_11); + +uint32_t dalrpc_fcn_12(uint32_t ddi_idx, void *handle, uint32_t s1, + void *obuf, uint32_t olen, uint32_t *oalen) +{ + struct daldevice_handle *h = handle; + uint32_t ret; + + if ((olen + 4) > DALRPC_MAX_PARAMS_SIZE) + return -EINVAL; + + if (!client_exists(h)) + return -EINVAL; + + mutex_lock(&h->client_lock); + + dalrpc_ddi_prologue(ddi_idx, h); + + h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 8; + h->msg.hdr.proto_id = 12; + h->msg.param[0] = s1; + h->msg.param[1] = olen; + + dalrpc_sendwait(h); + + if (h->msg.param[0] == DALRPC_SUCCESS) { + if (h->msg.param[1] > olen) { + mutex_unlock(&h->client_lock); + return -EIO; + } + *oalen = h->msg.param[1]; + memcpy(obuf, &h->msg.param[2], h->msg.param[1]); + } + + ret = h->msg.param[0]; + mutex_unlock(&h->client_lock); + return ret; +} +EXPORT_SYMBOL(dalrpc_fcn_12); + +uint32_t dalrpc_fcn_13(uint32_t ddi_idx, void *handle, const void *ibuf, + uint32_t ilen, const void *ibuf2, uint32_t ilen2, + void *obuf, uint32_t olen) +{ + struct daldevice_handle *h = handle; + uint32_t ret; + int param_idx; + + if ((ilen + ilen2 + 12) > DALRPC_MAX_PARAMS_SIZE || + (olen + 4) > DALRPC_MAX_PARAMS_SIZE) + return -EINVAL; + + if (!client_exists(h)) + return -EINVAL; + + mutex_lock(&h->client_lock); + + dalrpc_ddi_prologue(ddi_idx, h); + + h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 12 + + ROUND_BUFLEN(ilen) + ROUND_BUFLEN(ilen2); + h->msg.hdr.proto_id = 13; + h->msg.param[0] = ilen; + memcpy(&h->msg.param[1], ibuf, ilen); + param_idx = (ROUND_BUFLEN(ilen) / 4) + 1; + h->msg.param[param_idx++] = ilen2; + memcpy(&h->msg.param[param_idx], ibuf2, ilen2); + param_idx += (ROUND_BUFLEN(ilen2) / 4); + h->msg.param[param_idx] = olen; + + dalrpc_sendwait(h); + + if (h->msg.param[0] == DALRPC_SUCCESS) { + if (h->msg.param[1] > olen) { + mutex_unlock(&h->client_lock); + return -EIO; + } + memcpy(obuf, &h->msg.param[2], h->msg.param[1]); + } + + ret = h->msg.param[0]; + mutex_unlock(&h->client_lock); + return ret; +} +EXPORT_SYMBOL(dalrpc_fcn_13); + +uint32_t dalrpc_fcn_14(uint32_t ddi_idx, void *handle, const void *ibuf, + uint32_t ilen, void *obuf, uint32_t olen, + void *obuf2, uint32_t olen2, uint32_t *oalen2) +{ + struct daldevice_handle *h = handle; + uint32_t ret; + int param_idx; + + if ((ilen + 12) > DALRPC_MAX_PARAMS_SIZE || + (olen + olen2 + 8) > DALRPC_MAX_PARAMS_SIZE) + return -EINVAL; + + if (!client_exists(h)) + return -EINVAL; + + mutex_lock(&h->client_lock); + + dalrpc_ddi_prologue(ddi_idx, h); + + h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 12 + + ROUND_BUFLEN(ilen); + h->msg.hdr.proto_id = 14; + h->msg.param[0] = ilen; + memcpy(&h->msg.param[1], ibuf, ilen); + param_idx = (ROUND_BUFLEN(ilen) / 4) + 1; + h->msg.param[param_idx++] = olen; + h->msg.param[param_idx] = olen2; + + dalrpc_sendwait(h); + + if (h->msg.param[0] == DALRPC_SUCCESS) { + if (h->msg.param[1] > olen) { + mutex_unlock(&h->client_lock); + return -EIO; + } + param_idx = (ROUND_BUFLEN(h->msg.param[1]) / 4) + 2; + if (h->msg.param[param_idx] > olen2) { + mutex_unlock(&h->client_lock); + return -EIO; + } + memcpy(obuf, &h->msg.param[2], h->msg.param[1]); + memcpy(obuf2, &h->msg.param[param_idx + 1], + h->msg.param[param_idx]); + *oalen2 = h->msg.param[param_idx]; + } + + ret = h->msg.param[0]; + mutex_unlock(&h->client_lock); + return ret; +} +EXPORT_SYMBOL(dalrpc_fcn_14); + +uint32_t dalrpc_fcn_15(uint32_t ddi_idx, void *handle, const void *ibuf, + uint32_t ilen, const void *ibuf2, uint32_t ilen2, + void *obuf, uint32_t olen, uint32_t *oalen, + void *obuf2, uint32_t olen2) +{ + struct daldevice_handle *h = handle; + uint32_t ret; + int param_idx; + + if ((ilen + ilen2 + 16) > DALRPC_MAX_PARAMS_SIZE || + (olen + olen2 + 8) > DALRPC_MAX_PARAMS_SIZE) + return -EINVAL; + + if (!client_exists(h)) + return -EINVAL; + + mutex_lock(&h->client_lock); + + dalrpc_ddi_prologue(ddi_idx, h); + + h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 16 + + ROUND_BUFLEN(ilen) + ROUND_BUFLEN(ilen2); + h->msg.hdr.proto_id = 15; + h->msg.param[0] = ilen; + memcpy(&h->msg.param[1], ibuf, ilen); + param_idx = (ROUND_BUFLEN(ilen) / 4) + 1; + h->msg.param[param_idx++] = ilen2; + memcpy(&h->msg.param[param_idx], ibuf2, ilen2); + param_idx += (ROUND_BUFLEN(ilen2) / 4); + h->msg.param[param_idx++] = olen; + h->msg.param[param_idx] = olen2; + + dalrpc_sendwait(h); + + if (h->msg.param[0] == DALRPC_SUCCESS) { + if (h->msg.param[1] > olen) { + mutex_unlock(&h->client_lock); + return -EIO; + } + param_idx = (ROUND_BUFLEN(h->msg.param[1]) / 4) + 2; + if (h->msg.param[param_idx] > olen2) { + mutex_unlock(&h->client_lock); + return -EIO; + } + memcpy(obuf, &h->msg.param[2], h->msg.param[1]); + memcpy(obuf2, &h->msg.param[param_idx + 1], + h->msg.param[param_idx]); + *oalen = h->msg.param[1]; + } + + ret = h->msg.param[0]; + mutex_unlock(&h->client_lock); + return ret; +} +EXPORT_SYMBOL(dalrpc_fcn_15); + +void *dalrpc_alloc_event(void *handle) +{ + struct daldevice_handle *h; + struct dalrpc_event_handle *ev; + + h = (struct daldevice_handle *)handle; + + if (!client_exists(h)) + return NULL; + + ev = kmalloc(sizeof(struct dalrpc_event_handle), GFP_KERNEL); + if (!ev) + return NULL; + + ev->flag = 0; + spin_lock_init(&ev->lock); + + mutex_lock(&h->port->event_list_lock); + list_add(&ev->list, &h->port->event_list); + mutex_unlock(&h->port->event_list_lock); + + return ev; +} +EXPORT_SYMBOL(dalrpc_alloc_event); + +void *dalrpc_alloc_cb(void *handle, + void (*fn)(void *, uint32_t, void *, uint32_t), + void *context) +{ + struct daldevice_handle *h; + struct dalrpc_cb_handle *cb; + + h = (struct daldevice_handle *)handle; + + if (!client_exists(h)) + return NULL; + + cb = kmalloc(sizeof(struct dalrpc_cb_handle), GFP_KERNEL); + if (!cb) + return NULL; + + cb->fn = fn; + cb->context = context; + + mutex_lock(&h->port->cb_list_lock); + list_add(&cb->list, &h->port->cb_list); + mutex_unlock(&h->port->cb_list_lock); + + return cb; +} +EXPORT_SYMBOL(dalrpc_alloc_cb); + +void dalrpc_dealloc_event(void *handle, + void *ev_h) +{ + struct daldevice_handle *h; + struct dalrpc_event_handle *ev; + + h = (struct daldevice_handle *)handle; + ev = (struct dalrpc_event_handle *)ev_h; + + mutex_lock(&h->port->event_list_lock); + list_del(&ev->list); + mutex_unlock(&h->port->event_list_lock); + kfree(ev); +} +EXPORT_SYMBOL(dalrpc_dealloc_event); + +void dalrpc_dealloc_cb(void *handle, + void *cb_h) +{ + struct daldevice_handle *h; + struct dalrpc_cb_handle *cb; + + h = (struct daldevice_handle *)handle; + cb = (struct dalrpc_cb_handle *)cb_h; + + mutex_lock(&h->port->cb_list_lock); + list_del(&cb->list); + mutex_unlock(&h->port->cb_list_lock); + kfree(cb); +} +EXPORT_SYMBOL(dalrpc_dealloc_cb); + +static int event_occurred(int num_events, struct dalrpc_event_handle **events, + int *occurred) +{ + int i; + + for (i = 0; i < num_events; i++) { + spin_lock(&events[i]->lock); + if (events[i]->flag) { + events[i]->flag = 0; + spin_unlock(&events[i]->lock); + *occurred = i; + return 1; + } + spin_unlock(&events[i]->lock); + } + + return 0; +} + +int dalrpc_event_wait_multiple(int num, void **ev_h, int timeout) +{ + struct dalrpc_event_handle **events; + int ret, occurred; + + events = (struct dalrpc_event_handle **)ev_h; + + if (timeout == DALRPC_TIMEOUT_INFINITE) { + wait_event(event_wq, + event_occurred(num, events, &occurred)); + return occurred; + } + + ret = wait_event_timeout(event_wq, + event_occurred(num, events, &occurred), + timeout); + if (ret > 0) + return occurred; + else + return -ETIMEDOUT; +} +EXPORT_SYMBOL(dalrpc_event_wait_multiple); diff --git a/arch/arm/mach-msm/dal_remotetest.c b/arch/arm/mach-msm/dal_remotetest.c new file mode 100644 index 000000000000..bbe0f1a4475c --- /dev/null +++ b/arch/arm/mach-msm/dal_remotetest.c @@ -0,0 +1,454 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +/* + * DAL remote test device test suite. + */ + +#include +#include +#include +#include +#include + +#include "dal_remotetest.h" + +#define BYTEBUF_LEN 64 + +#define rpc_error(num) \ + do { \ + errmask |= (1 << num); \ + printk(KERN_INFO "%s: remote_unittest_%d failed (%d)\n", \ + __func__, num, ret); \ + } while (0) + +#define verify_error(num, field) \ + do { \ + errmask |= (1 << num); \ + printk(KERN_INFO "%s: remote_unittest_%d failed (%s)\n", \ + __func__, num, field); \ + } while (0) + + +static struct dentry *debugfs_dir_entry; +static struct dentry *debugfs_modem_entry; +static struct dentry *debugfs_dsp_entry; + +static uint8_t in_bytebuf[BYTEBUF_LEN]; +static uint8_t out_bytebuf[BYTEBUF_LEN]; +static uint8_t out_bytebuf2[BYTEBUF_LEN]; +static struct remote_test_data in_data; +static struct remote_test_data out_data; +static int block_until_cb = 1; + +static void init_data(struct remote_test_data *data) +{ + int i; + data->regular_event = REMOTE_UNITTEST_INPUT_HANDLE; + data->payload_event = REMOTE_UNITTEST_INPUT_HANDLE; + for (i = 0; i < 32; i++) + data->test[i] = i; +} + +static int verify_data(struct remote_test_data *data) +{ + int i; + if (data->regular_event != REMOTE_UNITTEST_INPUT_HANDLE || + data->payload_event != REMOTE_UNITTEST_INPUT_HANDLE) + return -1; + for (i = 0; i < 32; i++) + if (data->test[i] != i) + return -1; + + return 0; +} + +static int verify_uint32_buffer(uint32_t *buf) +{ + int i; + for (i = 0; i < 32; i++) + if (buf[i] != i) + return -1; + + return 0; +} + +static void init_bytebuf(uint8_t *bytebuf) +{ + int i; + for (i = 0; i < BYTEBUF_LEN; i++) + bytebuf[i] = i & 0xff; +} + +static int verify_bytebuf(uint8_t *bytebuf) +{ + int i; + for (i = 0; i < BYTEBUF_LEN; i++) + if (bytebuf[i] != (i & 0xff)) + return -1; + + return 0; +} + +static void test_cb(void *context, uint32_t param, void *data, uint32_t len) +{ + block_until_cb = 0; +} + +static int remotetest_exec(int dest, u64 *val) +{ + void *dev_handle; + void *event_handles[3]; + void *cb_handle; + int ret; + u64 errmask = 0; + uint32_t ouint; + uint32_t oalen; + + /* test daldevice_attach */ + ret = daldevice_attach(REMOTE_UNITTEST_DEVICEID, NULL, + dest, &dev_handle); + if (ret) { + printk(KERN_INFO "%s: failed to attach (%d)\n", __func__, ret); + *val = 0xffffffff; + return 0; + } + + /* test remote_unittest_0 */ + ret = remote_unittest_0(dev_handle, REMOTE_UNITTEST_INARG_1); + if (ret) + rpc_error(0); + + /* test remote_unittest_1 */ + ret = remote_unittest_1(dev_handle, REMOTE_UNITTEST_INARG_1, + REMOTE_UNITTEST_INARG_2); + if (ret) + rpc_error(1); + + /* test remote_unittest_2 */ + ouint = 0; + ret = remote_unittest_2(dev_handle, REMOTE_UNITTEST_INARG_1, &ouint); + if (ret) + rpc_error(2); + else if (ouint != REMOTE_UNITTEST_OUTARG_1) + verify_error(2, "ouint"); + + /* test remote_unittest_3 */ + ret = remote_unittest_3(dev_handle, REMOTE_UNITTEST_INARG_1, + REMOTE_UNITTEST_INARG_2, + REMOTE_UNITTEST_INARG_3); + if (ret) + rpc_error(3); + + /* test remote_unittest_4 */ + ouint = 0; + ret = remote_unittest_4(dev_handle, REMOTE_UNITTEST_INARG_1, + REMOTE_UNITTEST_INARG_2, &ouint); + if (ret) + rpc_error(4); + else if (ouint != REMOTE_UNITTEST_OUTARG_1) + verify_error(4, "ouint"); + + /* test remote_unittest_5 */ + init_data(&in_data); + ret = remote_unittest_5(dev_handle, &in_data, sizeof(in_data)); + if (ret) + rpc_error(5); + + /* test remote_unittest_6 */ + init_data(&in_data); + ret = remote_unittest_6(dev_handle, REMOTE_UNITTEST_INARG_1, + &in_data.test, sizeof(in_data.test)); + if (ret) + rpc_error(6); + + /* test remote_unittest_7 */ + init_data(&in_data); + memset(&out_data, 0, sizeof(out_data)); + ret = remote_unittest_7(dev_handle, &in_data, sizeof(in_data), + &out_data.test, sizeof(out_data.test), + &oalen); + if (ret) + rpc_error(7); + else if (oalen != sizeof(out_data.test)) + verify_error(7, "oalen"); + else if (verify_uint32_buffer(out_data.test)) + verify_error(7, "obuf"); + + /* test remote_unittest_8 */ + init_bytebuf(in_bytebuf); + memset(&out_data, 0, sizeof(out_data)); + ret = remote_unittest_8(dev_handle, in_bytebuf, sizeof(in_bytebuf), + &out_data, sizeof(out_data)); + if (ret) + rpc_error(8); + else if (verify_data(&out_data)) + verify_error(8, "obuf"); + + /* test remote_unittest_9 */ + memset(&out_bytebuf, 0, sizeof(out_bytebuf)); + ret = remote_unittest_9(dev_handle, out_bytebuf, sizeof(out_bytebuf)); + if (ret) + rpc_error(9); + else if (verify_bytebuf(out_bytebuf)) + verify_error(9, "obuf"); + + /* test remote_unittest_10 */ + init_bytebuf(in_bytebuf); + memset(&out_bytebuf, 0, sizeof(out_bytebuf)); + ret = remote_unittest_10(dev_handle, REMOTE_UNITTEST_INARG_1, + in_bytebuf, sizeof(in_bytebuf), + out_bytebuf, sizeof(out_bytebuf), &oalen); + if (ret) + rpc_error(10); + else if (oalen != sizeof(out_bytebuf)) + verify_error(10, "oalen"); + else if (verify_bytebuf(out_bytebuf)) + verify_error(10, "obuf"); + + /* test remote_unittest_11 */ + memset(&out_bytebuf, 0, sizeof(out_bytebuf)); + ret = remote_unittest_11(dev_handle, REMOTE_UNITTEST_INARG_1, + out_bytebuf, sizeof(out_bytebuf)); + if (ret) + rpc_error(11); + else if (verify_bytebuf(out_bytebuf)) + verify_error(11, "obuf"); + + /* test remote_unittest_12 */ + memset(&out_bytebuf, 0, sizeof(out_bytebuf)); + ret = remote_unittest_12(dev_handle, REMOTE_UNITTEST_INARG_1, + out_bytebuf, sizeof(out_bytebuf), &oalen); + if (ret) + rpc_error(12); + else if (oalen != sizeof(out_bytebuf)) + verify_error(12, "oalen"); + else if (verify_bytebuf(out_bytebuf)) + verify_error(12, "obuf"); + + /* test remote_unittest_13 */ + init_data(&in_data); + memset(&out_data, 0, sizeof(out_data)); + ret = remote_unittest_13(dev_handle, in_data.test, sizeof(in_data.test), + &in_data, sizeof(in_data), + &out_data, sizeof(out_data)); + if (ret) + rpc_error(13); + else if (verify_data(&out_data)) + verify_error(13, "obuf"); + + /* test remote_unittest_14 */ + init_data(&in_data); + memset(out_bytebuf, 0, sizeof(out_bytebuf)); + memset(out_bytebuf2, 0, sizeof(out_bytebuf2)); + ret = remote_unittest_14(dev_handle, + in_data.test, sizeof(in_data.test), + out_bytebuf, sizeof(out_bytebuf), + out_bytebuf2, sizeof(out_bytebuf2), &oalen); + if (ret) + rpc_error(14); + else if (verify_bytebuf(out_bytebuf)) + verify_error(14, "obuf"); + else if (oalen != sizeof(out_bytebuf2)) + verify_error(14, "oalen"); + else if (verify_bytebuf(out_bytebuf2)) + verify_error(14, "obuf2"); + + /* test remote_unittest_15 */ + init_data(&in_data); + memset(out_bytebuf, 0, sizeof(out_bytebuf)); + memset(&out_data, 0, sizeof(out_data)); + ret = remote_unittest_15(dev_handle, + in_data.test, sizeof(in_data.test), + &in_data, sizeof(in_data), + &out_data, sizeof(out_data), &oalen, + out_bytebuf, sizeof(out_bytebuf)); + if (ret) + rpc_error(15); + else if (oalen != sizeof(out_data)) + verify_error(15, "oalen"); + else if (verify_bytebuf(out_bytebuf)) + verify_error(15, "obuf"); + else if (verify_data(&out_data)) + verify_error(15, "obuf2"); + + /* test setting up asynch events */ + event_handles[0] = dalrpc_alloc_event(dev_handle); + event_handles[1] = dalrpc_alloc_event(dev_handle); + event_handles[2] = dalrpc_alloc_event(dev_handle); + cb_handle = dalrpc_alloc_cb(dev_handle, test_cb, &out_data); + in_data.regular_event = (uint32_t)event_handles[2]; + in_data.payload_event = (uint32_t)cb_handle; + ret = remote_unittest_eventcfg(dev_handle, &in_data, sizeof(in_data)); + if (ret) { + errmask |= (1 << 16); + printk(KERN_INFO "%s: failed to configure asynch (%d)\n", + __func__, ret); + } + + /* test event */ + ret = remote_unittest_eventtrig(dev_handle, + REMOTE_UNITTEST_REGULAR_EVENT); + if (ret) { + errmask |= (1 << 17); + printk(KERN_INFO "%s: failed to trigger event (%d)\n", + __func__, ret); + } + ret = dalrpc_event_wait(event_handles[2], 1000); + if (ret) { + errmask |= (1 << 18); + printk(KERN_INFO "%s: failed to receive event (%d)\n", + __func__, ret); + } + + /* test event again */ + ret = remote_unittest_eventtrig(dev_handle, + REMOTE_UNITTEST_REGULAR_EVENT); + if (ret) { + errmask |= (1 << 19); + printk(KERN_INFO "%s: failed to trigger event (%d)\n", + __func__, ret); + } + ret = dalrpc_event_wait_multiple(3, event_handles, 1000); + if (ret != 2) { + errmask |= (1 << 20); + printk(KERN_INFO "%s: failed to receive event (%d)\n", + __func__, ret); + } + + /* test callback */ + ret = remote_unittest_eventtrig(dev_handle, + REMOTE_UNITTEST_CALLBACK_EVENT); + if (ret) { + errmask |= (1 << 21); + printk(KERN_INFO "%s: failed to trigger callback (%d)\n", + __func__, ret); + } else + while (block_until_cb) + ; + + dalrpc_dealloc_cb(dev_handle, cb_handle); + dalrpc_dealloc_event(dev_handle, event_handles[0]); + dalrpc_dealloc_event(dev_handle, event_handles[1]); + dalrpc_dealloc_event(dev_handle, event_handles[2]); + + /* test daldevice_detach */ + ret = daldevice_detach(dev_handle); + if (ret) { + errmask |= (1 << 22); + printk(KERN_INFO "%s: failed to detach (%d)\n", __func__, ret); + } + + printk(KERN_INFO "%s: remote_unittest complete\n", __func__); + + *val = errmask; + return 0; +} + +static int remotetest_modem_exec(void *data, u64 *val) +{ + return remotetest_exec(DALRPC_DEST_MODEM, val); +} + +static int remotetest_dsp_exec(void *data, u64 *val) +{ + return remotetest_exec(DALRPC_DEST_QDSP, val); +} + +DEFINE_SIMPLE_ATTRIBUTE(dal_modemtest_fops, remotetest_modem_exec, + NULL, "%llu\n"); +DEFINE_SIMPLE_ATTRIBUTE(dal_dsptest_fops, remotetest_dsp_exec, + NULL, "%llu\n"); + +static int __init remotetest_init(void) +{ + debugfs_dir_entry = debugfs_create_dir("dal", 0); + if (IS_ERR(debugfs_dir_entry)) + return PTR_ERR(debugfs_dir_entry); + + debugfs_modem_entry = debugfs_create_file("modem_test", 0444, + debugfs_dir_entry, + NULL, &dal_modemtest_fops); + if (IS_ERR(debugfs_modem_entry)) { + debugfs_remove(debugfs_dir_entry); + return PTR_ERR(debugfs_modem_entry); + } + + debugfs_dsp_entry = debugfs_create_file("dsp_test", 0444, + debugfs_dir_entry, + NULL, &dal_dsptest_fops); + if (IS_ERR(debugfs_dsp_entry)) { + debugfs_remove(debugfs_modem_entry); + debugfs_remove(debugfs_dir_entry); + return PTR_ERR(debugfs_dsp_entry); + } + + return 0; +} + +static void __exit remotetest_exit(void) +{ + debugfs_remove(debugfs_modem_entry); + debugfs_remove(debugfs_dsp_entry); + debugfs_remove(debugfs_dir_entry); +} + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Test for DAL RPC"); +MODULE_VERSION("1.0"); + +module_init(remotetest_init); +module_exit(remotetest_exit); diff --git a/arch/arm/mach-msm/dal_remotetest.h b/arch/arm/mach-msm/dal_remotetest.h new file mode 100644 index 000000000000..88c058e8f7c3 --- /dev/null +++ b/arch/arm/mach-msm/dal_remotetest.h @@ -0,0 +1,216 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +/* + * DAL remote test device API. + */ + +#include + +#include + +#define REMOTE_UNITTEST_DEVICEID 0xDA1DA1DA + +enum { + DALRPC_TEST_API_0 = DALDEVICE_FIRST_DEVICE_API_IDX, + DALRPC_TEST_API_1, + DALRPC_TEST_API_2, + DALRPC_TEST_API_3, + DALRPC_TEST_API_4, + DALRPC_TEST_API_5, + DALRPC_TEST_API_6, + DALRPC_TEST_API_7, + DALRPC_TEST_API_8, + DALRPC_TEST_API_9, + DALRPC_TEST_API_10, + DALRPC_TEST_API_11, + DALRPC_TEST_API_12, + DALRPC_TEST_API_13, + DALRPC_TEST_API_14, + DALRPC_TEST_API_15, + DALRPC_TEST_API_16, + DALRPC_TEST_API_17 +}; + +#define REMOTE_UNITTEST_INARG_1 0x01010101 +#define REMOTE_UNITTEST_INARG_2 0x20202020 +#define REMOTE_UNITTEST_INARG_3 0x12121212 +#define REMOTE_UNITTEST_INPUT_HANDLE 0xDA1FDA1F +#define REMOTE_UNITTEST_OUTARG_1 0xBEEFDEAD + +#define REMOTE_UNITTEST_REGULAR_EVENT 0 +#define REMOTE_UNITTEST_CALLBACK_EVENT 1 + +#define REMOTE_UNITTEST_BAD_PARAM 0x10 + +struct remote_test_data { + uint32_t regular_event; + uint32_t test[32]; + uint32_t payload_event; +}; + +static int remote_unittest_0(void *handle, uint32_t s1) +{ + return dalrpc_fcn_0(DALRPC_TEST_API_0, handle, s1); +} + +static int remote_unittest_1(void *handle, uint32_t s1, uint32_t s2) +{ + return dalrpc_fcn_1(DALRPC_TEST_API_1, handle, s1, s2); +} + +static int remote_unittest_2(void *handle, uint32_t s1, uint32_t *p_s2) +{ + return dalrpc_fcn_2(DALRPC_TEST_API_2, handle, s1, p_s2); +} + +static int remote_unittest_3(void *handle, uint32_t s1, uint32_t s2, + uint32_t s3) +{ + return dalrpc_fcn_3(DALRPC_TEST_API_3, handle, s1, s2, s3); +} + +static int remote_unittest_4(void *handle, uint32_t s1, uint32_t s2, + uint32_t *p_s3) +{ + return dalrpc_fcn_4(DALRPC_TEST_API_4, handle, s1, s2, p_s3); +} + +static int remote_unittest_5(void *handle, const void *ibuf, uint32_t ilen) +{ + return dalrpc_fcn_5(DALRPC_TEST_API_5, handle, ibuf, ilen); +} + +static int remote_unittest_6(void *handle, uint32_t s1, const void *ibuf, + uint32_t ilen) +{ + return dalrpc_fcn_6(DALRPC_TEST_API_6, handle, s1, ibuf, ilen); +} + +static int remote_unittest_7(void *handle, const void *ibuf, uint32_t ilen, + void *obuf, uint32_t olen, uint32_t *oalen) +{ + return dalrpc_fcn_7(DALRPC_TEST_API_7, handle, ibuf, ilen, obuf, + olen, oalen); +} + +static int remote_unittest_8(void *handle, const void *ibuf, uint32_t ilen, + void *obuf, uint32_t olen) +{ + return dalrpc_fcn_8(DALRPC_TEST_API_8, handle, ibuf, ilen, obuf, olen); +} + +static int remote_unittest_9(void *handle, void *obuf, uint32_t olen) +{ + return dalrpc_fcn_9(DALRPC_TEST_API_9, handle, obuf, olen); +} + +static int remote_unittest_10(void *handle, uint32_t s1, const void *ibuf, + uint32_t ilen, void *obuf, uint32_t olen, + uint32_t *oalen) +{ + return dalrpc_fcn_10(DALRPC_TEST_API_10, handle, s1, ibuf, ilen, obuf, + olen, oalen); +} + +static int remote_unittest_11(void *handle, uint32_t s1, void *obuf, + uint32_t olen) +{ + return dalrpc_fcn_11(DALRPC_TEST_API_11, handle, s1, obuf, olen); +} + +static int remote_unittest_12(void *handle, uint32_t s1, void *obuf, + uint32_t olen, uint32_t *oalen) +{ + return dalrpc_fcn_12(DALRPC_TEST_API_12, handle, s1, obuf, olen, + oalen); +} + +static int remote_unittest_13(void *handle, const void *ibuf, uint32_t ilen, + const void *ibuf2, uint32_t ilen2, void *obuf, + uint32_t olen) +{ + return dalrpc_fcn_13(DALRPC_TEST_API_13, handle, ibuf, ilen, ibuf2, + ilen2, obuf, olen); +} + +static int remote_unittest_14(void *handle, const void *ibuf, uint32_t ilen, + void *obuf, uint32_t olen, void *obuf2, + uint32_t olen2, uint32_t *oalen2) +{ + return dalrpc_fcn_14(DALRPC_TEST_API_14, handle, ibuf, ilen, obuf, + olen, obuf2, olen2, oalen2); +} + +static int remote_unittest_15(void *handle, const void *ibuf, uint32_t ilen, + const void *ibuf2, uint32_t ilen2, void *obuf, + uint32_t olen, uint32_t *oalen, void *obuf2, + uint32_t olen2) +{ + return dalrpc_fcn_15(DALRPC_TEST_API_15, handle, ibuf, ilen, ibuf2, + ilen2, obuf, olen, oalen, obuf2, olen2); +} + +static int remote_unittest_eventcfg(void *handle, const void *ibuf, + uint32_t ilen) +{ + return dalrpc_fcn_5(DALRPC_TEST_API_16, handle, ibuf, ilen); +} + +static int remote_unittest_eventtrig(void *handle, uint32_t event_idx) +{ + return dalrpc_fcn_0(DALRPC_TEST_API_17, handle, event_idx); +} diff --git a/arch/arm/mach-msm/devices.c b/arch/arm/mach-msm/devices.c index 928a2290741b..d9edc27c6f5c 100644 --- a/arch/arm/mach-msm/devices.c +++ b/arch/arm/mach-msm/devices.c @@ -1,6 +1,7 @@ /* linux/arch/arm/mach-msm/devices.c * * Copyright (C) 2008 Google, Inc. + * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -16,17 +17,19 @@ #include #include +#include #include #include #include +#include + +#include "devices.h" #include #include #include -#include -#include "devices.h" -#include "clock.h" +#include static struct resource resources_uart1[] = { { @@ -88,6 +91,14 @@ struct platform_device msm_device_uart3 = { .resource = resources_uart3, }; +#if defined(CONFIG_ARCH_QSD) +#define MSM_UART1DM_PHYS 0xA0200000 +#define MSM_UART2DM_PHYS 0xA0900000 +#else +#define MSM_UART1DM_PHYS 0xA0200000 +#define MSM_UART2DM_PHYS 0xA0300000 +#endif + static struct resource resources_i2c[] = { { .start = MSM_I2C_PHYS, @@ -121,13 +132,42 @@ static struct resource resources_hsusb[] = { }, }; -struct platform_device msm_device_hsusb = { +struct platform_device msm_device_hsusb_peripheral = { +#ifdef CONFIG_USB_ANDROID .name = "msm_hsusb", +#else + .name = "msm_hsusb_peripheral", +#endif .id = -1, - .num_resources = ARRAY_SIZE(resources_hsusb), - .resource = resources_hsusb, + .num_resources = ARRAY_SIZE(resources_hsusb_peripheral), + .resource = resources_hsusb_peripheral, .dev = { - .coherent_dma_mask = 0xffffffff, + .dma_mask = &dma_mask, + .coherent_dma_mask = 0xffffffffULL, + }, +}; + +static struct resource resources_hsusb_host[] = { + { + .start = MSM_HSUSB_PHYS, + .end = MSM_HSUSB_PHYS + MSM_HSUSB_SIZE, + .flags = IORESOURCE_MEM, + }, + { + .start = INT_USB_HS, + .end = INT_USB_HS, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device msm_device_hsusb_host = { + .name = "msm_hsusb_host", + .id = -1, + .num_resources = ARRAY_SIZE(resources_hsusb_host), + .resource = resources_hsusb_host, + .dev = { + .dma_mask = &dma_mask, + .coherent_dma_mask = 0xffffffffULL, }, }; @@ -159,10 +199,22 @@ struct platform_device msm_device_smd = { .id = -1, }; +#if defined(CONFIG_ARCH_QSD) +#define MSM_SDC1_BASE 0xA0300000 +#define MSM_SDC2_BASE 0xA0400000 +#define MSM_SDC3_BASE 0xA0500000 +#define MSM_SDC4_BASE 0xA0600000 +#else +#define MSM_SDC1_BASE 0xA0400000 +#define MSM_SDC2_BASE 0xA0500000 +#define MSM_SDC3_BASE 0xA0600000 +#define MSM_SDC4_BASE 0xA0700000 +#endif + static struct resource resources_sdc1[] = { { - .start = MSM_SDC1_PHYS, - .end = MSM_SDC1_PHYS + MSM_SDC1_SIZE - 1, + .start = MSM_SDC1_BASE, + .end = MSM_SDC1_BASE + SZ_4K - 1, .flags = IORESOURCE_MEM, }, { @@ -179,8 +231,8 @@ static struct resource resources_sdc1[] = { static struct resource resources_sdc2[] = { { - .start = MSM_SDC2_PHYS, - .end = MSM_SDC2_PHYS + MSM_SDC2_SIZE - 1, + .start = MSM_SDC2_BASE, + .end = MSM_SDC2_BASE + SZ_4K - 1, .flags = IORESOURCE_MEM, }, { @@ -197,8 +249,8 @@ static struct resource resources_sdc2[] = { static struct resource resources_sdc3[] = { { - .start = MSM_SDC3_PHYS, - .end = MSM_SDC3_PHYS + MSM_SDC3_SIZE - 1, + .start = MSM_SDC3_BASE, + .end = MSM_SDC3_BASE + SZ_4K - 1, .flags = IORESOURCE_MEM, }, { @@ -215,8 +267,8 @@ static struct resource resources_sdc3[] = { static struct resource resources_sdc4[] = { { - .start = MSM_SDC4_PHYS, - .end = MSM_SDC4_PHYS + MSM_SDC4_SIZE - 1, + .start = MSM_SDC4_BASE, + .end = MSM_SDC4_BASE + SZ_4K - 1, .flags = IORESOURCE_MEM, }, { @@ -289,6 +341,7 @@ int __init msm_add_sdcc(unsigned int controller, struct mmc_platform_data *plat) pdev->dev.platform_data = plat; return platform_device_register(pdev); } + #define CLOCK(clk_name, clk_id, clk_dev, clk_flags, clk_arch) { \ .name = clk_name, \ .id = clk_id, \ @@ -296,57 +349,237 @@ int __init msm_add_sdcc(unsigned int controller, struct mmc_platform_data *plat) .dev = clk_dev, \ } -#define CLK_ALL(name, id, dev, flags) \ - CLOCK(name, id, dev, flags, CLKFLAG_ARCH_ALL) -#define CLK_7X00A(name, id, dev, flags) \ - CLOCK(name, id, dev, flags, CLKFLAG_ARCH_MSM7X00A) - -#define OFF CLKFLAG_AUTO_OFF -#define MINMAX (CLKFLAG_USE_MIN_TO_SET | CLKFLAG_USE_MAX_TO_SET) -#define USE_MIN CLKFLAG_USE_MIN_TO_SET - -struct clk msm_clocks[] = { - CLK_ALL("adm_clk", ADM_CLK, NULL, 0), - CLK_ALL("adsp_clk", ADSP_CLK, NULL, 0), - CLK_ALL("ebi1_clk", EBI1_CLK, NULL, USE_MIN), - CLK_ALL("ebi2_clk", EBI2_CLK, NULL, 0), - CLK_ALL("ecodec_clk", ECODEC_CLK, NULL, 0), - CLK_ALL("mddi_clk", EMDH_CLK, &msm_device_mddi1.dev, OFF), - CLK_ALL("gp_clk", GP_CLK, NULL, 0), - CLK_ALL("grp_clk", GRP_CLK, NULL, OFF), - CLK_ALL("i2c_clk", I2C_CLK, &msm_device_i2c.dev, 0), - CLK_ALL("icodec_rx_clk", ICODEC_RX_CLK, NULL, 0), - CLK_ALL("icodec_tx_clk", ICODEC_TX_CLK, NULL, 0), - CLK_ALL("imem_clk", IMEM_CLK, NULL, OFF), - CLK_ALL("mdc_clk", MDC_CLK, NULL, 0), - CLK_ALL("mdp_clk", MDP_CLK, &msm_device_mdp.dev, OFF), - CLK_ALL("pbus_clk", PBUS_CLK, NULL, 0), - CLK_ALL("pcm_clk", PCM_CLK, NULL, 0), - CLK_ALL("mddi_clk", PMDH_CLK, &msm_device_mddi0.dev, OFF | MINMAX), - CLK_ALL("sdac_clk", SDAC_CLK, NULL, OFF), - CLK_ALL("sdc_clk", SDC1_CLK, &msm_device_sdc1.dev, OFF), - CLK_ALL("sdc_pclk", SDC1_PCLK, &msm_device_sdc1.dev, OFF), - CLK_ALL("sdc_clk", SDC2_CLK, &msm_device_sdc2.dev, OFF), - CLK_ALL("sdc_pclk", SDC2_PCLK, &msm_device_sdc2.dev, OFF), - CLK_ALL("sdc_clk", SDC3_CLK, &msm_device_sdc3.dev, OFF), - CLK_ALL("sdc_pclk", SDC3_PCLK, &msm_device_sdc3.dev, OFF), - CLK_ALL("sdc_clk", SDC4_CLK, &msm_device_sdc4.dev, OFF), - CLK_ALL("sdc_pclk", SDC4_PCLK, &msm_device_sdc4.dev, OFF), - CLK_ALL("tsif_clk", TSIF_CLK, NULL, 0), - CLK_ALL("tsif_ref_clk", TSIF_REF_CLK, NULL, 0), - CLK_ALL("tv_dac_clk", TV_DAC_CLK, NULL, 0), - CLK_ALL("tv_enc_clk", TV_ENC_CLK, NULL, 0), - CLK_ALL("uart_clk", UART1_CLK, &msm_device_uart1.dev, OFF), - CLK_ALL("uart_clk", UART2_CLK, &msm_device_uart2.dev, 0), - CLK_ALL("uart_clk", UART3_CLK, &msm_device_uart3.dev, OFF), - CLK_ALL("uartdm_clk", UART1DM_CLK, &msm_device_uart_dm1.dev, OFF), - CLK_ALL("uartdm_clk", UART2DM_CLK, &msm_device_uart_dm2.dev, 0), - CLK_ALL("usb_hs_clk", USB_HS_CLK, &msm_device_hsusb.dev, OFF), - CLK_ALL("usb_hs_pclk", USB_HS_PCLK, &msm_device_hsusb.dev, OFF), - CLK_ALL("usb_otg_clk", USB_OTG_CLK, NULL, 0), - CLK_ALL("vdc_clk", VDC_CLK, NULL, OFF | MINMAX), - CLK_ALL("vfe_clk", VFE_CLK, NULL, OFF), - CLK_ALL("vfe_mdc_clk", VFE_MDC_CLK, NULL, OFF), - - CLOCK(NULL, 0, NULL, 0, 0), +static struct platform_device msm_tvenc_device = { + .name = "tvenc", + .id = 0, + .num_resources = ARRAY_SIZE(msm_tvenc_resources), + .resource = msm_tvenc_resources, }; + +static void __init msm_register_device(struct platform_device *pdev, void *data) +{ + int ret; + + pdev->dev.platform_data = data; + + ret = platform_device_register(pdev); + if (ret) + dev_err(&pdev->dev, + "%s: platform_device_register() failed = %d\n", + __func__, ret); +} + +void __init msm_fb_register_device(char *name, void *data) +{ + if (!strncmp(name, "mdp", 3)) + msm_register_device(&msm_mdp_device, data); + else if (!strncmp(name, "pmdh", 4)) + msm_register_device(&msm_mddi_device, data); + else if (!strncmp(name, "emdh", 4)) + msm_register_device(&msm_mddi_ext_device, data); + else if (!strncmp(name, "ebi2", 4)) + msm_register_device(&msm_ebi2_lcd_device, data); + else if (!strncmp(name, "tvenc", 5)) + msm_register_device(&msm_tvenc_device, data); + else if (!strncmp(name, "lcdc", 4)) + msm_register_device(&msm_lcdc_device, data); + else + printk(KERN_ERR "%s: unknown device! %s\n", __func__, name); +} + +static struct platform_device msm_camera_device = { + .name = "msm_camera", + .id = 0, +}; + +void __init msm_camera_register_device(void *res, uint32_t num, + void *data) +{ + msm_camera_device.num_resources = num; + msm_camera_device.resource = res; + + msm_register_device(&msm_camera_device, data); +} + +struct clk msm_clocks_7x01a[] = { + CLOCK("adm_clk", ADM_CLK, NULL, 0), + CLOCK("adsp_clk", ADSP_CLK, NULL, 0), + CLOCK("ebi1_clk", EBI1_CLK, NULL, CLK_MIN), + CLOCK("ebi2_clk", EBI2_CLK, NULL, 0), + CLOCK("ecodec_clk", ECODEC_CLK, NULL, 0), + CLOCK("emdh_clk", EMDH_CLK, NULL, OFF | CLK_MINMAX), + CLOCK("gp_clk", GP_CLK, NULL, 0), + CLOCK("grp_clk", GRP_CLK, NULL, OFF), + CLOCK("i2c_clk", I2C_CLK, &msm_device_i2c.dev, 0), + CLOCK("icodec_rx_clk", ICODEC_RX_CLK, NULL, 0), + CLOCK("icodec_tx_clk", ICODEC_TX_CLK, NULL, 0), + CLOCK("imem_clk", IMEM_CLK, NULL, OFF), + CLOCK("mdc_clk", MDC_CLK, NULL, 0), + CLOCK("mdp_clk", MDP_CLK, NULL, OFF), + CLOCK("pbus_clk", PBUS_CLK, NULL, CLK_MIN), + CLOCK("pcm_clk", PCM_CLK, NULL, 0), + CLOCK("mddi_clk", PMDH_CLK, NULL, OFF | CLK_MINMAX), + CLOCK("sdac_clk", SDAC_CLK, NULL, OFF), + CLOCK("sdc_clk", SDC1_CLK, &msm_device_sdc1.dev, OFF), + CLOCK("sdc_pclk", SDC1_PCLK, &msm_device_sdc1.dev, OFF), + CLOCK("sdc_clk", SDC2_CLK, &msm_device_sdc2.dev, OFF), + CLOCK("sdc_pclk", SDC2_PCLK, &msm_device_sdc2.dev, OFF), + CLOCK("sdc_clk", SDC3_CLK, &msm_device_sdc3.dev, OFF), + CLOCK("sdc_pclk", SDC3_PCLK, &msm_device_sdc3.dev, OFF), + CLOCK("sdc_clk", SDC4_CLK, &msm_device_sdc4.dev, OFF), + CLOCK("sdc_pclk", SDC4_PCLK, &msm_device_sdc4.dev, OFF), + CLOCK("tsif_clk", TSIF_CLK, NULL, 0), + CLOCK("tsif_ref_clk", TSIF_REF_CLK, NULL, 0), + CLOCK("tv_dac_clk", TV_DAC_CLK, NULL, 0), + CLOCK("tv_enc_clk", TV_ENC_CLK, NULL, 0), + CLOCK("uart_clk", UART1_CLK, &msm_device_uart1.dev, OFF), + CLOCK("uart_clk", UART2_CLK, &msm_device_uart2.dev, 0), + CLOCK("uart_clk", UART3_CLK, &msm_device_uart3.dev, OFF), + CLOCK("uartdm_clk", UART1DM_CLK, &msm_device_uart_dm1.dev, OFF), + CLOCK("uartdm_clk", UART2DM_CLK, &msm_device_uart_dm2.dev, 0), + CLOCK("usb_hs_clk", USB_HS_CLK, NULL, OFF), + CLOCK("usb_hs_pclk", USB_HS_PCLK, NULL, OFF), + CLOCK("usb_otg_clk", USB_OTG_CLK, NULL, 0), + CLOCK("vdc_clk", VDC_CLK, NULL, OFF | CLK_MIN), + CLOCK("vfe_clk", VFE_CLK, NULL, OFF), + CLOCK("vfe_mdc_clk", VFE_MDC_CLK, NULL, OFF), +}; + +unsigned msm_num_clocks_7x01a = ARRAY_SIZE(msm_clocks_7x01a); + +struct clk msm_clocks_7x25[] = { + CLOCK("adm_clk", ADM_CLK, NULL, 0), + CLOCK("adsp_clk", ADSP_CLK, NULL, 0), + CLOCK("ebi1_clk", EBI1_CLK, NULL, CLK_MIN), + CLOCK("ebi2_clk", EBI2_CLK, NULL, 0), + CLOCK("ecodec_clk", ECODEC_CLK, NULL, 0), + CLOCK("gp_clk", GP_CLK, NULL, 0), + CLOCK("i2c_clk", I2C_CLK, &msm_device_i2c.dev, 0), + CLOCK("icodec_rx_clk", ICODEC_RX_CLK, NULL, 0), + CLOCK("icodec_tx_clk", ICODEC_TX_CLK, NULL, 0), + CLOCK("imem_clk", IMEM_CLK, NULL, OFF), + CLOCK("mdc_clk", MDC_CLK, NULL, 0), + CLOCK("mdp_clk", MDP_CLK, NULL, OFF), + CLOCK("mdp_lcdc_pclk_clk", MDP_LCDC_PCLK_CLK, NULL, 0), + CLOCK("mdp_lcdc_pad_pclk_clk", MDP_LCDC_PAD_PCLK_CLK, NULL, 0), + CLOCK("mdp_vsync_clk", MDP_VSYNC_CLK, NULL, 0), + CLOCK("pbus_clk", PBUS_CLK, NULL, CLK_MIN), + CLOCK("pcm_clk", PCM_CLK, NULL, 0), + CLOCK("mddi_clk", PMDH_CLK, NULL, OFF | CLK_MINMAX), + CLOCK("sdac_clk", SDAC_CLK, NULL, OFF), + CLOCK("sdc_clk", SDC1_CLK, &msm_device_sdc1.dev, OFF), + CLOCK("sdc_pclk", SDC1_PCLK, &msm_device_sdc1.dev, OFF), + CLOCK("sdc_clk", SDC2_CLK, &msm_device_sdc2.dev, OFF), + CLOCK("sdc_pclk", SDC2_PCLK, &msm_device_sdc2.dev, OFF), + CLOCK("sdc_clk", SDC3_CLK, &msm_device_sdc3.dev, OFF), + CLOCK("sdc_pclk", SDC3_PCLK, &msm_device_sdc3.dev, OFF), + CLOCK("sdc_clk", SDC4_CLK, &msm_device_sdc4.dev, OFF), + CLOCK("sdc_pclk", SDC4_PCLK, &msm_device_sdc4.dev, OFF), + CLOCK("uart_clk", UART1_CLK, &msm_device_uart1.dev, OFF), + CLOCK("uart_clk", UART2_CLK, &msm_device_uart2.dev, 0), + CLOCK("uart_clk", UART3_CLK, &msm_device_uart3.dev, OFF), + CLOCK("uartdm_clk", UART1DM_CLK, &msm_device_uart_dm1.dev, OFF), + CLOCK("uartdm_clk", UART2DM_CLK, &msm_device_uart_dm2.dev, 0), + CLOCK("usb_hs_clk", USB_HS_CLK, NULL, OFF), + CLOCK("usb_hs_pclk", USB_HS_PCLK, NULL, OFF), + CLOCK("usb_otg_clk", USB_OTG_CLK, NULL, 0), + CLOCK("vdc_clk", VDC_CLK, NULL, OFF | CLK_MIN), + CLOCK("vfe_clk", VFE_CLK, NULL, OFF), + CLOCK("vfe_mdc_clk", VFE_MDC_CLK, NULL, OFF), +}; + +unsigned msm_num_clocks_7x25 = ARRAY_SIZE(msm_clocks_7x25); + +struct clk msm_clocks_7x27[] = { + CLOCK("adm_clk", ADM_CLK, NULL, 0), + CLOCK("adsp_clk", ADSP_CLK, NULL, 0), + CLOCK("ebi1_clk", EBI1_CLK, NULL, CLK_MIN), + CLOCK("ebi2_clk", EBI2_CLK, NULL, 0), + CLOCK("ecodec_clk", ECODEC_CLK, NULL, 0), + CLOCK("gp_clk", GP_CLK, NULL, 0), + CLOCK("grp_clk", GRP_CLK, NULL, 0), + CLOCK("i2c_clk", I2C_CLK, &msm_device_i2c.dev, 0), + CLOCK("icodec_rx_clk", ICODEC_RX_CLK, NULL, 0), + CLOCK("icodec_tx_clk", ICODEC_TX_CLK, NULL, 0), + CLOCK("imem_clk", IMEM_CLK, NULL, OFF), + CLOCK("mdc_clk", MDC_CLK, NULL, 0), + CLOCK("mdp_clk", MDP_CLK, NULL, OFF), + CLOCK("mdp_lcdc_pclk_clk", MDP_LCDC_PCLK_CLK, NULL, 0), + CLOCK("mdp_lcdc_pad_pclk_clk", MDP_LCDC_PAD_PCLK_CLK, NULL, 0), + CLOCK("mdp_vsync_clk", MDP_VSYNC_CLK, NULL, 0), + CLOCK("pbus_clk", PBUS_CLK, NULL, CLK_MIN), + CLOCK("pcm_clk", PCM_CLK, NULL, 0), + CLOCK("mddi_clk", PMDH_CLK, NULL, OFF | CLK_MINMAX), + CLOCK("sdac_clk", SDAC_CLK, NULL, OFF), + CLOCK("sdc_clk", SDC1_CLK, &msm_device_sdc1.dev, OFF), + CLOCK("sdc_pclk", SDC1_PCLK, &msm_device_sdc1.dev, OFF), + CLOCK("sdc_clk", SDC2_CLK, &msm_device_sdc2.dev, OFF), + CLOCK("sdc_pclk", SDC2_PCLK, &msm_device_sdc2.dev, OFF), + CLOCK("sdc_clk", SDC3_CLK, &msm_device_sdc3.dev, OFF), + CLOCK("sdc_pclk", SDC3_PCLK, &msm_device_sdc3.dev, OFF), + CLOCK("sdc_clk", SDC4_CLK, &msm_device_sdc4.dev, OFF), + CLOCK("sdc_pclk", SDC4_PCLK, &msm_device_sdc4.dev, OFF), + CLOCK("uart_clk", UART1_CLK, &msm_device_uart1.dev, OFF), + CLOCK("uart_clk", UART2_CLK, &msm_device_uart2.dev, 0), + CLOCK("uart_clk", UART3_CLK, &msm_device_uart3.dev, OFF), + CLOCK("uartdm_clk", UART1DM_CLK, &msm_device_uart_dm1.dev, OFF), + CLOCK("uartdm_clk", UART2DM_CLK, &msm_device_uart_dm2.dev, 0), + CLOCK("usb_hs_clk", USB_HS_CLK, NULL, OFF), + CLOCK("usb_hs_pclk", USB_HS_PCLK, NULL, OFF), + CLOCK("usb_otg_clk", USB_OTG_CLK, NULL, 0), + CLOCK("vdc_clk", VDC_CLK, NULL, OFF | CLK_MIN), + CLOCK("vfe_clk", VFE_CLK, NULL, OFF), + CLOCK("vfe_mdc_clk", VFE_MDC_CLK, NULL, OFF), +}; + +unsigned msm_num_clocks_7x27 = ARRAY_SIZE(msm_clocks_7x27); + +struct clk msm_clocks_8x50[] = { + CLOCK("adm_clk", ADM_CLK, NULL, 0), + CLOCK("ebi1_clk", EBI1_CLK, NULL, CLK_MIN), + CLOCK("ebi2_clk", EBI2_CLK, NULL, 0), + CLOCK("ecodec_clk", ECODEC_CLK, NULL, 0), + CLOCK("emdh_clk", EMDH_CLK, NULL, OFF | CLK_MINMAX), + CLOCK("gp_clk", GP_CLK, NULL, 0), + CLOCK("grp_clk", GRP_CLK, NULL, 0), + CLOCK("i2c_clk", I2C_CLK, &msm_device_i2c.dev, 0), + CLOCK("icodec_rx_clk", ICODEC_RX_CLK, NULL, 0), + CLOCK("icodec_tx_clk", ICODEC_TX_CLK, NULL, 0), + CLOCK("imem_clk", IMEM_CLK, NULL, OFF), + CLOCK("mdc_clk", MDC_CLK, NULL, 0), + CLOCK("mddi_clk", PMDH_CLK, NULL, OFF | CLK_MINMAX), + CLOCK("mdp_clk", MDP_CLK, NULL, OFF), + CLOCK("mdp_lcdc_pclk_clk", MDP_LCDC_PCLK_CLK, NULL, 0), + CLOCK("mdp_lcdc_pad_pclk_clk", MDP_LCDC_PAD_PCLK_CLK, NULL, 0), + CLOCK("mdp_vsync_clk", MDP_VSYNC_CLK, NULL, 0), + CLOCK("pbus_clk", PBUS_CLK, NULL, CLK_MIN), + CLOCK("pcm_clk", PCM_CLK, NULL, 0), + CLOCK("sdac_clk", SDAC_CLK, NULL, OFF), + CLOCK("sdc_clk", SDC1_CLK, &msm_device_sdc1.dev, OFF), + CLOCK("sdc_pclk", SDC1_PCLK, &msm_device_sdc1.dev, OFF), + CLOCK("sdc_clk", SDC2_CLK, &msm_device_sdc2.dev, OFF), + CLOCK("sdc_pclk", SDC2_PCLK, &msm_device_sdc2.dev, OFF), + CLOCK("sdc_clk", SDC3_CLK, &msm_device_sdc3.dev, OFF), + CLOCK("sdc_pclk", SDC3_PCLK, &msm_device_sdc3.dev, OFF), + CLOCK("sdc_clk", SDC4_CLK, &msm_device_sdc4.dev, OFF), + CLOCK("sdc_pclk", SDC4_PCLK, &msm_device_sdc4.dev, OFF), + CLOCK("spi_clk", SPI_CLK, NULL, 0), + CLOCK("tsif_clk", TSIF_CLK, NULL, 0), + CLOCK("tsif_ref_clk", TSIF_REF_CLK, NULL, 0), + CLOCK("tv_dac_clk", TV_DAC_CLK, NULL, 0), + CLOCK("tv_enc_clk", TV_ENC_CLK, NULL, 0), + CLOCK("uart_clk", UART1_CLK, &msm_device_uart1.dev, OFF), + CLOCK("uart_clk", UART2_CLK, &msm_device_uart2.dev, 0), + CLOCK("uart_clk", UART3_CLK, &msm_device_uart3.dev, OFF), + CLOCK("uartdm_clk", UART1DM_CLK, &msm_device_uart_dm1.dev, OFF), + CLOCK("uartdm_clk", UART2DM_CLK, &msm_device_uart_dm2.dev, 0), + CLOCK("usb_hs_clk", USB_HS_CLK, NULL, OFF), + CLOCK("usb_hs_pclk", USB_HS_PCLK, NULL, OFF), + CLOCK("usb_otg_clk", USB_OTG_CLK, NULL, 0), + CLOCK("vdc_clk", VDC_CLK, NULL, OFF | CLK_MIN), + CLOCK("vfe_clk", VFE_CLK, NULL, OFF), + CLOCK("vfe_mdc_clk", VFE_MDC_CLK, NULL, OFF), + CLOCK("vfe_axi_clk", VFE_AXI_CLK, NULL, OFF), +}; + +unsigned msm_num_clocks_8x50 = ARRAY_SIZE(msm_clocks_8x50); diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h index 0744c4a27d6a..5a42b009afff 100644 --- a/arch/arm/mach-msm/devices.h +++ b/arch/arm/mach-msm/devices.h @@ -1,6 +1,7 @@ /* linux/arch/arm/mach-msm/devices.h * * Copyright (C) 2008 Google, Inc. + * Copyright (c) 2009, Code Aurora Forum. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -16,6 +17,8 @@ #ifndef __ARCH_ARM_MACH_MSM_DEVICES_H #define __ARCH_ARM_MACH_MSM_DEVICES_H +#include "clock.h" + extern struct platform_device msm_device_uart1; extern struct platform_device msm_device_uart2; extern struct platform_device msm_device_uart3; @@ -25,7 +28,9 @@ extern struct platform_device msm_device_sdc2; extern struct platform_device msm_device_sdc3; extern struct platform_device msm_device_sdc4; -extern struct platform_device msm_device_hsusb; +extern struct platform_device msm_device_hsusb_otg; +extern struct platform_device msm_device_hsusb_peripheral; +extern struct platform_device msm_device_hsusb_host; extern struct platform_device msm_device_i2c; @@ -33,4 +38,17 @@ extern struct platform_device msm_device_smd; extern struct platform_device msm_device_nand; +extern struct clk msm_clocks_7x01a[]; +extern unsigned msm_num_clocks_7x01a; + +extern struct clk msm_clocks_7x25[]; +extern unsigned msm_num_clocks_7x25; + +extern struct clk msm_clocks_7x27[]; +extern unsigned msm_num_clocks_7x27; + +extern struct clk msm_clocks_8x50[]; +extern unsigned msm_num_clocks_8x50; + + #endif diff --git a/arch/arm/mach-msm/dma.c b/arch/arm/mach-msm/dma.c index 73c186d14d10..5ae76db8fb9b 100644 --- a/arch/arm/mach-msm/dma.c +++ b/arch/arm/mach-msm/dma.c @@ -1,6 +1,7 @@ /* linux/arch/arm/mach-msm/dma.c * * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -124,6 +125,7 @@ int msm_dmov_exec_cmd(unsigned id, unsigned int cmdptr) PRINT_FLOW("dmov_exec_cmdptr(%d, %x) done\n", id, cmdptr); return 0; } +EXPORT_SYMBOL_GPL(msm_dmov_exec_cmd); static irqreturn_t msm_datamover_irq_handler(int irq, void *dev_id) diff --git a/arch/arm/mach-msm/dma_test.c b/arch/arm/mach-msm/dma_test.c new file mode 100644 index 000000000000..ecde8e3ae8a0 --- /dev/null +++ b/arch/arm/mach-msm/dma_test.c @@ -0,0 +1,405 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + + +/********************************************************************** + * User-space testing of the DMA driver. + * Intended to be loaded as a module. We have a bunch of static + * buffers that the user-side can refer to. The main DMA is simply + * used memory-to-memory. Device DMA is best tested with the specific + * device driver in question. + */ +#define MAX_TEST_BUFFERS 40 +#define MAX_TEST_BUFFER_SIZE 65536 +static void *(buffers[MAX_TEST_BUFFERS]); +static int sizes[MAX_TEST_BUFFERS]; + +/* Anything that allocates or deallocates buffers must lock with this + * mutex. */ +static DECLARE_MUTEX(buffer_lock); + +/* Each buffer has a semaphore associated with it that will be held + * for the duration of any operations on that buffer. It also must be + * available to free the given buffer. */ +static struct semaphore buffer_sems[MAX_TEST_BUFFERS]; + +#define buffer_up(num) up(&buffer_sems[num]) +#define buffer_down(num) down(&buffer_sems[num]) + +/* Use the General Purpose DMA channel as our test channel. This channel + * should be available on any target. */ +#define TEST_CHANNEL DMOV_GP_CHAN + +struct private { + /* Each open instance is allowed a single pending + * operation. */ + struct semaphore sem; + + /* Simple command buffer. Allocated and freed by driver. */ + /* TODO: Allocate these together. */ + dmov_s *command_ptr; + + /* Indirect. */ + u32 *command_ptr_ptr; + + /* Indicates completion with pending request. */ + struct completion complete; +}; + +static void free_buffers(void) +{ + int i; + + for (i = 0; i < MAX_TEST_BUFFERS; i++) { + if (sizes[i] > 0) { + kfree(buffers[i]); + sizes[i] = 0; + } + } +} + +/* Copy between two buffers, using the DMA. */ + +/* Allocate a buffer of a requested size. */ +static int buffer_req(struct msm_dma_alloc_req *req) +{ + int i; + + if (req->size <= 0 || req->size > MAX_TEST_BUFFER_SIZE) + return -EINVAL; + + down(&buffer_lock); + + /* Find a free buffer. */ + for (i = 0; i < MAX_TEST_BUFFERS; i++) + if (sizes[i] == 0) + break; + + if (i >= MAX_TEST_BUFFERS) + goto error; + + buffers[i] = kmalloc(req->size, GFP_KERNEL | __GFP_DMA); + if (buffers[i] == 0) + goto error; + sizes[i] = req->size; + + req->bufnum = i; + + up(&buffer_lock); + return 0; + +error: + up(&buffer_lock); + return -ENOSPC; +} + +static int dma_scopy(struct msm_dma_scopy *scopy, struct private *priv) +{ + int err = 0; + dma_addr_t mapped_cmd; + dma_addr_t mapped_cmd_ptr; + + buffer_down(scopy->srcbuf); + if (scopy->srcbuf != scopy->destbuf) + buffer_down(scopy->destbuf); + + priv->command_ptr->cmd = CMD_PTR_LP | CMD_MODE_SINGLE; + priv->command_ptr->src = dma_map_single(NULL, buffers[scopy->srcbuf], + scopy->size, DMA_TO_DEVICE); + priv->command_ptr->dst = dma_map_single(NULL, buffers[scopy->destbuf], + scopy->size, DMA_FROM_DEVICE); + priv->command_ptr->len = scopy->size; + + mapped_cmd = + dma_map_single(NULL, priv->command_ptr, sizeof(*priv->command_ptr), + DMA_TO_DEVICE); + *(priv->command_ptr_ptr) = CMD_PTR_ADDR(mapped_cmd) | CMD_PTR_LP; + + mapped_cmd_ptr = dma_map_single(NULL, priv->command_ptr_ptr, + sizeof(*priv->command_ptr_ptr), + DMA_TO_DEVICE); + + msm_dmov_exec_cmd(TEST_CHANNEL, + DMOV_CMD_PTR_LIST | DMOV_CMD_ADDR(mapped_cmd_ptr)); + + dma_unmap_single(NULL, (dma_addr_t) mapped_cmd_ptr, + sizeof(*priv->command_ptr_ptr), DMA_TO_DEVICE); + dma_unmap_single(NULL, (dma_addr_t) mapped_cmd, + sizeof(*priv->command_ptr), DMA_TO_DEVICE); + dma_unmap_single(NULL, (dma_addr_t) priv->command_ptr->dst, + scopy->size, DMA_FROM_DEVICE); + dma_unmap_single(NULL, (dma_addr_t) priv->command_ptr->src, + scopy->size, DMA_TO_DEVICE); + + if (scopy->srcbuf != scopy->destbuf) + buffer_up(scopy->destbuf); + buffer_up(scopy->srcbuf); + + return err; +} + +static int dma_test_open(struct inode *inode, struct file *file) +{ + struct private *priv; + + printk(KERN_ALERT "%s\n", __func__); + + priv = kmalloc(sizeof(struct private), GFP_KERNEL); + if (priv == NULL) + return -ENOMEM; + file->private_data = priv; + + init_MUTEX(&priv->sem); + + /* Note, that these should be allocated together so we don't + * waste 32 bytes for each. */ + + /* Allocate the command pointer. */ + priv->command_ptr = kmalloc(sizeof(&priv->command_ptr), + GFP_KERNEL | __GFP_DMA); + if (priv->command_ptr == NULL) { + kfree(priv); + return -ENOSPC; + } + + /* And the indirect pointer. */ + priv->command_ptr_ptr = kmalloc(sizeof(u32), GFP_KERNEL | __GFP_DMA); + if (priv->command_ptr_ptr == NULL) { + kfree(priv->command_ptr); + kfree(priv); + return -ENOSPC; + } + + return 0; +} + +static int dma_test_release(struct inode *inode, struct file *file) +{ + struct private *priv; + + printk(KERN_ALERT "%s\n", __func__); + + if (file->private_data != NULL) { + priv = file->private_data; + kfree(priv->command_ptr_ptr); + kfree(priv->command_ptr); + } + kfree(file->private_data); + file->private_data = NULL; + + return 0; +} + +static int dma_test_ioctl(struct inode *inode, struct file *file, + unsigned cmd, unsigned long arg) +{ + int err = 0; + int tmp; + struct msm_dma_alloc_req alloc_req; + struct msm_dma_bufxfer xfer; + struct msm_dma_scopy scopy; + struct private *priv = file->private_data; + + /* Verify user arguments. */ + if (_IOC_TYPE(cmd) != MSM_DMA_IOC_MAGIC) + return -ENOTTY; + + switch (cmd) { + case MSM_DMA_IOALLOC: + if (!access_ok(VERIFY_WRITE, (void __user *)arg, + sizeof(alloc_req))) + return -EFAULT; + if (__copy_from_user(&alloc_req, (void __user *)arg, + sizeof(alloc_req))) + return -EFAULT; + err = buffer_req(&alloc_req); + if (err < 0) + return err; + if (__copy_to_user((void __user *)arg, &alloc_req, + sizeof(alloc_req))) + return -EFAULT; + break; + + case MSM_DMA_IOFREEALL: + down(&buffer_lock); + for (tmp = 0; tmp < MAX_TEST_BUFFERS; tmp++) { + buffer_down(tmp); + if (sizes[tmp] > 0) { + kfree(buffers[tmp]); + sizes[tmp] = 0; + } + buffer_up(tmp); + } + up(&buffer_lock); + break; + + case MSM_DMA_IOWBUF: + if (copy_from_user(&xfer, (void __user *)arg, sizeof(xfer))) + return -EFAULT; + if (xfer.bufnum < 0 || xfer.bufnum >= MAX_TEST_BUFFERS) + return -EINVAL; + buffer_down(xfer.bufnum); + if (sizes[xfer.bufnum] == 0 || + xfer.size <= 0 || xfer.size > sizes[xfer.bufnum]) { + buffer_up(xfer.bufnum); + return -EINVAL; + } + if (copy_from_user(buffers[xfer.bufnum], + (void __user *)xfer.data, xfer.size)) + err = -EFAULT; + buffer_up(xfer.bufnum); + break; + + case MSM_DMA_IORBUF: + if (copy_from_user(&xfer, (void __user *)arg, sizeof(xfer))) + return -EFAULT; + if (xfer.bufnum < 0 || xfer.bufnum >= MAX_TEST_BUFFERS) + return -EINVAL; + buffer_down(xfer.bufnum); + if (sizes[xfer.bufnum] == 0 || + xfer.size <= 0 || xfer.size > sizes[xfer.bufnum]) { + buffer_up(xfer.bufnum); + return -EINVAL; + } + if (copy_to_user((void __user *)xfer.data, buffers[xfer.bufnum], + xfer.size)) + err = -EFAULT; + buffer_up(xfer.bufnum); + break; + + case MSM_DMA_IOSCOPY: + if (copy_from_user(&scopy, (void __user *)arg, sizeof(scopy))) + return -EFAULT; + if (scopy.srcbuf < 0 || scopy.srcbuf >= MAX_TEST_BUFFERS || + sizes[scopy.srcbuf] == 0 || + scopy.destbuf < 0 || scopy.destbuf >= MAX_TEST_BUFFERS || + sizes[scopy.destbuf] == 0 || + scopy.size > sizes[scopy.destbuf] || + scopy.size > sizes[scopy.srcbuf]) + return -EINVAL; +#if 0 + /* Test interface using memcpy. */ + memcpy(buffers[scopy.destbuf], + buffers[scopy.srcbuf], scopy.size); +#else + err = dma_scopy(&scopy, priv); +#endif + break; + + default: + return -ENOTTY; + } + + return err; +} + +/********************************************************************** + * Register ourselves as a misc device to be able to test the DMA code + * from userspace. */ +#define MSM_DMOV_MINOR 32 + +static const struct file_operations dma_test_fops = { + .owner = THIS_MODULE, + .ioctl = dma_test_ioctl, + .open = dma_test_open, + .release = dma_test_release, +}; + +static struct miscdevice dma_test_dev = { + .minor = MSM_DMOV_MINOR, + .name = "msmdma", + .fops = &dma_test_fops, +}; +static int dma_test_init(void) +{ + int ret, i; + + ret = misc_register(&dma_test_dev); + if (ret < 0) + return ret; + + for (i = 0; i < MAX_TEST_BUFFERS; i++) + init_MUTEX(&buffer_sems[i]); + + printk(KERN_ALERT "%s\n", __func__); + return 0; +} + +static void dma_test_exit(void) +{ + free_buffers(); + misc_deregister(&dma_test_dev); + printk(KERN_ALERT "%s\n", __func__); +} + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("David Brown, Qualcomm, Incorporated"); +MODULE_DESCRIPTION("Test for MSM DMA driver"); +MODULE_VERSION("1.01"); + +module_init(dma_test_init); +module_exit(dma_test_exit); diff --git a/arch/arm/mach-msm/gpio.c b/arch/arm/mach-msm/gpio.c index ba41ee1f7a79..91f6c710286c 100644 --- a/arch/arm/mach-msm/gpio.c +++ b/arch/arm/mach-msm/gpio.c @@ -1,6 +1,7 @@ /* linux/arch/arm/mach-msm/gpio.c * * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2009, Code Aurora Forum. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -17,8 +18,10 @@ #include #include #include +#include #include "gpio_chip.h" #include "gpio_hw.h" +#include "proc_comm.h" #include "smd_private.h" @@ -167,7 +170,11 @@ struct msm_gpio_chip msm_gpio_chips[] = { }, .chip = { .start = 95, +#if defined(CONFIG_ARCH_QSD) + .end = 103, +#else .end = 106, +#endif .configure = msm_gpio_configure, .get_irq_num = msm_gpio_get_irq_num, .read = msm_gpio_read, @@ -188,8 +195,13 @@ struct msm_gpio_chip msm_gpio_chips[] = { .oe = GPIO_OE_5, }, .chip = { - .start = 107, +#if defined(CONFIG_ARCH_QSD) + .start = 104, .end = 121, +#else + .start = 107, + .end = 132, +#endif .configure = msm_gpio_configure, .get_irq_num = msm_gpio_get_irq_num, .read = msm_gpio_read, @@ -197,7 +209,53 @@ struct msm_gpio_chip msm_gpio_chips[] = { .read_detect_status = msm_gpio_read_detect_status, .clear_detect_status = msm_gpio_clear_detect_status } - } + }, +#if defined(CONFIG_ARCH_QSD) + { + .regs = { + .out = GPIO_OUT_6, + .in = GPIO_IN_6, + .int_status = GPIO_INT_STATUS_6, + .int_clear = GPIO_INT_CLEAR_6, + .int_en = GPIO_INT_EN_6, + .int_edge = GPIO_INT_EDGE_6, + .int_pos = GPIO_INT_POS_6, + .oe = GPIO_OE_6, + }, + .chip = { + .start = 122, + .end = 152, + .configure = msm_gpio_configure, + .get_irq_num = msm_gpio_get_irq_num, + .read = msm_gpio_read, + .write = msm_gpio_write, + .read_detect_status = msm_gpio_read_detect_status, + .clear_detect_status = msm_gpio_clear_detect_status + } + }, + { + .regs = { + .out = GPIO_OUT_7, + .in = GPIO_IN_7, + .int_status = GPIO_INT_STATUS_7, + .int_clear = GPIO_INT_CLEAR_7, + .int_en = GPIO_INT_EN_7, + .int_edge = GPIO_INT_EDGE_7, + .int_pos = GPIO_INT_POS_7, + .oe = GPIO_OE_7, + }, + .chip = { + .start = 153, + .end = 164, + .configure = msm_gpio_configure, + .get_irq_num = msm_gpio_get_irq_num, + .read = msm_gpio_read, + .write = msm_gpio_write, + .read_detect_status = msm_gpio_read_detect_status, + .clear_detect_status = msm_gpio_clear_detect_status + } + }, +#endif }; static void msm_gpio_update_both_edge_detect(struct msm_gpio_chip *msm_chip) @@ -399,16 +457,16 @@ static struct irq_chip msm_gpio_irq_chip = { .set_type = msm_gpio_irq_set_type, }; -#define NUM_GPIO_INT_REGISTERS 6 +#define NUM_GPIO_SMEM_BANKS 6 #define GPIO_SMEM_NUM_GROUPS 2 #define GPIO_SMEM_MAX_PC_INTERRUPTS 8 struct tramp_gpio_smem { uint16_t num_fired[GPIO_SMEM_NUM_GROUPS]; uint16_t fired[GPIO_SMEM_NUM_GROUPS][GPIO_SMEM_MAX_PC_INTERRUPTS]; - uint32_t enabled[NUM_GPIO_INT_REGISTERS]; - uint32_t detection[NUM_GPIO_INT_REGISTERS]; - uint32_t polarity[NUM_GPIO_INT_REGISTERS]; + uint32_t enabled[NUM_GPIO_SMEM_BANKS]; + uint32_t detection[NUM_GPIO_SMEM_BANKS]; + uint32_t polarity[NUM_GPIO_SMEM_BANKS]; }; static void msm_gpio_sleep_int(unsigned long arg) @@ -416,7 +474,7 @@ static void msm_gpio_sleep_int(unsigned long arg) int i, j; struct tramp_gpio_smem *smem_gpio; - BUILD_BUG_ON(ARRAY_SIZE(msm_gpio_chips) != ARRAY_SIZE(smem_gpio->enabled)); + BUILD_BUG_ON(NR_GPIO_IRQS > NUM_GPIO_SMEM_BANKS * 32); smem_gpio = smem_alloc(SMEM_GPIO_INT, sizeof(*smem_gpio)); if (smem_gpio == NULL) @@ -440,8 +498,6 @@ void msm_gpio_enter_sleep(int from_idle) int i; struct tramp_gpio_smem *smem_gpio; - BUILD_BUG_ON(ARRAY_SIZE(msm_gpio_chips) != ARRAY_SIZE(smem_gpio->enabled)); - smem_gpio = smem_alloc(SMEM_GPIO_INT, sizeof(*smem_gpio)); if (smem_gpio) { @@ -491,8 +547,6 @@ void msm_gpio_exit_sleep(void) int i; struct tramp_gpio_smem *smem_gpio; - BUILD_BUG_ON(ARRAY_SIZE(msm_gpio_chips) != ARRAY_SIZE(smem_gpio->enabled)); - smem_gpio = smem_alloc(SMEM_GPIO_INT, sizeof(*smem_gpio)); for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) { @@ -530,3 +584,56 @@ static int __init msm_init_gpio(void) } postcore_initcall(msm_init_gpio); + +int gpio_tlmm_config(unsigned config, unsigned disable) +{ + return msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &config, &disable); +} +EXPORT_SYMBOL(gpio_tlmm_config); + +#if defined(CONFIG_DEBUG_FS) + +static int msm_gpio_debug_result = 1; + +static int gpio_enable_set(void *data, u64 val) +{ + msm_gpio_debug_result = gpio_tlmm_config(val, 0); + return 0; +} +static int gpio_disable_set(void *data, u64 val) +{ + msm_gpio_debug_result = gpio_tlmm_config(val, 1); + return 0; +} + +static int gpio_debug_get(void *data, u64 *val) +{ + unsigned int result = msm_gpio_debug_result; + msm_gpio_debug_result = 1; + if (result) + *val = 1; + else + *val = 0; + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(gpio_enable_fops, gpio_debug_get, + gpio_enable_set, "%llu\n"); +DEFINE_SIMPLE_ATTRIBUTE(gpio_disable_fops, gpio_debug_get, + gpio_disable_set, "%llu\n"); + +static int __init gpio_debug_init(void) +{ + struct dentry *dent; + dent = debugfs_create_dir("gpio", 0); + if (IS_ERR(dent)) + return 0; + + debugfs_create_file("enable", 0644, dent, 0, &gpio_enable_fops); + debugfs_create_file("disable", 0644, dent, 0, &gpio_disable_fops); + return 0; +} + +device_initcall(gpio_debug_init); +#endif + diff --git a/arch/arm/mach-msm/gpio.h b/arch/arm/mach-msm/gpio.h new file mode 100644 index 000000000000..7c5e266dd939 --- /dev/null +++ b/arch/arm/mach-msm/gpio.h @@ -0,0 +1,64 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef _ARCH_ARM_MACH_MSM_GPIO_H_ +#define _ARCH_ARM_MACH_MSM_GPIO_H_ + +void msm_gpio_enter_sleep(int from_idle); +void msm_gpio_exit_sleep(void); + +#endif diff --git a/arch/arm/mach-msm/gpio_hw-7xxx.h b/arch/arm/mach-msm/gpio_hw-7xxx.h new file mode 100644 index 000000000000..17b4d80c2310 --- /dev/null +++ b/arch/arm/mach-msm/gpio_hw-7xxx.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2007 Google, Inc. + * Author: Brian Swetland + */ + +#ifndef __ARCH_ARM_MACH_MSM_GPIO_HW_7XXX_H +#define __ARCH_ARM_MACH_MSM_GPIO_HW_7XXX_H + +/* output value */ +#define GPIO_OUT_0 GPIO1_REG(0x00) /* gpio 15-0 */ +#define GPIO_OUT_1 GPIO2_REG(0x00) /* gpio 42-16 */ +#define GPIO_OUT_2 GPIO1_REG(0x04) /* gpio 67-43 */ +#define GPIO_OUT_3 GPIO1_REG(0x08) /* gpio 94-68 */ +#define GPIO_OUT_4 GPIO1_REG(0x0C) /* gpio 106-95 */ +#define GPIO_OUT_5 GPIO1_REG(0x50) /* gpio 107-121 */ + +/* same pin map as above, output enable */ +#define GPIO_OE_0 GPIO1_REG(0x10) +#define GPIO_OE_1 GPIO2_REG(0x08) +#define GPIO_OE_2 GPIO1_REG(0x14) +#define GPIO_OE_3 GPIO1_REG(0x18) +#define GPIO_OE_4 GPIO1_REG(0x1C) +#define GPIO_OE_5 GPIO1_REG(0x54) + +/* same pin map as above, input read */ +#define GPIO_IN_0 GPIO1_REG(0x34) +#define GPIO_IN_1 GPIO2_REG(0x20) +#define GPIO_IN_2 GPIO1_REG(0x38) +#define GPIO_IN_3 GPIO1_REG(0x3C) +#define GPIO_IN_4 GPIO1_REG(0x40) +#define GPIO_IN_5 GPIO1_REG(0x44) + +/* same pin map as above, 1=edge 0=level interrup */ +#define GPIO_INT_EDGE_0 GPIO1_REG(0x60) +#define GPIO_INT_EDGE_1 GPIO2_REG(0x50) +#define GPIO_INT_EDGE_2 GPIO1_REG(0x64) +#define GPIO_INT_EDGE_3 GPIO1_REG(0x68) +#define GPIO_INT_EDGE_4 GPIO1_REG(0x6C) +#define GPIO_INT_EDGE_5 GPIO1_REG(0xC0) + +/* same pin map as above, 1=positive 0=negative */ +#define GPIO_INT_POS_0 GPIO1_REG(0x70) +#define GPIO_INT_POS_1 GPIO2_REG(0x58) +#define GPIO_INT_POS_2 GPIO1_REG(0x74) +#define GPIO_INT_POS_3 GPIO1_REG(0x78) +#define GPIO_INT_POS_4 GPIO1_REG(0x7C) +#define GPIO_INT_POS_5 GPIO1_REG(0xBC) + +/* same pin map as above, interrupt enable */ +#define GPIO_INT_EN_0 GPIO1_REG(0x80) +#define GPIO_INT_EN_1 GPIO2_REG(0x60) +#define GPIO_INT_EN_2 GPIO1_REG(0x84) +#define GPIO_INT_EN_3 GPIO1_REG(0x88) +#define GPIO_INT_EN_4 GPIO1_REG(0x8C) +#define GPIO_INT_EN_5 GPIO1_REG(0xB8) + +/* same pin map as above, write 1 to clear interrupt */ +#define GPIO_INT_CLEAR_0 GPIO1_REG(0x90) +#define GPIO_INT_CLEAR_1 GPIO2_REG(0x68) +#define GPIO_INT_CLEAR_2 GPIO1_REG(0x94) +#define GPIO_INT_CLEAR_3 GPIO1_REG(0x98) +#define GPIO_INT_CLEAR_4 GPIO1_REG(0x9C) +#define GPIO_INT_CLEAR_5 GPIO1_REG(0xB4) + +/* same pin map as above, 1=interrupt pending */ +#define GPIO_INT_STATUS_0 GPIO1_REG(0xA0) +#define GPIO_INT_STATUS_1 GPIO2_REG(0x70) +#define GPIO_INT_STATUS_2 GPIO1_REG(0xA4) +#define GPIO_INT_STATUS_3 GPIO1_REG(0xA8) +#define GPIO_INT_STATUS_4 GPIO1_REG(0xAC) +#define GPIO_INT_STATUS_5 GPIO1_REG(0xB0) + +#endif diff --git a/arch/arm/mach-msm/gpio_hw-8xxx.h b/arch/arm/mach-msm/gpio_hw-8xxx.h new file mode 100644 index 000000000000..d8e01e0efcfb --- /dev/null +++ b/arch/arm/mach-msm/gpio_hw-8xxx.h @@ -0,0 +1,141 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef __ARCH_ARM_MACH_MSM_GPIO_HW_8XXX_H +#define __ARCH_ARM_MACH_MSM_GPIO_HW_8XXX_H + +/* output value */ +#define GPIO_OUT_0 GPIO1_REG(0x00) /* gpio 15-0 */ +#define GPIO_OUT_1 GPIO2_REG(0x00) /* gpio 42-16 */ +#define GPIO_OUT_2 GPIO1_REG(0x04) /* gpio 67-43 */ +#define GPIO_OUT_3 GPIO1_REG(0x08) /* gpio 94-68 */ +#define GPIO_OUT_4 GPIO1_REG(0x0C) /* gpio 103-95 */ +#define GPIO_OUT_5 GPIO1_REG(0x10) /* gpio 121-104 */ +#define GPIO_OUT_6 GPIO1_REG(0x14) /* gpio 152-122 */ +#define GPIO_OUT_7 GPIO1_REG(0x18) /* gpio 164-153 */ + +/* same pin map as above, output enable */ +#define GPIO_OE_0 GPIO1_REG(0x20) +#define GPIO_OE_1 GPIO2_REG(0x08) +#define GPIO_OE_2 GPIO1_REG(0x24) +#define GPIO_OE_3 GPIO1_REG(0x28) +#define GPIO_OE_4 GPIO1_REG(0x2C) +#define GPIO_OE_5 GPIO1_REG(0x30) +#define GPIO_OE_6 GPIO1_REG(0x34) +#define GPIO_OE_7 GPIO1_REG(0x38) + +/* same pin map as above, input read */ +#define GPIO_IN_0 GPIO1_REG(0x50) +#define GPIO_IN_1 GPIO2_REG(0x20) +#define GPIO_IN_2 GPIO1_REG(0x54) +#define GPIO_IN_3 GPIO1_REG(0x58) +#define GPIO_IN_4 GPIO1_REG(0x5C) +#define GPIO_IN_5 GPIO1_REG(0x60) +#define GPIO_IN_6 GPIO1_REG(0x64) +#define GPIO_IN_7 GPIO1_REG(0x6C) + +/* same pin map as above, 1=edge 0=level interrup */ +#define GPIO_INT_EDGE_0 GPIO1_REG(0x70) +#define GPIO_INT_EDGE_1 GPIO2_REG(0x50) +#define GPIO_INT_EDGE_2 GPIO1_REG(0x74) +#define GPIO_INT_EDGE_3 GPIO1_REG(0x78) +#define GPIO_INT_EDGE_4 GPIO1_REG(0x7C) +#define GPIO_INT_EDGE_5 GPIO1_REG(0x80) +#define GPIO_INT_EDGE_6 GPIO1_REG(0x84) +#define GPIO_INT_EDGE_7 GPIO1_REG(0x88) + +/* same pin map as above, 1=positive 0=negative */ +#define GPIO_INT_POS_0 GPIO1_REG(0x90) +#define GPIO_INT_POS_1 GPIO2_REG(0x58) +#define GPIO_INT_POS_2 GPIO1_REG(0x94) +#define GPIO_INT_POS_3 GPIO1_REG(0x98) +#define GPIO_INT_POS_4 GPIO1_REG(0x9C) +#define GPIO_INT_POS_5 GPIO1_REG(0xA0) +#define GPIO_INT_POS_6 GPIO1_REG(0xA4) +#define GPIO_INT_POS_7 GPIO1_REG(0xA8) + +/* same pin map as above, interrupt enable */ +#define GPIO_INT_EN_0 GPIO1_REG(0xB0) +#define GPIO_INT_EN_1 GPIO2_REG(0x60) +#define GPIO_INT_EN_2 GPIO1_REG(0xB4) +#define GPIO_INT_EN_3 GPIO1_REG(0xB8) +#define GPIO_INT_EN_4 GPIO1_REG(0xBC) +#define GPIO_INT_EN_5 GPIO1_REG(0xC0) +#define GPIO_INT_EN_6 GPIO1_REG(0xC4) +#define GPIO_INT_EN_7 GPIO1_REG(0xC8) + +/* same pin map as above, write 1 to clear interrupt */ +#define GPIO_INT_CLEAR_0 GPIO1_REG(0xD0) +#define GPIO_INT_CLEAR_1 GPIO2_REG(0x68) +#define GPIO_INT_CLEAR_2 GPIO1_REG(0xD4) +#define GPIO_INT_CLEAR_3 GPIO1_REG(0xD8) +#define GPIO_INT_CLEAR_4 GPIO1_REG(0xDC) +#define GPIO_INT_CLEAR_5 GPIO1_REG(0xE0) +#define GPIO_INT_CLEAR_6 GPIO1_REG(0xE4) +#define GPIO_INT_CLEAR_7 GPIO1_REG(0xE8) + +/* same pin map as above, 1=interrupt pending */ +#define GPIO_INT_STATUS_0 GPIO1_REG(0xF0) +#define GPIO_INT_STATUS_1 GPIO2_REG(0x70) +#define GPIO_INT_STATUS_2 GPIO1_REG(0xF4) +#define GPIO_INT_STATUS_3 GPIO1_REG(0xF8) +#define GPIO_INT_STATUS_4 GPIO1_REG(0xFC) +#define GPIO_INT_STATUS_5 GPIO1_REG(0x100) +#define GPIO_INT_STATUS_6 GPIO1_REG(0x104) +#define GPIO_INT_STATUS_7 GPIO1_REG(0x108) + +#endif diff --git a/arch/arm/mach-msm/gpio_hw.h b/arch/arm/mach-msm/gpio_hw.h index 61f410c6e7ff..e9f38664bbe5 100644 --- a/arch/arm/mach-msm/gpio_hw.h +++ b/arch/arm/mach-msm/gpio_hw.h @@ -1,6 +1,6 @@ -/* arch/arm/mach-msm/gpio_hw.h - * +/* * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. * Author: Brian Swetland * * This software is licensed under the terms of the GNU General Public @@ -33,68 +33,10 @@ #define GPIO1_REG(off) (MSM_GPIO1_BASE + 0x800 + (off)) #define GPIO2_REG(off) (MSM_GPIO2_BASE + 0xC00 + (off)) -/* output value */ -#define GPIO_OUT_0 GPIO1_REG(0x00) /* gpio 15-0 */ -#define GPIO_OUT_1 GPIO2_REG(0x00) /* gpio 42-16 */ -#define GPIO_OUT_2 GPIO1_REG(0x04) /* gpio 67-43 */ -#define GPIO_OUT_3 GPIO1_REG(0x08) /* gpio 94-68 */ -#define GPIO_OUT_4 GPIO1_REG(0x0C) /* gpio 106-95 */ -#define GPIO_OUT_5 GPIO1_REG(0x50) /* gpio 107-121 */ - -/* same pin map as above, output enable */ -#define GPIO_OE_0 GPIO1_REG(0x10) -#define GPIO_OE_1 GPIO2_REG(0x08) -#define GPIO_OE_2 GPIO1_REG(0x14) -#define GPIO_OE_3 GPIO1_REG(0x18) -#define GPIO_OE_4 GPIO1_REG(0x1C) -#define GPIO_OE_5 GPIO1_REG(0x54) - -/* same pin map as above, input read */ -#define GPIO_IN_0 GPIO1_REG(0x34) -#define GPIO_IN_1 GPIO2_REG(0x20) -#define GPIO_IN_2 GPIO1_REG(0x38) -#define GPIO_IN_3 GPIO1_REG(0x3C) -#define GPIO_IN_4 GPIO1_REG(0x40) -#define GPIO_IN_5 GPIO1_REG(0x44) - -/* same pin map as above, 1=edge 0=level interrup */ -#define GPIO_INT_EDGE_0 GPIO1_REG(0x60) -#define GPIO_INT_EDGE_1 GPIO2_REG(0x50) -#define GPIO_INT_EDGE_2 GPIO1_REG(0x64) -#define GPIO_INT_EDGE_3 GPIO1_REG(0x68) -#define GPIO_INT_EDGE_4 GPIO1_REG(0x6C) -#define GPIO_INT_EDGE_5 GPIO1_REG(0xC0) - -/* same pin map as above, 1=positive 0=negative */ -#define GPIO_INT_POS_0 GPIO1_REG(0x70) -#define GPIO_INT_POS_1 GPIO2_REG(0x58) -#define GPIO_INT_POS_2 GPIO1_REG(0x74) -#define GPIO_INT_POS_3 GPIO1_REG(0x78) -#define GPIO_INT_POS_4 GPIO1_REG(0x7C) -#define GPIO_INT_POS_5 GPIO1_REG(0xBC) - -/* same pin map as above, interrupt enable */ -#define GPIO_INT_EN_0 GPIO1_REG(0x80) -#define GPIO_INT_EN_1 GPIO2_REG(0x60) -#define GPIO_INT_EN_2 GPIO1_REG(0x84) -#define GPIO_INT_EN_3 GPIO1_REG(0x88) -#define GPIO_INT_EN_4 GPIO1_REG(0x8C) -#define GPIO_INT_EN_5 GPIO1_REG(0xB8) - -/* same pin map as above, write 1 to clear interrupt */ -#define GPIO_INT_CLEAR_0 GPIO1_REG(0x90) -#define GPIO_INT_CLEAR_1 GPIO2_REG(0x68) -#define GPIO_INT_CLEAR_2 GPIO1_REG(0x94) -#define GPIO_INT_CLEAR_3 GPIO1_REG(0x98) -#define GPIO_INT_CLEAR_4 GPIO1_REG(0x9C) -#define GPIO_INT_CLEAR_5 GPIO1_REG(0xB4) - -/* same pin map as above, 1=interrupt pending */ -#define GPIO_INT_STATUS_0 GPIO1_REG(0xA0) -#define GPIO_INT_STATUS_1 GPIO2_REG(0x70) -#define GPIO_INT_STATUS_2 GPIO1_REG(0xA4) -#define GPIO_INT_STATUS_3 GPIO1_REG(0xA8) -#define GPIO_INT_STATUS_4 GPIO1_REG(0xAC) -#define GPIO_INT_STATUS_5 GPIO1_REG(0xB0) +#if defined(CONFIG_ARCH_QSD) +#include "gpio_hw-8xxx.h" +#else +#include "gpio_hw-7xxx.h" +#endif #endif diff --git a/arch/arm/mach-msm/idle-v6.S b/arch/arm/mach-msm/idle-v6.S new file mode 100644 index 000000000000..33157734a078 --- /dev/null +++ b/arch/arm/mach-msm/idle-v6.S @@ -0,0 +1,140 @@ +/* + * Idle processing for ARMv6-based Qualcomm SoCs. + * Work around bugs with SWFI. + * + * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2007-2009, Code Aurora Forum. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 + +ENTRY(msm_pm_collapse) + ldr r0, =saved_state + stmia r0!, {r4-r14} + mrc p15, 0, r1, c1, c0, 0 /* MMU control */ + mrc p15, 0, r2, c2, c0, 0 /* ttb */ + mrc p15, 0, r3, c3, c0, 0 /* dacr */ + mrc p15, 0, ip, c13, c0, 1 /* context ID */ + stmia r0!, {r1-r3, ip} +#if defined(CONFIG_OPROFILE) + mrc p15, 0, r1, c15, c12, 0 /* pmnc */ + mrc p15, 0, r2, c15, c12, 1 /* ccnt */ + mrc p15, 0, r3, c15, c12, 2 /* pmn0 */ + mrc p15, 0, ip, c15, c12, 3 /* pmn1 */ + stmia r0!, {r1-r3, ip} +#endif + mrc p15, 0, r1, c1, c0, 2 /* read CACR */ + stmia r0!, {r1} + /* fall though */ +ENTRY(msm_arch_idle) +#if defined(CONFIG_MSM_FIQ_SUPPORT) + cpsid f +#endif + mcr p15, 0, r0, c7, c10, 0 /* flush the cache */ + mrc p15, 0, r1, c1, c0, 0 /* read current CR */ + bic r0, r1, #(1 << 2) /* clear dcache bit */ + bic r0, r0, #(1 << 12) /* clear icache bit */ + mcr p15, 0, r0, c1, c0, 0 /* disable d/i cache */ + + mov r0, #0 /* prepare wfi value + * also used as return value from + * msm_pm_collapse */ + + mcr p15, 0, r0, c7, c10, 4 /* memory barrier */ + mcr p15, 0, r0, c7, c0, 4 /* wait for interrupt */ + + mcr p15, 0, r1, c1, c0, 0 /* restore d/i cache */ +#if defined(CONFIG_MSM_FIQ_SUPPORT) + cpsie f +#endif + mov pc, lr + +ENTRY(msm_pm_collapse_exit) +#if 0 /* serial debug */ + mov r0, #0x80000016 + mcr p15, 0, r0, c15, c2, 4 + mov r0, #0xA9000000 + add r0, r0, #0x00A00000 /* UART1 */ + /*add r0, r0, #0x00C00000*/ /* UART3 */ + mov r1, #'A' + str r1, [r0, #0x00C] +#endif + ldr r1, =saved_state_end + ldr r2, =msm_pm_collapse_exit + adr r3, msm_pm_collapse_exit + add r1, r1, r3 + sub r1, r1, r2 + + ldmdb r1!, {r2} + mcr p15, 0, r2, c1, c0, 2 /* restore CACR */ +#if defined(CONFIG_OPROFILE) + ldmdb r1!, {r2-r5} + mcr p15, 0, r3, c15, c12, 1 /* ccnt */ + mcr p15, 0, r4, c15, c12, 2 /* pmn0 */ + mcr p15, 0, r5, c15, c12, 3 /* pmn1 */ + mcr p15, 0, r2, c15, c12, 0 /* pmnc */ +#endif + ldmdb r1!, {r2-r5} + mcr p15, 0, r4, c3, c0, 0 /* dacr */ + mcr p15, 0, r3, c2, c0, 0 /* ttb */ + mcr p15, 0, r5, c13, c0, 1 /* context ID */ + ldmdb r1!, {r4-r14} + + /* Add 1:1 map in the PMD to allow smooth switch when turning on MMU */ + and r3, r3, #~0x7F /* mask off lower 7 bits of TTB */ + adr r0, msm_pm_mapped_pa /* get address of the mapped instr */ + lsr r1, r0, #20 /* get the addr range of addr in MB */ + lsl r1, r1, #2 /* multiply by 4 to get to the pg index */ + add r3, r3, r1 /* pgd + pgd_index(addr) */ + ldr r1, [r3] /* save current entry to r1 */ + lsr r0, #20 /* align current addr to 1MB boundary */ + lsl r0, #20 + /* Create new entry for this 1MB page */ + orr r0, r0, #0x400 /* PMD_SECT_AP_WRITE */ + orr r0, r0, #0x2 /* PMD_TYPE_SECT|PMD_DOMAIN(DOMAIN_KERNEL) */ + str r0, [r3] /* put new entry into the MMU table */ + mcr p15, 0, r3, c7, c10, 1 /* flush_pmd */ + mcr p15, 0, r2, c1, c0, 0 /* MMU control */ +msm_pm_mapped_pa: + /* Switch to virtual */ + adr r2, msm_pm_pa_to_va + ldr r0, =msm_pm_pa_to_va + mov pc, r0 +msm_pm_pa_to_va: + sub r0, r0, r2 + /* Restore r1 in MMU table */ + add r3, r3, r0 + str r1, [r3] + mcr p15, 0, r3, c7, c10, 1 /* flush_pmd */ + mov r0, #1 + mov pc, lr + nop + nop + nop + nop + nop +1: b 1b + + + .data + +saved_state: + .space 4 * 11 /* r4-14 */ + .space 4 * 4 /* cp15 - MMU control, ttb, dacr, context ID */ +#if defined(CONFIG_OPROFILE) + .space 4 * 4 /* more cp15 - pmnc, ccnt, pmn0, pmn1 */ +#endif + .space 4 /* cacr */ +saved_state_end: + diff --git a/arch/arm/mach-msm/idle-v7.S b/arch/arm/mach-msm/idle-v7.S new file mode 100644 index 000000000000..ad49e46b45c7 --- /dev/null +++ b/arch/arm/mach-msm/idle-v7.S @@ -0,0 +1,150 @@ +/* + * Idle processing for ARMv7-based Qualcomm SoCs. + * + * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2007-2009, Code Aurora Forum. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 + +ENTRY(msm_pm_collapse) + ldr r0, =saved_state + stmia r0!, {r4-r14} + mrc p15, 0, r1, c1, c0, 0 /* MMU control */ + mrc p15, 0, r2, c2, c0, 0 /* ttb */ + mrc p15, 0, r3, c3, c0, 0 /* dacr */ + mrc p15, 3, r4, c15, c0, 3 /* L2CR1 is the L2 cache control reg 1 */ + mrc p15, 0, ip, c13, c0, 1 /* context ID */ + stmia r0!, {r1-r4, ip} +#ifdef CONFIG_VFP + VFPFSTMIA r0, r1 /* Save VFP working registers */ + fmrx r1, fpexc + fmrx r2, fpscr + stmia r0!, {r1, r2} /* Save VFP state registers */ +#endif + stmfd sp!, {r4-r5, r7, r9-r11, lr} + bl v7_flush_dcache_all + ldmfd sp!, {r4-r5, r7, r9-r11, lr} + + mrc p15, 0, r1, c1, c0, 0 /* read current CR */ + bic r0, r1, #(1 << 2) /* clear dcache bit */ + bic r0, r0, #(1 << 12) /* clear icache bit */ + mcr p15, 0, r0, c1, c0, 0 /* disable d/i cache */ + /* fall though */ +ENTRY(msm_arch_idle) +#if defined(CONFIG_MSM_FIQ_SUPPORT) + cpsid f +#endif + mov r0, #0 /* prepare wfi value + * also used as return value from + * msm_pm_collapse */ + wfi + +#if defined(CONFIG_MSM_FIQ_SUPPORT) + cpsie f +#endif + mov pc, lr + +ENTRY(msm_pm_collapse_exit) +#if 0 /* serial debug */ + mov r0, #0x80000016 + mcr p15, 0, r0, c15, c2, 4 + mov r0, #0xA9000000 + add r0, r0, #0x00A00000 /* UART1 */ + /*add r0, r0, #0x00C00000*/ /* UART3 */ + mov r1, #'A' + str r1, [r0, #0x00C] +#endif + ldr r1, =saved_state_end + ldr r2, =msm_pm_collapse_exit + adr r3, msm_pm_collapse_exit + add r1, r1, r3 + sub r1, r1, r2 +#ifdef CONFIG_VFP + mrc p15, 0, r2, c1, c0, 2 /* Read CP Access Control Register */ + orr r2, r2, #0x00F00000 /* Enable full access for p10,11 */ + mcr p15, 0, r2, c1, c0, 2 /* Write CPACR */ + isb + mov r2, #0x40000000 /* Enable VFP */ + fmxr fpexc, r2 + isb + ldmdb r1!, {r2, r3} /* Read saved VFP state registers */ + sub r1, r1, #32*8 /* Jump to start of vfp regs area */ + VFPFLDMIA r1, r4 /* Restore VFP working registers, + * r1 incremented to end of vfp + * regs area */ + sub r1, r1, #32*8 /* Jump back to start of vfp regs area */ + fmxr fpscr, r3 /* Restore FPSCR */ + fmxr fpexc, r2 /* Restore FPEXC last */ +#endif + ldmdb r1!, {r2-r6} + mcr p15, 0, r4, c3, c0, 0 /* dacr */ + mcr p15, 0, r3, c2, c0, 0 /* ttb */ + mcr p15, 3, r5, c15, c0, 3 /* L2CR1 */ + mcr p15, 0, r6, c13, c0, 1 /* context ID */ + isb + ldmdb r1!, {r4-r14} + /* Add 1:1 map in the PMD to allow smooth switch when turning on MMU */ + and r3, r3, #~0x7F /* mask off lower 7 bits of TTB */ + adr r0, msm_pm_mapped_pa /* get address of the mapped instr */ + lsr r1, r0, #20 /* get the addr range of addr in MB */ + lsl r1, r1, #2 /* multiply by 4 to get to the pg index */ + add r3, r3, r1 /* pgd + pgd_index(addr) */ + ldr r1, [r3] /* save current entry to r1 */ + lsr r0, #20 /* align current addr to 1MB boundary */ + lsl r0, #20 + /* Create new entry for this 1MB page */ + orr r0, r0, #0x400 /* PMD_SECT_AP_WRITE */ + orr r0, r0, #0x2 /* PMD_TYPE_SECT|PMD_DOMAIN(DOMAIN_KERNEL) */ + str r0, [r3] /* put new entry into the MMU table */ + mcr p15, 0, r3, c7, c10, 1 /* flush_pmd */ + dsb + isb + mcr p15, 0, r2, c1, c0, 0 /* MMU control */ + isb +msm_pm_mapped_pa: + /* Switch to virtual */ + adr r2, msm_pm_pa_to_va + ldr r0, =msm_pm_pa_to_va + mov pc, r0 +msm_pm_pa_to_va: + sub r0, r0, r2 + /* Restore r1 in MMU table */ + add r3, r3, r0 + str r1, [r3] + mcr p15, 0, r3, c7, c10, 1 /* flush_pmd */ + dsb + isb + mov r0, #1 + mov pc, lr + nop + nop + nop + nop + nop +1: b 1b + + + .data + +saved_state: + .space 4 * 11 /* r4-14 */ + .space 4 * 5 /* cp15 */ +#ifdef CONFIG_VFP + .space 8 * 32 /* VFP working registers */ + .space 4 * 2 /* VFP state registers */ +#endif +saved_state_end: + diff --git a/arch/arm/mach-msm/idle.S b/arch/arm/mach-msm/idle.S deleted file mode 100644 index d4c3e8174731..000000000000 --- a/arch/arm/mach-msm/idle.S +++ /dev/null @@ -1,106 +0,0 @@ -/* arch/arm/mach-msm/idle.S - * - * Idle processing for MSM7X00A - work around bugs with SWFI. - * - * Copyright (c) 2007 QUALCOMM Incorporated. - * Copyright (C) 2007 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * 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 - -ENTRY(msm_pm_collapse) - ldr r0, =saved_state - stmia r0!, {r4-r14} - mrc p15, 0, r1, c1, c0, 0 /* MMU control */ - mrc p15, 0, r2, c2, c0, 0 /* ttb */ - mrc p15, 0, r3, c3, c0, 0 /* dacr */ - mrc p15, 0, ip, c13, c0, 1 /* context ID */ - stmia r0!, {r1-r3, ip} -#if defined(CONFIG_OPROFILE) - mrc p15, 0, r1, c15, c12, 0 /* pmnc */ - mrc p15, 0, r2, c15, c12, 1 /* ccnt */ - mrc p15, 0, r3, c15, c12, 2 /* pmn0 */ - mrc p15, 0, ip, c15, c12, 3 /* pmn1 */ - stmia r0!, {r1-r3, ip} -#endif - /* fall though */ -ENTRY(msm_arch_idle) -#if defined(CONFIG_MSM_FIQ_SUPPORT) - cpsid f -#endif - mrc p15, 0, r1, c1, c0, 0 /* read current CR */ - bic r0, r1, #(1 << 2) /* clear dcache bit */ - bic r0, r0, #(1 << 12) /* clear icache bit */ - mcr p15, 0, r0, c1, c0, 0 /* disable d/i cache */ - - mov r0, #0 /* prepare wfi value */ /* also used as return value from msm_pm_collapse */ - mcr p15, 0, r0, c7, c10, 0 /* flush the cache */ - mcr p15, 0, r0, c7, c10, 4 /* memory barrier */ - mcr p15, 0, r0, c7, c0, 4 /* wait for interrupt */ - - mcr p15, 0, r1, c1, c0, 0 /* restore d/i cache */ -#if defined(CONFIG_MSM_FIQ_SUPPORT) - cpsie f -#endif - mov pc, lr - -ENTRY(msm_pm_collapse_exit) -#if 0 /* serial debug */ - mov r0, #0x80000016 - mcr p15, 0, r0, c15, c2, 4 - mov r0, #0xA9000000 - add r0, r0, #0x00A00000 /* UART1 */ - /*add r0, r0, #0x00C00000*/ /* UART3 */ - mov r1, #'A' - str r1, [r0, #0x00C] -#endif - ldr r1, =saved_state_end - ldr r2, =msm_pm_collapse_exit - adr r3, msm_pm_collapse_exit - add r1, r1, r3 - sub r1, r1, r2 -#if defined(CONFIG_OPROFILE) - ldmdb r1!, {r2-r5} - mcr p15, 0, r3, c15, c12, 1 /* ccnt */ - mcr p15, 0, r4, c15, c12, 2 /* pmn0 */ - mcr p15, 0, r5, c15, c12, 3 /* pmn1 */ - mcr p15, 0, r2, c15, c12, 0 /* pmnc */ -#endif - ldmdb r1!, {r2-r5} - mcr p15, 0, r4, c3, c0, 0 /* dacr */ - mcr p15, 0, r3, c2, c0, 0 /* ttb */ - mcr p15, 0, r5, c13, c0, 1 /* context ID */ - ldmdb r1!, {r4-r14} - mov r0, #1 - - mcr p15, 0, r2, c1, c0, 0 /* MMU control */ - mov pc, lr - nop - nop - nop - nop - nop -1: b 1b - - - .data - -saved_state: - .space 4 * 11 /* r4-14 */ - .space 4 * 4 /* cp15 - MMU control, ttb, dacr, context ID */ -#if defined(CONFIG_OPROFILE) - .space 4 * 4 /* more cp15 - pmnc, ccnt, pmn0, pmn1 */ -#endif -saved_state_end: - diff --git a/arch/arm/mach-msm/idle.h b/arch/arm/mach-msm/idle.h new file mode 100644 index 000000000000..46c76aea71cc --- /dev/null +++ b/arch/arm/mach-msm/idle.h @@ -0,0 +1,65 @@ +/* Copyright (c) 2007-2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef _ARCH_ARM_MACH_MSM_IDLE_H_ +#define _ARCH_ARM_MACH_MSM_IDLE_H_ + +int msm_arch_idle(void); +int msm_pm_collapse(void); +void msm_pm_collapse_exit(void); + +#endif diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h index 51dce01a2197..390a6af2dad0 100644 --- a/arch/arm/mach-msm/include/mach/board.h +++ b/arch/arm/mach-msm/include/mach/board.h @@ -1,6 +1,7 @@ /* arch/arm/mach-msm/include/mach/board.h * * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. * Author: Brian Swetland * * This software is licensed under the terms of the GNU General Public @@ -18,6 +19,7 @@ #define __ASM_ARCH_MSM_BOARD_H #include +#include /* platform device data structures */ @@ -34,14 +36,19 @@ struct msm_acpu_clock_platform_data uint32_t vdd_switch_time_us; unsigned long power_collapse_khz; unsigned long wait_for_irq_khz; + unsigned int max_axi_khz; + unsigned int max_vdd; + int (*acpu_set_vdd) (int mvolts); }; /* common init routines for use by arch/arm/mach-msm/board-*.c */ void __init msm_add_devices(void); void __init msm_map_common_io(void); +void __init msm_map_qsd8x50_io(void); +void __init msm_map_comet_io(void); void __init msm_init_irq(void); -void __init msm_clock_init(void); +void __init msm_clock_init(struct clk *clock_tbl, unsigned num_clocks); void __init msm_acpu_clock_init(struct msm_acpu_clock_platform_data *); #if defined(CONFIG_USB_FUNCTION_MSM_HSUSB) @@ -50,4 +57,6 @@ void msm_hsusb_set_vbus_state(int online); static inline void msm_hsusb_set_vbus_state(int online) {} #endif +extern int msm_shared_ram_phys; /* defined in arch/arm/mach-msm/io.c */ + #endif diff --git a/arch/arm/mach-msm/include/mach/camera.h b/arch/arm/mach-msm/include/mach/camera.h new file mode 100644 index 000000000000..9facbecc0678 --- /dev/null +++ b/arch/arm/mach-msm/include/mach/camera.h @@ -0,0 +1,326 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef __ASM__ARCH_CAMERA_H +#define __ASM__ARCH_CAMERA_H + +#include +#include +#include +#include +#include "linux/types.h" + +#include +#include + +#undef CDBG +#ifdef CAMERA_DBG_MSG +#define CDBG(fmt, args...) printk(KERN_INFO "msm_camera: " fmt, ##args) +#else +#define CDBG(fmt, args...) +#endif + +#define MSM_CAMERA_MSG 0 +#define MSM_CAMERA_EVT 1 +#define NUM_WB_EXP_NEUTRAL_REGION_LINES 4 +#define NUM_WB_EXP_STAT_OUTPUT_BUFFERS 3 +#define NUM_AUTOFOCUS_MULTI_WINDOW_GRIDS 16 +#define NUM_AF_STAT_OUTPUT_BUFFERS 3 + +enum msm_queut_t { + MSM_CAM_Q_IVALID, + MSM_CAM_Q_CTRL, + MSM_CAM_Q_VFE_EVT, + MSM_CAM_Q_VFE_MSG, + MSM_CAM_Q_V4L2_REQ, + + MSM_CAM_Q_MAX +}; + +enum vfe_resp_msg_t { + VFE_EVENT, + VFE_MSG_GENERAL, + VFE_MSG_SNAPSHOT, + VFE_MSG_OUTPUT1, + VFE_MSG_OUTPUT2, + VFE_MSG_STATS_AF, + VFE_MSG_STATS_WE, + + VFE_MSG_INVALID +}; + +struct msm_vfe_phy_info { + uint32_t sbuf_phy; + uint32_t y_phy; + uint32_t cbcr_phy; +}; + +struct msm_vfe_resp_t { + enum vfe_resp_msg_t type; + struct msm_vfe_evt_msg_t evt_msg; + struct msm_vfe_phy_info phy; + void *extdata; + int32_t extlen; +}; + +struct msm_vfe_resp { + void (*vfe_resp)(struct msm_vfe_resp_t *, + enum msm_queut_t, void *syncdata); +}; + +struct msm_camvfe_fn_t { + int (*vfe_init) (struct msm_vfe_resp *, struct platform_device *); + int (*vfe_enable) (struct camera_enable_cmd_t *); + int (*vfe_config) (struct msm_vfe_cfg_cmd_t *, void *); + int (*vfe_disable) (struct camera_enable_cmd_t *, + struct platform_device *dev); + void (*vfe_release) (struct platform_device *); +}; + +struct msm_sensor_ctrl_t { + int (*s_init)(struct msm_camera_sensor_info *); + int (*s_release)(void); + int (*s_config)(void __user *); +}; + +struct msm_sync_t { + spinlock_t msg_event_queue_lock; + struct list_head msg_event_queue; + wait_queue_head_t msg_event_wait; + + spinlock_t prev_frame_q_lock; + struct list_head prev_frame_q; + wait_queue_head_t prev_frame_wait; + + spinlock_t pict_frame_q_lock; + struct list_head pict_frame_q; + wait_queue_head_t pict_frame_wait; + + spinlock_t ctrl_status_lock; + struct list_head ctrl_status_queue; + wait_queue_head_t ctrl_status_wait; + + struct hlist_head frame; + struct hlist_head stats; +}; + +struct msm_device_t { + struct msm_camvfe_fn_t vfefn; + struct device *device; + struct cdev cdev; + struct platform_device *pdev; + + struct mutex msm_lock; + uint8_t opencnt; + + const char *apps_id; + + void *cropinfo; + int croplen; + + struct mutex pict_pp_lock; + uint8_t pict_pp; + + int sidx; + struct msm_sensor_ctrl_t sctrl; + + struct mutex msm_sem; + struct msm_sync_t sync; +}; + +/* this structure is used in kernel */ +struct msm_queue_cmd_t { + struct list_head list; + + /* 1 - control command or control command status; + * 2 - adsp event; + * 3 - adsp message; + * 4 - v4l2 request; + */ + enum msm_queut_t type; + void *command; +}; + +struct register_address_value_pair_t { + uint16_t register_address; + uint16_t register_value; +}; + +struct msm_pmem_region { + struct hlist_node list; + enum msm_pmem_t type; + void *vaddr; + unsigned long paddr; + unsigned long len; + struct file *file; + uint32_t y_off; + uint32_t cbcr_off; + int fd; + uint8_t active; +}; + +struct axidata_t { + uint32_t bufnum1; + uint32_t bufnum2; + struct msm_pmem_region *region; +}; + +int32_t mt9d112_probe_init(void *, void *); +int32_t mt9t013_probe_init(void *, void *); +int32_t mt9p012_probe_init(void *, void *); +int32_t s5k3e2fx_probe_init(void *, void *); + +int32_t flash_set_led_state(enum msm_camera_led_state_t led_state); + +/* Below functions are added for V4L2 kernel APIs */ +struct msm_driver { + struct msm_device_t *vmsm; + long (*init)(struct msm_device_t *); + long (*ctrl)(struct msm_ctrl_cmd_t *, + struct msm_device_t *); + + long (*reg_pmem)(struct msm_pmem_info_t *, + struct msm_device_t *); + + long (*get_frame) (struct msm_frame_t *, + struct msm_device_t *); + + long (*put_frame) (struct msm_frame_t *, + struct msm_device_t *msm); + + long (*get_pict) (struct msm_ctrl_cmd_t *, + struct msm_device_t *msm); + + unsigned int (*drv_poll) (struct file *, struct poll_table_struct *, + struct msm_device_t *msm); +}; + +unsigned int msm_poll(struct file *, struct poll_table_struct *); + +long msm_register(struct msm_driver *, + const char *); +long msm_unregister(struct msm_driver *, + const char *); + +void msm_camvfe_init(void); +int msm_camvfe_check(void *); +void msm_camvfe_fn_init(struct msm_camvfe_fn_t *); +int msm_camera_drv_start(struct platform_device *); +int msm_camera_drv_remove(struct platform_device *); + +enum msm_camio_clk_type { + CAMIO_VFE_MDC_CLK, + CAMIO_MDC_CLK, + CAMIO_VFE_CLK, + CAMIO_VFE_AXI_CLK, + + CAMIO_MAX_CLK +}; + +enum msm_camio_clk_src_type { + MSM_CAMIO_CLK_SRC_INTERNAL, + MSM_CAMIO_CLK_SRC_EXTERNAL, + MSM_CAMIO_CLK_SRC_MAX +}; + +enum msm_s_test_mode_t { + S_TEST_OFF, + S_TEST_1, + S_TEST_2, + S_TEST_3 +}; + +enum msm_s_resolution_t { + S_QTR_SIZE, + S_FULL_SIZE, + S_INVALID_SIZE +}; + +enum msm_s_reg_update_t { + /* Sensor egisters that need to be updated during initialization */ + S_REG_INIT, + /* Sensor egisters that needs periodic I2C writes */ + S_UPDATE_PERIODIC, + /* All the sensor Registers will be updated */ + S_UPDATE_ALL, + /* Not valid update */ + S_UPDATE_INVALID +}; + +enum msm_s_setting_t { + S_RES_PREVIEW, + S_RES_CAPTURE +}; + +int msm_camio_enable(struct platform_device *dev); + +int msm_camio_clk_enable(enum msm_camio_clk_type clk); +int msm_camio_clk_disable(enum msm_camio_clk_type clk); +int msm_camio_clk_config(uint32_t freq); +void msm_camio_clk_rate_set(int rate); +void msm_camio_clk_axi_rate_set(int rate); + +void msm_camio_camif_pad_reg_reset(void); +void msm_camio_camif_pad_reg_reset_2(void); + +void msm_camio_vfe_blk_reset(void); + +void msm_camio_clk_sel(enum msm_camio_clk_src_type); +void msm_camio_disable(struct platform_device *); +int msm_camio_probe_on(struct platform_device *); +int msm_camio_probe_off(struct platform_device *); +#endif diff --git a/arch/arm/mach-msm/include/mach/clk.h b/arch/arm/mach-msm/include/mach/clk.h new file mode 100644 index 000000000000..6a1aded34ec6 --- /dev/null +++ b/arch/arm/mach-msm/include/mach/clk.h @@ -0,0 +1,68 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef __MACH_CLK_H +#define __MACH_CLK_H + +struct clk; + +/* Rate is minimum clock rate in Hz */ +int clk_set_min_rate(struct clk *clk, unsigned long rate); + +/* Rate is maximum clock rate in Hz */ +int clk_set_max_rate(struct clk *clk, unsigned long rate); + +#endif diff --git a/arch/arm/mach-msm/include/mach/dal.h b/arch/arm/mach-msm/include/mach/dal.h new file mode 100644 index 000000000000..1f0353583e7a --- /dev/null +++ b/arch/arm/mach-msm/include/mach/dal.h @@ -0,0 +1,184 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef __DAL_H__ +#define __DAL_H__ + +#include +#include + +#define DALRPC_DEST_MODEM SMD_APPS_MODEM +#define DALRPC_DEST_QDSP SMD_APPS_QDSP + +#define DALRPC_TIMEOUT_INFINITE -1 + +enum { + DALDEVICE_ATTACH_IDX = 0, + DALDEVICE_DETACH_IDX, + DALDEVICE_INIT_IDX, + DALDEVICE_DEINIT_IDX, + DALDEVICE_OPEN_IDX, + DALDEVICE_CLOSE_IDX, + DALDEVICE_INFO_IDX, + DALDEVICE_POWEREVENT_IDX, + DALDEVICE_SYSREQUEST_IDX, + DALDEVICE_FIRST_DEVICE_API_IDX +}; + +struct daldevice_info_t { + uint32_t size; + uint32_t version; + char name[32]; +}; + +int daldevice_attach(uint32_t device_id, char *port, int cpu, + void **handle_ptr); + +/* The caller must ensure there are no outstanding dalrpc calls on + * the client before (and while) calling daldevice_detach. */ +int daldevice_detach(void *handle); + +uint32_t dalrpc_fcn_0(uint32_t ddi_idx, void *handle, uint32_t s1); +uint32_t dalrpc_fcn_1(uint32_t ddi_idx, void *handle, uint32_t s1, + uint32_t s2); +uint32_t dalrpc_fcn_2(uint32_t ddi_idx, void *handle, uint32_t s1, + uint32_t *p_s2); +uint32_t dalrpc_fcn_3(uint32_t ddi_idx, void *handle, uint32_t s1, + uint32_t s2, uint32_t s3); +uint32_t dalrpc_fcn_4(uint32_t ddi_idx, void *handle, uint32_t s1, + uint32_t s2, uint32_t *p_s3); +uint32_t dalrpc_fcn_5(uint32_t ddi_idx, void *handle, const void *ibuf, + uint32_t ilen); +uint32_t dalrpc_fcn_6(uint32_t ddi_idx, void *handle, uint32_t s1, + const void *ibuf, uint32_t ilen); +uint32_t dalrpc_fcn_7(uint32_t ddi_idx, void *handle, const void *ibuf, + uint32_t ilen, void *obuf, uint32_t olen, + uint32_t *oalen); +uint32_t dalrpc_fcn_8(uint32_t ddi_idx, void *handle, const void *ibuf, + uint32_t ilen, void *obuf, uint32_t olen); +uint32_t dalrpc_fcn_9(uint32_t ddi_idx, void *handle, void *obuf, + uint32_t olen); +uint32_t dalrpc_fcn_10(uint32_t ddi_idx, void *handle, uint32_t s1, + const void *ibuf, uint32_t ilen, void *obuf, + uint32_t olen, uint32_t *oalen); +uint32_t dalrpc_fcn_11(uint32_t ddi_idx, void *handle, uint32_t s1, + void *obuf, uint32_t olen); +uint32_t dalrpc_fcn_12(uint32_t ddi_idx, void *handle, uint32_t s1, + void *obuf, uint32_t olen, uint32_t *oalen); +uint32_t dalrpc_fcn_13(uint32_t ddi_idx, void *handle, const void *ibuf, + uint32_t ilen, const void *ibuf2, uint32_t ilen2, + void *obuf, uint32_t olen); +uint32_t dalrpc_fcn_14(uint32_t ddi_idx, void *handle, const void *ibuf, + uint32_t ilen, void *obuf1, uint32_t olen1, + void *obuf2, uint32_t olen2, uint32_t *oalen2); +uint32_t dalrpc_fcn_15(uint32_t ddi_idx, void *handle, const void *ibuf, + uint32_t ilen, const void *ibuf2, uint32_t ilen2, + void *obuf, uint32_t olen, uint32_t *oalen, + void *obuf2, uint32_t olen2); + +static inline uint32_t daldevice_info(void *handle, + struct daldevice_info_t *info, + uint32_t info_size) +{ + return dalrpc_fcn_9(DALDEVICE_INFO_IDX, handle, info, info_size); +} + +static inline uint32_t daldevice_sysrequest(void *handle, uint32_t req_id, + const void *src_ptr, + uint32_t src_len, void *dest_ptr, + uint32_t dest_len, + uint32_t *dest_alen) +{ + return dalrpc_fcn_10(DALDEVICE_SYSREQUEST_IDX, handle, req_id, + src_ptr, src_len, dest_ptr, dest_len, dest_alen); +} + +static inline uint32_t daldevice_init(void *handle) +{ + return dalrpc_fcn_0(DALDEVICE_INIT_IDX, handle, 0); +} + +static inline uint32_t daldevice_deinit(void *handle) +{ + return dalrpc_fcn_0(DALDEVICE_DEINIT_IDX, handle, 0); +} + +static inline uint32_t daldevice_open(void *handle, uint32_t mode) +{ + return dalrpc_fcn_0(DALDEVICE_OPEN_IDX, handle, mode); +} + +static inline uint32_t daldevice_close(void *handle) +{ + return dalrpc_fcn_0(DALDEVICE_CLOSE_IDX, handle, 0); +} + +void *dalrpc_alloc_event(void *handle); +void *dalrpc_alloc_cb(void *handle, + void (*fn)(void *, uint32_t, void *, uint32_t), + void *context); +void dalrpc_dealloc_event(void *handle, + void *ev_h); +void dalrpc_dealloc_cb(void *handle, + void *cb_h); + +#define dalrpc_event_wait(ev_h, timeout) \ + dalrpc_event_wait_multiple(1, &ev_h, timeout) + +int dalrpc_event_wait_multiple(int num, void **ev_h, int timeout); + +#endif /* __DAL_H__ */ diff --git a/arch/arm/mach-msm/include/mach/dma.h b/arch/arm/mach-msm/include/mach/dma.h index 5ab5bdffab07..d743ef88cd3a 100644 --- a/arch/arm/mach-msm/include/mach/dma.h +++ b/arch/arm/mach-msm/include/mach/dma.h @@ -1,6 +1,7 @@ /* linux/include/asm-arm/arch-msm/dma.h * * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -81,6 +82,8 @@ int msm_dmov_exec_cmd(unsigned id, unsigned int cmdptr); /* channel assignments */ +#define DMOV_GP_CHAN 4 + #define DMOV_NAND_CHAN 7 #define DMOV_NAND_CRCI_CMD 5 #define DMOV_NAND_CRCI_DATA 4 diff --git a/arch/arm/mach-msm/include/mach/dma_test.h b/arch/arm/mach-msm/include/mach/dma_test.h new file mode 100644 index 000000000000..f2ccaa3a0031 --- /dev/null +++ b/arch/arm/mach-msm/include/mach/dma_test.h @@ -0,0 +1,96 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef __MSM_DMA_TEST__ +#define __MSM_DMA_TEST__ + +#include + +#define MSM_DMA_IOC_MAGIC 0x83 + +/* The testing driver can manage a series of buffers. These are + * allocated and freed using these calls. */ +struct msm_dma_alloc_req { + int size; /* Size of this request, in bytes. */ + int bufnum; /* OUT: Number of buffer allocated. */ +}; +#define MSM_DMA_IOALLOC _IOWR(MSM_DMA_IOC_MAGIC, 2, struct msm_dma_alloc_req) + +/* Free the specified buffer. */ +#define MSM_DMA_IOFREE _IOW(MSM_DMA_IOC_MAGIC, 3, int) + +/* Free all used buffers. */ +#define MSM_DMA_IOFREEALL _IO(MSM_DMA_IOC_MAGIC, 7) + +/* Read/write data into kernel buffer. */ +struct msm_dma_bufxfer { + void *data; + int size; + int bufnum; +}; +#define MSM_DMA_IOWBUF _IOW(MSM_DMA_IOC_MAGIC, 4, struct msm_dma_bufxfer) +#define MSM_DMA_IORBUF _IOW(MSM_DMA_IOC_MAGIC, 5, struct msm_dma_bufxfer) + +/* Use the data mover to copy from one buffer to another. */ +struct msm_dma_scopy { + int srcbuf; + int destbuf; + int size; +}; +#define MSM_DMA_IOSCOPY _IOW(MSM_DMA_IOC_MAGIC, 6, struct msm_dma_scopy) + +#endif /* __MSM_DMA_TEST__ */ diff --git a/arch/arm/mach-msm/include/mach/gpio.h b/arch/arm/mach-msm/include/mach/gpio.h index 590573f78c2f..1c4e19ea15a0 100644 --- a/arch/arm/mach-msm/include/mach/gpio.h +++ b/arch/arm/mach-msm/include/mach/gpio.h @@ -1,6 +1,7 @@ /* linux/include/asm-arm/arch-msm/gpio.h * * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2009, Code Aurora Forum. All rights reserved. * Author: Mike Lockwood * * This software is licensed under the terms of the GNU General Public @@ -44,4 +45,48 @@ extern int gpio_configure(unsigned int gpio, unsigned long flags); extern int gpio_read_detect_status(unsigned int gpio); extern int gpio_clear_detect_status(unsigned int gpio); +/* GPIO TLMM (Top Level Multiplexing) Definitions */ + +/* GPIO TLMM: Function -- GPIO specific */ + +/* GPIO TLMM: Direction */ +enum { + GPIO_INPUT, + GPIO_OUTPUT, +}; + +/* GPIO TLMM: Pullup/Pulldown */ +enum { + GPIO_NO_PULL, + GPIO_PULL_DOWN, + GPIO_KEEPER, + GPIO_PULL_UP, +}; + +/* GPIO TLMM: Drive Strength */ +enum { + GPIO_2MA, + GPIO_4MA, + GPIO_6MA, + GPIO_8MA, + GPIO_10MA, + GPIO_12MA, + GPIO_14MA, + GPIO_16MA, +}; + +enum { + GPIO_ENABLE, + GPIO_DISABLE, +}; + +#define GPIO_CFG(gpio, func, dir, pull, drvstr) \ + ((((gpio) & 0x3FF) << 4) | \ + ((func) & 0xf) | \ + (((dir) & 0x1) << 14) | \ + (((pull) & 0x3) << 15) | \ + (((drvstr) & 0xF) << 17)) + +int gpio_tlmm_config(unsigned config, unsigned disable); + #endif diff --git a/arch/arm/mach-msm/include/mach/htc_pwrsink.h b/arch/arm/mach-msm/include/mach/htc_pwrsink.h index d82c21273a45..c7a91f1d906c 100644 --- a/arch/arm/mach-msm/include/mach/htc_pwrsink.h +++ b/arch/arm/mach-msm/include/mach/htc_pwrsink.h @@ -68,7 +68,6 @@ struct pwr_sink_platform_data { #ifndef CONFIG_HTC_PWRSINK static inline int htc_pwrsink_set(pwrsink_id_type id, unsigned percent) { - printk(KERN_DEBUG "%s:STUB!\n", __func__); return 0; } static inline int htc_pwrsink_audio_set(pwrsink_audio_id_type id, diff --git a/arch/arm/mach-msm/include/mach/io.h b/arch/arm/mach-msm/include/mach/io.h index aab964591db4..bdac617f4204 100644 --- a/arch/arm/mach-msm/include/mach/io.h +++ b/arch/arm/mach-msm/include/mach/io.h @@ -23,7 +23,7 @@ void __iomem *__msm_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype); -#define __io(a) __typesafe_io(a) +#define __io(a) __typesafe_io(a) #define __mem_pci(a) (a) #endif diff --git a/arch/arm/mach-msm/include/mach/irqs-7xxx.h b/arch/arm/mach-msm/include/mach/irqs-7xxx.h new file mode 100644 index 000000000000..ccb13eb67bde --- /dev/null +++ b/arch/arm/mach-msm/include/mach/irqs-7xxx.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * Author: Brian Swetland + */ + +#ifndef __ASM_ARCH_MSM_IRQS_7XXX_H +#define __ASM_ARCH_MSM_IRQS_7XXX_H + +/* MSM ARM11 Interrupt Numbers */ +/* See 80-VE113-1 A, pp219-221 */ + +#define INT_A9_M2A_0 0 +#define INT_A9_M2A_1 1 +#define INT_A9_M2A_2 2 +#define INT_A9_M2A_3 3 +#define INT_A9_M2A_4 4 +#define INT_A9_M2A_5 5 +#define INT_A9_M2A_6 6 +#define INT_GP_TIMER_EXP 7 +#define INT_DEBUG_TIMER_EXP 8 +#define INT_UART1 9 +#define INT_UART2 10 +#define INT_UART3 11 +#define INT_UART1_RX 12 +#define INT_UART2_RX 13 +#define INT_UART3_RX 14 +#define INT_USB_OTG 15 +#define INT_MDDI_PRI 16 +#define INT_MDDI_EXT 17 +#define INT_MDDI_CLIENT 18 +#define INT_MDP 19 +#define INT_GRAPHICS 20 +#define INT_ADM_AARM 21 +#define INT_ADSP_A11 22 +#define INT_ADSP_A9_A11 23 +#define INT_SDC1_0 24 +#define INT_SDC1_1 25 +#define INT_SDC2_0 26 +#define INT_SDC2_1 27 +#define INT_KEYSENSE 28 +#define INT_TCHSCRN_SSBI 29 +#define INT_TCHSCRN1 30 +#define INT_TCHSCRN2 31 + +#define INT_GPIO_GROUP1 (32 + 0) +#define INT_GPIO_GROUP2 (32 + 1) +#define INT_PWB_I2C (32 + 2) +#define INT_SOFTRESET (32 + 3) +#define INT_NAND_WR_ER_DONE (32 + 4) +#define INT_NAND_OP_DONE (32 + 5) +#define INT_PBUS_ARM11 (32 + 6) +#define INT_AXI_MPU_SMI (32 + 7) +#define INT_AXI_MPU_EBI1 (32 + 8) +#define INT_AD_HSSD (32 + 9) +#define INT_ARM11_PMU (32 + 10) +#define INT_ARM11_DMA (32 + 11) +#define INT_TSIF_IRQ (32 + 12) +#define INT_UART1DM_IRQ (32 + 13) +#define INT_UART1DM_RX (32 + 14) +#define INT_USB_HS (32 + 15) +#define INT_SDC3_0 (32 + 16) +#define INT_SDC3_1 (32 + 17) +#define INT_SDC4_0 (32 + 18) +#define INT_SDC4_1 (32 + 19) +#define INT_UART2DM_RX (32 + 20) +#define INT_UART2DM_IRQ (32 + 21) + +/* 22-31 are reserved */ + +/* 7x00A uses 122, but 7x25 has up to 132. */ +#define NR_GPIO_IRQS 133 + +#endif diff --git a/arch/arm/mach-msm/include/mach/irqs-8xxx.h b/arch/arm/mach-msm/include/mach/irqs-8xxx.h new file mode 100644 index 000000000000..9cedbfeb60b8 --- /dev/null +++ b/arch/arm/mach-msm/include/mach/irqs-8xxx.h @@ -0,0 +1,131 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef __ASM_ARCH_MSM_IRQS_8XXX_H +#define __ASM_ARCH_MSM_IRQS_8XXX_H + +/* MSM ACPU Interrupt Numbers */ + +#define INT_A9_M2A_0 0 +#define INT_A9_M2A_1 1 +#define INT_A9_M2A_2 2 +#define INT_A9_M2A_3 3 +#define INT_A9_M2A_4 4 +#define INT_A9_M2A_5 5 +#define INT_A9_M2A_6 6 +#define INT_GP_TIMER_EXP 7 +#define INT_DEBUG_TIMER_EXP 8 +#define INT_SIRC_0 9 +#define INT_SDC3_0 10 +#define INT_SDC3_1 11 +#define INT_SDC4_0 12 +#define INT_SDC4_1 13 +#define INT_AD6_EXT_VFR 14 +#define INT_USB_OTG 15 +#define INT_MDDI_PRI 16 +#define INT_MDDI_EXT 17 +#define INT_MDDI_CLIENT 18 +#define INT_MDP 19 +#define INT_GRAPHICS 20 +#define INT_ADM_AARM 21 +#define INT_ADSP_A11 22 +#define INT_ADSP_A9_A11 23 +#define INT_SDC1_0 24 +#define INT_SDC1_1 25 +#define INT_SDC2_0 26 +#define INT_SDC2_1 27 +#define INT_KEYSENSE 28 +#define INT_TCHSCRN_SSBI 29 +#define INT_TCHSCRN1 30 +#define INT_TCHSCRN2 31 + +#define INT_TCSR_MPRPH_SC1 (32 + 0) +#define INT_USB_FS2 (32 + 1) +#define INT_PWB_I2C (32 + 2) +#define INT_SOFTRESET (32 + 3) +#define INT_NAND_WR_ER_DONE (32 + 4) +#define INT_NAND_OP_DONE (32 + 5) +#define INT_TCSR_MPRPH_SC2 (32 + 6) +#define INT_OP_PEN (32 + 7) +#define INT_AD_HSSD (32 + 8) +#define INT_ARM11_PM (32 + 9) +#define INT_SDMA_NON_SECURE (32 + 10) +#define INT_TSIF_IRQ (32 + 11) +#define INT_UART1DM_IRQ (32 + 12) +#define INT_UART1DM_RX (32 + 13) +#define INT_SDMA_SECURE (32 + 14) +#define INT_SI2S_SLAVE (32 + 15) +#define INT_SC_I2CPU (32 + 16) +#define INT_SC_DBG_RDTRFULL (32 + 17) +#define INT_SC_DBG_WDTRFULL (32 + 18) +#define INT_SCPLL_CTL_DONE (32 + 19) +#define INT_UART2DM_IRQ (32 + 20) +#define INT_UART2DM_RX (32 + 21) +#define INT_VDC_MEC (32 + 22) +#define INT_VDC_DB (32 + 23) +#define INT_VDC_AXI (32 + 24) +#define INT_VFE (32 + 25) +#define INT_USB_HS (32 + 26) +#define INT_AUDIO_OUT0 (32 + 27) +#define INT_AUDIO_OUT1 (32 + 28) +#define INT_CRYPTO (32 + 29) +#define INT_AD6M_IDLE (32 + 30) +#define INT_SIRC_1 (32 + 31) + +#define NR_GPIO_IRQS 165 + +#endif diff --git a/arch/arm/mach-msm/include/mach/irqs.h b/arch/arm/mach-msm/include/mach/irqs.h index 9dd4cf8a2693..69af8fc00c9d 100644 --- a/arch/arm/mach-msm/include/mach/irqs.h +++ b/arch/arm/mach-msm/include/mach/irqs.h @@ -1,6 +1,6 @@ -/* arch/arm/mach-msm/include/mach/irqs.h - * +/* * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. * Author: Brian Swetland * * This software is licensed under the terms of the GNU General Public @@ -17,72 +17,18 @@ #ifndef __ASM_ARCH_MSM_IRQS_H #define __ASM_ARCH_MSM_IRQS_H -/* MSM ARM11 Interrupt Numbers */ -/* See 80-VE113-1 A, pp219-221 */ - -#define INT_A9_M2A_0 0 -#define INT_A9_M2A_1 1 -#define INT_A9_M2A_2 2 -#define INT_A9_M2A_3 3 -#define INT_A9_M2A_4 4 -#define INT_A9_M2A_5 5 -#define INT_A9_M2A_6 6 -#define INT_GP_TIMER_EXP 7 -#define INT_DEBUG_TIMER_EXP 8 -#define INT_UART1 9 -#define INT_UART2 10 -#define INT_UART3 11 -#define INT_UART1_RX 12 -#define INT_UART2_RX 13 -#define INT_UART3_RX 14 -#define INT_USB_OTG 15 -#define INT_MDDI_PRI 16 -#define INT_MDDI_EXT 17 -#define INT_MDDI_CLIENT 18 -#define INT_MDP 19 -#define INT_GRAPHICS 20 -#define INT_ADM_AARM 21 -#define INT_ADSP_A11 22 -#define INT_ADSP_A9_A11 23 -#define INT_SDC1_0 24 -#define INT_SDC1_1 25 -#define INT_SDC2_0 26 -#define INT_SDC2_1 27 -#define INT_KEYSENSE 28 -#define INT_TCHSCRN_SSBI 29 -#define INT_TCHSCRN1 30 -#define INT_TCHSCRN2 31 - -#define INT_GPIO_GROUP1 (32 + 0) -#define INT_GPIO_GROUP2 (32 + 1) -#define INT_PWB_I2C (32 + 2) -#define INT_SOFTRESET (32 + 3) -#define INT_NAND_WR_ER_DONE (32 + 4) -#define INT_NAND_OP_DONE (32 + 5) -#define INT_PBUS_ARM11 (32 + 6) -#define INT_AXI_MPU_SMI (32 + 7) -#define INT_AXI_MPU_EBI1 (32 + 8) -#define INT_AD_HSSD (32 + 9) -#define INT_ARM11_PMU (32 + 10) -#define INT_ARM11_DMA (32 + 11) -#define INT_TSIF_IRQ (32 + 12) -#define INT_UART1DM_IRQ (32 + 13) -#define INT_UART1DM_RX (32 + 14) -#define INT_USB_HS (32 + 15) -#define INT_SDC3_0 (32 + 16) -#define INT_SDC3_1 (32 + 17) -#define INT_SDC4_0 (32 + 18) -#define INT_SDC4_1 (32 + 19) -#define INT_UART2DM_RX (32 + 20) -#define INT_UART2DM_IRQ (32 + 21) - -/* 22-31 are reserved */ - #define MSM_IRQ_BIT(irq) (1 << ((irq) & 31)) #define NR_MSM_IRQS 64 -#define NR_GPIO_IRQS 122 #define NR_BOARD_IRQS 64 + +#if defined(CONFIG_ARCH_QSD) +#include "irqs-8xxx.h" +#include "sirc.h" +#else +#include "irqs-7xxx.h" +#endif + #define NR_IRQS (NR_MSM_IRQS + NR_GPIO_IRQS + NR_BOARD_IRQS) #define MSM_GPIO_TO_INT(n) (NR_MSM_IRQS + (n)) diff --git a/arch/arm/mach-msm/include/mach/memory.h b/arch/arm/mach-msm/include/mach/memory.h index f4698baec976..77316bb85e15 100644 --- a/arch/arm/mach-msm/include/mach/memory.h +++ b/arch/arm/mach-msm/include/mach/memory.h @@ -1,6 +1,7 @@ /* arch/arm/mach-msm/include/mach/memory.h * * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2009, Code Aurora Forum. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -12,12 +13,38 @@ * GNU General Public License for more details. * */ - #ifndef __ASM_ARCH_MEMORY_H #define __ASM_ARCH_MEMORY_H /* physical offset of RAM */ +#ifdef CONFIG_MSM_STACKED_MEMORY + +#ifdef CONFIG_ARCH_QSD +#define PHYS_OFFSET UL(0x16000000) +#else #define PHYS_OFFSET UL(0x10000000) +#endif + +#else + +#define PHYS_OFFSET UL(0x00200000) + +#endif + +#ifndef __ASSEMBLY__ +void *alloc_bootmem_aligned(unsigned long size, unsigned long alignment); + +#ifdef CONFIG_ARCH_MSM +void write_to_strongly_ordered_memory(void); + +#include + +#define arch_barrier_extra() do \ + { if (machine_is_msm7x27_surf() || machine_is_msm7x27_ffa()) \ + write_to_strongly_ordered_memory(); \ + } while (0) +#endif +#endif #endif diff --git a/arch/arm/mach-msm/include/mach/mpp.h b/arch/arm/mach-msm/include/mach/mpp.h new file mode 100644 index 000000000000..aa52baf26edb --- /dev/null +++ b/arch/arm/mach-msm/include/mach/mpp.h @@ -0,0 +1,90 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef __ARCH_ARM_MACH_MSM_MPP_H +#define __ARCH_ARM_MACH_MSM_MPP_H + +struct mpp { + const char *name; + unsigned id; + int status; +}; + +/* Digital Logical Output Level */ +enum { + MPP_DLOGIC_LVL_MSME, + MPP_DLOGIC_LVL_MSMP, + MPP_DLOGIC_LVL_RUIM, + MPP_DLOGIC_LVL_MMC, + MPP_DLOGIC_LVL_VDD, +}; + +/* Digital Logical Output Control Value */ +enum { + MPP_DLOGIC_OUT_CTRL_LOW, + MPP_DLOGIC_OUT_CTRL_HIGH, + MPP_DLOGIC_OUT_CTRL_MPP, /* MPP Output = MPP Input */ + MPP_DLOGIC_OUT_CTRL_NOT_MPP, /* MPP Output = Inverted MPP Input */ +}; + +#define MPP_CFG(level, control) ((((level) & 0x0FFFF) << 16) | \ + ((control) & 0x0FFFFF)) + +struct mpp *mpp_get(struct device *dev, const char *id); +int mpp_config_digital_out(struct mpp *mpp, unsigned config); + +#endif diff --git a/arch/arm/mach-msm/include/mach/msm_handset.h b/arch/arm/mach-msm/include/mach/msm_handset.h new file mode 100644 index 000000000000..4d6ccd21d4da --- /dev/null +++ b/arch/arm/mach-msm/include/mach/msm_handset.h @@ -0,0 +1,36 @@ +/* arch/arm/mach-msm/include/mach/msm_handset.h + * + * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#ifndef _MSM_HANDSET_H +#define _MSM_HANDSET_H + +#include +#include + +#if defined(CONFIG_INPUT_MSM_HANDSET) +struct input_dev *msm_get_handset_input_dev(void); +#else +struct input_dev *msm_get_handset_input_dev(void) +{ + return NULL; +} +#endif + +struct msm_handset { + struct input_dev *ip_dev; + struct switch_dev sdev; +}; + +#endif diff --git a/arch/arm/mach-msm/include/mach/msm_i2ckbd.h b/arch/arm/mach-msm/include/mach/msm_i2ckbd.h new file mode 100644 index 000000000000..2b78ba842ffc --- /dev/null +++ b/arch/arm/mach-msm/include/mach/msm_i2ckbd.h @@ -0,0 +1,70 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef _MSM_I2CKBD_H_ +#define _MSM_I2CKBD_H_ + +struct msm_i2ckbd_platform_data { + uint8_t hwrepeat; + uint8_t scanset1; + int gpioreset; + int gpioirq; + int (*gpio_setup) (void); + void (*gpio_shutdown)(void); +}; + +#endif diff --git a/arch/arm/mach-msm/include/mach/msm_iomap.h b/arch/arm/mach-msm/include/mach/msm_iomap.h index ea107948e3dc..22e1ecb52555 100644 --- a/arch/arm/mach-msm/include/mach/msm_iomap.h +++ b/arch/arm/mach-msm/include/mach/msm_iomap.h @@ -1,6 +1,7 @@ /* arch/arm/mach-msm/include/mach/msm_iomap.h * * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. * Author: Brian Swetland * * This software is licensed under the terms of the GNU General Public @@ -44,11 +45,19 @@ #endif #define MSM_VIC_BASE IOMEM(0xE0000000) +#if defined(CONFIG_ARCH_QSD) +#define MSM_VIC_PHYS 0xAC000000 +#else #define MSM_VIC_PHYS 0xC0000000 +#endif #define MSM_VIC_SIZE SZ_4K #define MSM_CSR_BASE IOMEM(0xE0001000) +#if defined(CONFIG_ARCH_QSD) +#define MSM_CSR_PHYS 0xAC100000 +#else #define MSM_CSR_PHYS 0xC0100000 +#endif #define MSM_CSR_SIZE SZ_4K #define MSM_GPT_PHYS MSM_CSR_PHYS @@ -60,19 +69,38 @@ #define MSM_DMOV_SIZE SZ_4K #define MSM_GPIO1_BASE IOMEM(0xE0003000) +#if defined(CONFIG_ARCH_QSD) +#define MSM_GPIO1_PHYS 0xA9000000 +#else #define MSM_GPIO1_PHYS 0xA9200000 +#endif #define MSM_GPIO1_SIZE SZ_4K #define MSM_GPIO2_BASE IOMEM(0xE0004000) +#if defined(CONFIG_ARCH_QSD) +#define MSM_GPIO2_PHYS 0xA9100000 +#else #define MSM_GPIO2_PHYS 0xA9300000 +#endif #define MSM_GPIO2_SIZE SZ_4K #define MSM_CLK_CTL_BASE IOMEM(0xE0005000) #define MSM_CLK_CTL_PHYS 0xA8600000 #define MSM_CLK_CTL_SIZE SZ_4K +#define MSM_L2CC_BASE IOMEM(0xE0006000) +#define MSM_L2CC_PHYS 0xC0400000 +#define MSM_L2CC_SIZE SZ_4K + +#define MSM_SIRC_BASE IOMEM(0xE1006000) +#define MSM_SIRC_PHYS 0xAC200000 +#define MSM_SIRC_SIZE SZ_4K + +#define MSM_SCPLL_BASE IOMEM(0xE1007000) +#define MSM_SCPLL_PHYS 0xA8800000 +#define MSM_SCPLL_SIZE SZ_4K + #define MSM_SHARED_RAM_BASE IOMEM(0xE0100000) -#define MSM_SHARED_RAM_PHYS 0x01F00000 #define MSM_SHARED_RAM_SIZE SZ_1M #define MSM_UART1_PHYS 0xA9A00000 @@ -96,18 +124,6 @@ #define MSM_DEBUG_UART_SIZE SZ_4K #endif -#define MSM_SDC1_PHYS 0xA0400000 -#define MSM_SDC1_SIZE SZ_4K - -#define MSM_SDC2_PHYS 0xA0500000 -#define MSM_SDC2_SIZE SZ_4K - -#define MSM_SDC3_PHYS 0xA0600000 -#define MSM_SDC3_SIZE SZ_4K - -#define MSM_SDC4_PHYS 0xA0700000 -#define MSM_SDC4_SIZE SZ_4K - #define MSM_I2C_PHYS 0xA9900000 #define MSM_I2C_SIZE SZ_4K @@ -115,22 +131,13 @@ #define MSM_HSUSB_BASE IOMEM(0xE0009000) #define MSM_HSUSB_SIZE SZ_4K -#define MSM_PMDH_PHYS 0xAA600000 -#define MSM_PMDH_SIZE SZ_4K - -#define MSM_EMDH_PHYS 0xAA700000 -#define MSM_EMDH_SIZE SZ_4K - -#define MSM_MDP_PHYS 0xAA200000 -#define MSM_MDP_SIZE 0x000F0000 - +#define MSM_MDC_BASE IOMEM(0xE0200000) #define MSM_MDC_PHYS 0xAA500000 #define MSM_MDC_SIZE SZ_1M #define MSM_AD5_PHYS 0xAC000000 #define MSM_AD5_SIZE (SZ_1M*13) - #define MSM_SSBI_BASE IOMEM(0xE1004000) #define MSM_SSBI_PHYS 0xA8100000 #define MSM_SSBI_SIZE SZ_4K diff --git a/arch/arm/mach-msm/include/mach/msm_otg.h b/arch/arm/mach-msm/include/mach/msm_otg.h new file mode 100644 index 000000000000..6ab662921fee --- /dev/null +++ b/arch/arm/mach-msm/include/mach/msm_otg.h @@ -0,0 +1,72 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#ifndef __ARCH_ARM_MACH_MSM_OTG_H +#define __ARCH_ARM_MACH_MSM_OTG_H + +/* + * The otg driver needs to interact with both device side and host side + * usb controllers. it decides which controller is active at a given + * moment, using the transceiver, ID signal. + */ + +struct msm_otg_transceiver { + struct device *dev; + struct clk *clk; + struct clk *pclk; + int in_lpm; + struct msm_otg_ops *dcd_ops; + struct msm_otg_ops *hcd_ops; + int irq; + int flags; + int state; + int active; + void __iomem *regs; /* device memory/io */ + struct work_struct work; + spinlock_t lock; + + /* bind/unbind the host controller */ + int (*set_host)(struct msm_otg_transceiver *otg, + struct msm_otg_ops *hcd_ops); + + /* bind/unbind the peripheral controller */ + int (*set_peripheral)(struct msm_otg_transceiver *otg, + struct msm_otg_ops *dcd_ops); + void (*set_suspend) (int on); + +}; + +struct msm_otg_ops { + void (*status_change)(int); +}; + +/* for usb host and peripheral controller drivers */ +#ifdef CONFIG_USB_MSM_OTG + +extern struct msm_otg_transceiver *msm_otg_get_transceiver(void); +extern void msm_otg_put_transceiver(struct msm_otg_transceiver *xceiv); + +#else + +static inline struct msm_otg_transceiver *msm_otg_get_transceiver(void) +{ + return NULL; +} + +static inline void msm_otg_put_transceiver(struct msm_otg_transceiver *xceiv) +{ +} + +#endif /*CONFIG_USB_MSM_OTG*/ + +#endif diff --git a/arch/arm/mach-msm/include/mach/msm_rpcrouter.h b/arch/arm/mach-msm/include/mach/msm_rpcrouter.h index facef7cefd2d..86859941210d 100644 --- a/arch/arm/mach-msm/include/mach/msm_rpcrouter.h +++ b/arch/arm/mach-msm/include/mach/msm_rpcrouter.h @@ -1,7 +1,7 @@ /** include/asm-arm/arch-msm/msm_rpcrouter.h * * Copyright (C) 2007 Google, Inc. - * Copyright (c) 2007 QUALCOMM Incorporated + * Copyright (c) 2007-2009, Code Aurora Forum. All rights reserved. * Author: San Mehat * * This software is licensed under the terms of the GNU General Public @@ -28,6 +28,20 @@ struct rpcrouter_ioctl_server_args { uint32_t vers; }; +/* RPC API version structure + * Version bit 31 : 1->hashkey versioning, + * 0->major-minor (backward compatible) versioning + * hashkey versioning: + * Version bits 31-0 hashkey + * major-minor (backward compatible) versioning + * Version bits 30-28 reserved (no match) + * Version bits 27-16 major (must match) + * Version bits 15-0 minor (greater or equal) + */ +#define RPC_VERSION_MODE_MASK 0x80000000 +#define RPC_VERSION_MAJOR_MASK 0x0fff0000 +#define RPC_VERSION_MINOR_MASK 0x0000ffff + struct msm_rpc_endpoint; struct rpcsvr_platform_device @@ -105,7 +119,16 @@ struct rpc_reply_hdr /* use IS_ERR() to check for failure */ struct msm_rpc_endpoint *msm_rpc_open(void); +/* Connect with the specified server version */ struct msm_rpc_endpoint *msm_rpc_connect(uint32_t prog, uint32_t vers, unsigned flags); +/* Connect with a compatible server version */ +struct msm_rpc_endpoint *msm_rpc_connect_compatible(uint32_t prog, + uint32_t vers, unsigned flags); +int msm_rpc_get_compatible_server(uint32_t prog, uint32_t vers, + uint32_t *found_vers); +/* check if server version can handle client requested version */ +int msm_rpc_is_compatible_version(uint32_t server_version, + uint32_t client_version); int msm_rpc_close(struct msm_rpc_endpoint *ept); int msm_rpc_write(struct msm_rpc_endpoint *ept, @@ -119,6 +142,7 @@ int msm_rpc_register_server(struct msm_rpc_endpoint *ept, int msm_rpc_unregister_server(struct msm_rpc_endpoint *ept, uint32_t prog, uint32_t vers); +int msm_rpc_clear_netreset(struct msm_rpc_endpoint *ept); /* simple blocking rpc call * * request is mandatory and must have a rpc_request_hdr diff --git a/arch/arm/mach-msm/include/mach/msm_smd.h b/arch/arm/mach-msm/include/mach/msm_smd.h index bdf7731ab680..74ef100af8f5 100644 --- a/arch/arm/mach-msm/include/mach/msm_smd.h +++ b/arch/arm/mach-msm/include/mach/msm_smd.h @@ -1,6 +1,7 @@ /* linux/include/asm-arm/arch-msm/msm_smd.h * * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2009, Code Aurora Forum. All rights reserved. * Author: Brian Swetland * * This software is licensed under the terms of the GNU General Public @@ -31,6 +32,7 @@ int smd_close(smd_channel_t *ch); /* passing a null pointer for data reads and discards */ int smd_read(smd_channel_t *ch, void *data, int len); +int smd_read_from_cb(smd_channel_t *ch, void *data, int len); /* Write to stream channels may do a partial write and return ** the length actually written. @@ -47,12 +49,6 @@ int smd_read_avail(smd_channel_t *ch); */ int smd_cur_packet_size(smd_channel_t *ch); -/* used for tty unthrottling and the like -- causes the notify() -** callback to be called from the same lock context as is used -** when it is called from channel updates -*/ -void smd_kick(smd_channel_t *ch); - #if 0 /* these are interruptable waits which will block you until the specified @@ -62,6 +58,12 @@ int smd_wait_until_readable(smd_channel_t *ch, int bytes); int smd_wait_until_writable(smd_channel_t *ch, int bytes); #endif +/* these are used to get and set the IF sigs of a channel. + * DTR and RTS can be set; DSR, CTS, CD and RI can be read. + */ +int smd_tiocmget(smd_channel_t *ch); +int smd_tiocmset(smd_channel_t *ch, unsigned int set, unsigned int clear); + typedef enum { SMD_PORT_DS = 0, @@ -97,11 +99,26 @@ typedef enum SMD_PORT_BRIDGE_3, SMD_PORT_BRIDGE_4, SMD_PORT_BRIDGE_5, - SMD_PORT_LOOPBACK, SMD_PORT_CS_APPS_MODEM, SMD_PORT_CS_APPS_DSP, SMD_PORT_CS_MODEM_DSP, + SMD_PORT_LOOPBACK, SMD_NUM_PORTS, } smd_port_id_type; +#if defined(CONFIG_MSM_N_WAY_SMD) +enum { + SMD_APPS_MODEM = 0, + SMD_APPS_QDSP, + SMD_MODEM_QDSP +}; +#else +enum { + SMD_APPS_MODEM = 0 +}; +#endif + +int smd_named_open_on_edge(const char *name, uint32_t edge, smd_channel_t **_ch, + void *priv, void (*notify)(void *, unsigned)); + #endif diff --git a/arch/arm/mach-msm/include/mach/msm_touch.h b/arch/arm/mach-msm/include/mach/msm_touch.h new file mode 100644 index 000000000000..763d6a8f1113 --- /dev/null +++ b/arch/arm/mach-msm/include/mach/msm_touch.h @@ -0,0 +1,26 @@ +/* arch/arm/mach-msm/include/mach/msm_touch.h + * + * Platform data for MSM touchscreen driver. + * + * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#ifndef _MACH_MSM_TOUCH_H_ +#define _MACH_MSM_TOUCH_H_ + +struct msm_ts_platform_data { + unsigned int x_max; + unsigned int y_max; + unsigned int pressure_max; +}; + +#endif diff --git a/arch/arm/mach-msm/include/mach/msm_touchpad.h b/arch/arm/mach-msm/include/mach/msm_touchpad.h new file mode 100644 index 000000000000..7e62f0095a79 --- /dev/null +++ b/arch/arm/mach-msm/include/mach/msm_touchpad.h @@ -0,0 +1,66 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +/* + * Touchpad driver for QSD platform. + */ + +struct msm_touchpad_platform_data { + int gpioirq; + int gpiosuspend; + int (*gpio_setup) (void); + void (*gpio_shutdown)(void); +}; diff --git a/arch/arm/mach-msm/include/mach/pmic.h b/arch/arm/mach-msm/include/mach/pmic.h new file mode 100644 index 000000000000..9a810246b6f8 --- /dev/null +++ b/arch/arm/mach-msm/include/mach/pmic.h @@ -0,0 +1,140 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +enum spkr_left_right { + LEFT_SPKR, + RIGHT_SPKR, + SPKR_OUT_OF_RANGE /* Not valid */ +}; + +enum spkr_gain { + SPKR_GAIN_MINUS16DB, /* -16 db */ + SPKR_GAIN_MINUS12DB, /* -12 db */ + SPKR_GAIN_MINUS08DB, /* -08 db */ + SPKR_GAIN_MINUS04DB, /* -04 db */ + SPKR_GAIN_00DB, /* 00 db */ + SPKR_GAIN_PLUS04DB, /* +04 db */ + SPKR_GAIN_PLUS08DB, /* +08 db */ + SPKR_GAIN_PLUS12DB, /* +12 db */ + SPKR_GAIN_OUT_OF_RANGE /* Not valid */ +}; + +/* Turn the speaker on or off and enables or disables mute.*/ +enum spkr_cmd { + SPKR_DISABLE, /* Enable Speaker */ + SPKR_ENABLE, /* Disable Speaker */ + SPKR_MUTE_OFF, /* turn speaker mute off, SOUND ON */ + SPKR_MUTE_ON, /* turn speaker mute on, SOUND OFF */ + SPKR_OFF, /* turn speaker OFF (speaker disable and mute on) */ + SPKR_ON, /* turn speaker ON (speaker enable and mute off) */ + SPKR_SET_FREQ_CMD, /* set speaker frequency */ + SPKR_GET_FREQ_CMD, /* get speaker frequency */ + SPKR_SET_GAIN_CMD, /* set speaker gain */ + SPKR_GET_GAIN_CMD, /* get speaker gain */ + SPKR_SET_DELAY_CMD, /* set speaker delay */ + SPKR_GET_DELAY_CMD, /* get speaker delay */ + SPKR_SET_PDM_MODE, + SPKR_SET_PWM_MODE, + SPKR_CMD_OUT_OF_RANGE /* Not valid */ +}; + +struct spkr_config_mode { + uint32_t is_right_chan_en; + uint32_t is_left_chan_en; + uint32_t is_right_left_chan_added; + uint32_t is_stereo_en; + uint32_t is_usb_with_hpf_20hz; + uint32_t is_mux_bypassed; + uint32_t is_hpf_en; + uint32_t is_sink_curr_from_ref_volt_cir_en; +}; + +enum mic_volt { + MIC_VOLT_2_00V, /* 2.00 V */ + MIC_VOLT_1_93V, /* 1.93 V */ + MIC_VOLT_1_80V, /* 1.80 V */ + MIC_VOLT_1_73V, /* 1.73 V */ + MIC_VOLT_OUT_OF_RANGE /* Not valid */ +}; + +enum ledtype { + LED_LCD, + LED_KEYPAD, + LED_TYPE_OUT_OF_RANGE +}; + +int spkr_en_right_chan(const unsigned char enable); +int spkr_is_right_chan_en(unsigned char *enabled); +int spkr_en_left_chan(const unsigned char enable); +int spkr_is_left_chan_en(unsigned char *enabled); +int spkr_is_en(const enum spkr_left_right left_right, unsigned char *enabled); +int spkr_get_gain(const enum spkr_left_right left_right, enum spkr_gain *gain); +int set_speaker_gain(const enum spkr_gain speaker_gain); +int speaker_cmd(const enum spkr_cmd cmd); +int set_spkr_configuration(const struct spkr_config_mode *t); +int get_spkr_configuration(struct spkr_config_mode *t); + +int mic_en(const unsigned char enable); +int mic_is_en(unsigned char *enabled); +int mic_set_volt(const enum mic_volt type); + +/* Cannot use 'current' as the parameter name because 'current' is defined as + * a macro to get a pointer to the current task. + */ +int flash_led_set_current(const uint16_t milliamps); + +int set_led_intensity(const enum ledtype type, int val); diff --git a/arch/arm/mach-msm/include/mach/remote_spinlock.h b/arch/arm/mach-msm/include/mach/remote_spinlock.h new file mode 100644 index 000000000000..402888eaa56b --- /dev/null +++ b/arch/arm/mach-msm/include/mach/remote_spinlock.h @@ -0,0 +1,75 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef __ASM__ARCH_QC_REMOTE_SPINLOCK_H +#define __ASM__ARCH_QC_REMOTE_SPINLOCK_H + +#include + +typedef struct { + volatile uint32_t lock; +} raw_remote_spinlock_t; + +typedef raw_remote_spinlock_t *_remote_spinlock_t; + +#define remote_spin_lock_id_t uint32_t + +int _remote_spin_lock_init(remote_spin_lock_id_t id, _remote_spinlock_t *lock); +void _remote_spin_lock(_remote_spinlock_t *lock); +void _remote_spin_unlock(_remote_spinlock_t *lock); + +#endif diff --git a/arch/arm/mach-msm/include/mach/rpc_hsusb.h b/arch/arm/mach-msm/include/mach/rpc_hsusb.h new file mode 100644 index 000000000000..9ef304be2189 --- /dev/null +++ b/arch/arm/mach-msm/include/mach/rpc_hsusb.h @@ -0,0 +1,45 @@ +/* linux/include/mach/rpc_hsusb.h + * + * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * All source code in this file is licensed under the following license except + * where indicated. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License 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. + * You should have received a copy of the GNU General Public License + * along with this program; if not, you can find it at http://www.fsf.org + */ + +#ifndef __ASM_ARCH_MSM_RPC_HSUSB_H +#define __ASM_ARCH_MSM_RPC_HSUSB_H + +#include + +int msm_hsusb_rpc_connect(void); +int msm_hsusb_phy_reset(void); +int msm_hsusb_vbus_powerup(void); +int msm_hsusb_vbus_shutdown(void); +int msm_hsusb_send_productID(uint32_t product_id); +int msm_hsusb_send_serial_number(char *serial_number); +int msm_hsusb_is_serial_num_null(uint32_t val); +int msm_hsusb_reset_rework_installed(void); +int msm_hsusb_enable_pmic_ulpidata0(void); +int msm_hsusb_disable_pmic_ulpidata0(void); +int msm_hsusb_rpc_close(void); + +int msm_chg_rpc_connect(void); +int msm_chg_usb_charger_connected(uint32_t type); +int msm_chg_usb_i_is_available(uint32_t sample); +int msm_chg_usb_i_is_not_available(void); +int msm_chg_usb_charger_disconnected(void); +int msm_chg_rpc_close(void); + +#endif diff --git a/arch/arm/mach-msm/include/mach/sirc.h b/arch/arm/mach-msm/include/mach/sirc.h new file mode 100644 index 000000000000..c902cb12ddd6 --- /dev/null +++ b/arch/arm/mach-msm/include/mach/sirc.h @@ -0,0 +1,132 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef __ASM_ARCH_MSM_SIRC_H +#define __ASM_ARCH_MSM_SIRC_H + +struct sirc_regs_t { + void *int_enable; + void *int_enable_clear; + void *int_enable_set; + void *int_type; + void *int_polarity; + void *int_clear; +}; + +struct sirc_cascade_regs { + void *int_status; + unsigned int cascade_irq; +}; + +void msm_init_sirc(void); +void msm_sirc_enter_sleep(void); +void msm_sirc_exit_sleep(void); + +#if defined(CONFIG_ARCH_QSD) + +#include + +/* + * Secondary interrupt controller interrupts + */ + +#define FIRST_SIRC_IRQ (NR_MSM_IRQS + NR_GPIO_IRQS) + +#define INT_UART1 (FIRST_SIRC_IRQ + 0) +#define INT_UART2 (FIRST_SIRC_IRQ + 1) +#define INT_UART3 (FIRST_SIRC_IRQ + 2) +#define INT_UART1_RX (FIRST_SIRC_IRQ + 3) +#define INT_UART2_RX (FIRST_SIRC_IRQ + 4) +#define INT_UART3_RX (FIRST_SIRC_IRQ + 5) +#define INT_SPI_INPUT (FIRST_SIRC_IRQ + 6) +#define INT_SPI_OUTPUT (FIRST_SIRC_IRQ + 7) +#define INT_SPI_ERROR (FIRST_SIRC_IRQ + 8) +#define INT_GPIO_GROUP1 (FIRST_SIRC_IRQ + 9) +#define INT_GPIO_GROUP2 (FIRST_SIRC_IRQ + 10) +#define INT_GPIO_GROUP1_SECURE (FIRST_SIRC_IRQ + 11) +#define INT_GPIO_GROUP2_SECURE (FIRST_SIRC_IRQ + 12) +#define INT_AVS_SVIC (FIRST_SIRC_IRQ + 13) +#define INT_AVS_REQ_UP (FIRST_SIRC_IRQ + 14) +#define INT_AVS_REQ_DOWN (FIRST_SIRC_IRQ + 15) +#define INT_PBUS_ERR (FIRST_SIRC_IRQ + 16) +#define INT_AXI_ERR (FIRST_SIRC_IRQ + 17) +#define INT_SMI_ERR (FIRST_SIRC_IRQ + 18) +#define INT_EBI1_ERR (FIRST_SIRC_IRQ + 19) +#define INT_IMEM_ERR (FIRST_SIRC_IRQ + 20) +#define INT_SC_TEMP_SENSOR (FIRST_SIRC_IRQ + 21) +#define INT_TV_ENC (FIRST_SIRC_IRQ + 22) + +#define NR_SIRC_IRQS 23 +#define SIRC_MASK 0x007FFFFF +#define LAST_SIRC_IRQ (FIRST_SIRC_IRQ + NR_SIRC_IRQS - 1) + +#define SPSS_SIRC_INT_SELECT (MSM_SIRC_BASE + 0x00) +#define SPSS_SIRC_INT_ENABLE (MSM_SIRC_BASE + 0x04) +#define SPSS_SIRC_INT_ENABLE_CLEAR (MSM_SIRC_BASE + 0x08) +#define SPSS_SIRC_INT_ENABLE_SET (MSM_SIRC_BASE + 0x0C) +#define SPSS_SIRC_INT_TYPE (MSM_SIRC_BASE + 0x10) +#define SPSS_SIRC_INT_POLARITY (MSM_SIRC_BASE + 0x14) +#define SPSS_SIRC_SECURITY (MSM_SIRC_BASE + 0x18) +#define SPSS_SIRC_IRQ_STATUS (MSM_SIRC_BASE + 0x1C) +#define SPSS_SIRC_IRQ1_STATUS (MSM_SIRC_BASE + 0x20) +#define SPSS_SIRC_RAW_STATUS (MSM_SIRC_BASE + 0x24) +#define SPSS_SIRC_INT_CLEAR (MSM_SIRC_BASE + 0x28) +#define SPSS_SIRC_SOFT_INT (MSM_SIRC_BASE + 0x2C) + +#endif + +#endif diff --git a/arch/arm/mach-msm/include/mach/smem_log.h b/arch/arm/mach-msm/include/mach/smem_log.h new file mode 100644 index 000000000000..0980670c4cb2 --- /dev/null +++ b/arch/arm/mach-msm/include/mach/smem_log.h @@ -0,0 +1,261 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include + +#define SMEM_LOG_BASE 0x30 + +#define SMIOC_SETMODE _IOW(SMEM_LOG_BASE, 1, int) +#define SMIOC_SETLOG _IOW(SMEM_LOG_BASE, 2, int) + +#define SMIOC_TEXT 0x00000001 +#define SMIOC_BINARY 0x00000002 +#define SMIOC_LOG 0x00000003 +#define SMIOC_STATIC_LOG 0x00000004 + +/* Event indentifier format: + * bit 31-28 is processor ID 8 => apps, 4 => Q6, 0 => modem + * bits 27-16 are subsystem id (event base) + * bits 15-0 are event id + */ + +#define PROC 0xF0000000 +#define SUB 0x0FFF0000 +#define ID 0x0000FFFF + +#define SMEM_LOG_PROC_ID_MODEM 0x00000000 +#define SMEM_LOG_PROC_ID_Q6 0x40000000 +#define SMEM_LOG_PROC_ID_APPS 0x80000000 + +#define SMEM_LOG_CONT 0x10000000 + +#define SMEM_LOG_DEBUG_EVENT_BASE 0x00000000 +#define SMEM_LOG_ONCRPC_EVENT_BASE 0x00010000 +#define SMEM_LOG_SMEM_EVENT_BASE 0x00020000 +#define SMEM_LOG_TMC_EVENT_BASE 0x00030000 +#define SMEM_LOG_TIMETICK_EVENT_BASE 0x00040000 +#define SMEM_LOG_DEM_EVENT_BASE 0x00050000 +#define SMEM_LOG_ERROR_EVENT_BASE 0x00060000 +#define SMEM_LOG_DCVS_EVENT_BASE 0x00070000 +#define SMEM_LOG_SLEEP_EVENT_BASE 0x00080000 +#define SMEM_LOG_RPC_ROUTER_EVENT_BASE 0x00090000 +#if defined(CONFIG_MSM_N_WAY_SMSM) +#define DEM_SMSM_ISR (SMEM_LOG_DEM_EVENT_BASE + 0x1) +#define DEM_STATE_CHANGE (SMEM_LOG_DEM_EVENT_BASE + 0x2) +#define DEM_STATE_MACHINE_ENTER (SMEM_LOG_DEM_EVENT_BASE + 0x3) +#define DEM_ENTER_SLEEP (SMEM_LOG_DEM_EVENT_BASE + 0x4) +#define DEM_END_SLEEP (SMEM_LOG_DEM_EVENT_BASE + 0x5) +#define DEM_SETUP_SLEEP (SMEM_LOG_DEM_EVENT_BASE + 0x6) +#define DEM_SETUP_POWER_COLLAPSE (SMEM_LOG_DEM_EVENT_BASE + 0x7) +#define DEM_SETUP_SUSPEND (SMEM_LOG_DEM_EVENT_BASE + 0x8) +#define DEM_EARLY_EXIT (SMEM_LOG_DEM_EVENT_BASE + 0x9) +#define DEM_WAKEUP_REASON (SMEM_LOG_DEM_EVENT_BASE + 0xA) +#define DEM_DETECT_WAKEUP (SMEM_LOG_DEM_EVENT_BASE + 0xB) +#define DEM_DETECT_RESET (SMEM_LOG_DEM_EVENT_BASE + 0xC) +#define DEM_DETECT_SLEEPEXIT (SMEM_LOG_DEM_EVENT_BASE + 0xD) +#define DEM_DETECT_RUN (SMEM_LOG_DEM_EVENT_BASE + 0xE) +#define DEM_APPS_SWFI (SMEM_LOG_DEM_EVENT_BASE + 0xF) +#define DEM_SEND_WAKEUP (SMEM_LOG_DEM_EVENT_BASE + 0x10) +#define DEM_ASSERT_OKTS (SMEM_LOG_DEM_EVENT_BASE + 0x11) +#define DEM_NEGATE_OKTS (SMEM_LOG_DEM_EVENT_BASE + 0x12) +#define DEM_PROC_COMM_CMD (SMEM_LOG_DEM_EVENT_BASE + 0x13) +#define DEM_REMOVE_PROC_PWR (SMEM_LOG_DEM_EVENT_BASE + 0x14) +#define DEM_RESTORE_PROC_PWR (SMEM_LOG_DEM_EVENT_BASE + 0x15) +#define DEM_SMI_CLK_DISABLED (SMEM_LOG_DEM_EVENT_BASE + 0x16) +#define DEM_SMI_CLK_ENABLED (SMEM_LOG_DEM_EVENT_BASE + 0x17) +#define DEM_MAO_INTS (SMEM_LOG_DEM_EVENT_BASE + 0x18) +#define DEM_APPS_WAKEUP_INT (SMEM_LOG_DEM_EVENT_BASE + 0x19) +#define DEM_PROC_WAKEUP (SMEM_LOG_DEM_EVENT_BASE + 0x1A) +#define DEM_PROC_POWERUP (SMEM_LOG_DEM_EVENT_BASE + 0x1B) +#define DEM_TIMER_EXPIRED (SMEM_LOG_DEM_EVENT_BASE + 0x1C) +#define DEM_SEND_BATTERY_INFO (SMEM_LOG_DEM_EVENT_BASE + 0x1D) +#define DEM_REMOTE_PWR_CB (SMEM_LOG_DEM_EVENT_BASE + 0x24) +#define DEM_TIME_SYNC_START (SMEM_LOG_DEM_EVENT_BASE + 0x1E) +#define DEM_TIME_SYNC_SEND_VALUE (SMEM_LOG_DEM_EVENT_BASE + 0x1F) +#define DEM_TIME_SYNC_DONE (SMEM_LOG_DEM_EVENT_BASE + 0x20) +#define DEM_TIME_SYNC_REQUEST (SMEM_LOG_DEM_EVENT_BASE + 0x21) +#define DEM_TIME_SYNC_POLL (SMEM_LOG_DEM_EVENT_BASE + 0x22) +#define DEM_TIME_SYNC_INIT (SMEM_LOG_DEM_EVENT_BASE + 0x23) +#define DEM_INIT (SMEM_LOG_DEM_EVENT_BASE + 0x25) +#else +#define DEM_NO_SLEEP (SMEM_LOG_DEM_EVENT_BASE + 1) +#define DEM_INSUF_TIME (SMEM_LOG_DEM_EVENT_BASE + 2) +#define DEMAPPS_ENTER_SLEEP (SMEM_LOG_DEM_EVENT_BASE + 3) +#define DEMAPPS_DETECT_WAKEUP (SMEM_LOG_DEM_EVENT_BASE + 4) +#define DEMAPPS_END_APPS_TCXO (SMEM_LOG_DEM_EVENT_BASE + 5) +#define DEMAPPS_ENTER_SLEEPEXIT (SMEM_LOG_DEM_EVENT_BASE + 6) +#define DEMAPPS_END_APPS_SLEEP (SMEM_LOG_DEM_EVENT_BASE + 7) +#define DEMAPPS_SETUP_APPS_PWRCLPS (SMEM_LOG_DEM_EVENT_BASE + 8) +#define DEMAPPS_PWRCLPS_EARLY_EXIT (SMEM_LOG_DEM_EVENT_BASE + 9) +#define DEMMOD_SEND_WAKEUP (SMEM_LOG_DEM_EVENT_BASE + 0xA) +#define DEMMOD_NO_APPS_VOTE (SMEM_LOG_DEM_EVENT_BASE + 0xB) +#define DEMMOD_NO_TCXO_SLEEP (SMEM_LOG_DEM_EVENT_BASE + 0xC) +#define DEMMOD_BT_CLOCK (SMEM_LOG_DEM_EVENT_BASE + 0xD) +#define DEMMOD_UART_CLOCK (SMEM_LOG_DEM_EVENT_BASE + 0xE) +#define DEMMOD_OKTS (SMEM_LOG_DEM_EVENT_BASE + 0xF) +#define DEM_SLEEP_INFO (SMEM_LOG_DEM_EVENT_BASE + 0x10) +#define DEMMOD_TCXO_END (SMEM_LOG_DEM_EVENT_BASE + 0x11) +#define DEMMOD_END_SLEEP_SIG (SMEM_LOG_DEM_EVENT_BASE + 0x12) +#define DEMMOD_SETUP_APPSSLEEP (SMEM_LOG_DEM_EVENT_BASE + 0x13) +#define DEMMOD_ENTER_TCXO (SMEM_LOG_DEM_EVENT_BASE + 0x14) +#define DEMMOD_WAKE_APPS (SMEM_LOG_DEM_EVENT_BASE + 0x15) +#define DEMMOD_POWER_COLLAPSE_APPS (SMEM_LOG_DEM_EVENT_BASE + 0x16) +#define DEMMOD_RESTORE_APPS_PWR (SMEM_LOG_DEM_EVENT_BASE + 0x17) +#define DEMAPPS_ASSERT_OKTS (SMEM_LOG_DEM_EVENT_BASE + 0x18) +#define DEMAPPS_RESTART_START_TIMER (SMEM_LOG_DEM_EVENT_BASE + 0x19) +#define DEMAPPS_ENTER_RUN (SMEM_LOG_DEM_EVENT_BASE + 0x1A) +#define DEMMOD_MAO_INTS (SMEM_LOG_DEM_EVENT_BASE + 0x1B) +#define DEMMOD_POWERUP_APPS_CALLED (SMEM_LOG_DEM_EVENT_BASE + 0x1C) +#define DEMMOD_PC_TIMER_EXPIRED (SMEM_LOG_DEM_EVENT_BASE + 0x1D) +#define DEM_DETECT_SLEEPEXIT (SMEM_LOG_DEM_EVENT_BASE + 0x1E) +#define DEM_DETECT_RUN (SMEM_LOG_DEM_EVENT_BASE + 0x1F) +#define DEM_SET_APPS_TIMER (SMEM_LOG_DEM_EVENT_BASE + 0x20) +#define DEM_NEGATE_OKTS (SMEM_LOG_DEM_EVENT_BASE + 0x21) +#define DEMMOD_APPS_WAKEUP_INT (SMEM_LOG_DEM_EVENT_BASE + 0x22) +#define DEMMOD_APPS_SWFI (SMEM_LOG_DEM_EVENT_BASE + 0x23) +#define DEM_SEND_BATTERY_INFO (SMEM_LOG_DEM_EVENT_BASE + 0x24) +#define DEM_SMI_CLK_DISABLED (SMEM_LOG_DEM_EVENT_BASE + 0x25) +#define DEM_SMI_CLK_ENABLED (SMEM_LOG_DEM_EVENT_BASE + 0x26) +#define DEMAPPS_SETUP_APPS_SUSPEND (SMEM_LOG_DEM_EVENT_BASE + 0x27) +#define DEM_RPC_EARLY_EXIT (SMEM_LOG_DEM_EVENT_BASE + 0x28) +#define DEMAPPS_WAKEUP_REASON (SMEM_LOG_DEM_EVENT_BASE + 0x29) +#define DEM_INIT (SMEM_LOG_DEM_EVENT_BASE + 0x30) +#endif +#define DEMMOD_UMTS_BASE (SMEM_LOG_DEM_EVENT_BASE + 0x8000) +#define DEMMOD_GL1_GO_TO_SLEEP (DEMMOD_UMTS_BASE + 0x0000) +#define DEMMOD_GL1_SLEEP_START (DEMMOD_UMTS_BASE + 0x0001) +#define DEMMOD_GL1_AFTER_GSM_CLK_ON (DEMMOD_UMTS_BASE + 0x0002) +#define DEMMOD_GL1_BEFORE_RF_ON (DEMMOD_UMTS_BASE + 0x0003) +#define DEMMOD_GL1_AFTER_RF_ON (DEMMOD_UMTS_BASE + 0x0004) +#define DEMMOD_GL1_FRAME_TICK (DEMMOD_UMTS_BASE + 0x0005) +#define DEMMOD_GL1_WCDMA_START (DEMMOD_UMTS_BASE + 0x0006) +#define DEMMOD_GL1_WCDMA_ENDING (DEMMOD_UMTS_BASE + 0x0007) +#define DEMMOD_UMTS_NOT_OKTS (DEMMOD_UMTS_BASE + 0x0008) +#define DEMMOD_UMTS_START_TCXO_SHUTDOWN (DEMMOD_UMTS_BASE + 0x0009) +#define DEMMOD_UMTS_END_TCXO_SHUTDOWN (DEMMOD_UMTS_BASE + 0x000A) +#define DEMMOD_UMTS_START_ARM_HALT (DEMMOD_UMTS_BASE + 0x000B) +#define DEMMOD_UMTS_END_ARM_HALT (DEMMOD_UMTS_BASE + 0x000C) +#define DEMMOD_UMTS_NEXT_WAKEUP_SCLK (DEMMOD_UMTS_BASE + 0x000D) +#define TIME_REMOTE_LOG_EVENT_START (SMEM_LOG_TIMETICK_EVENT_BASE + 0) +#define TIME_REMOTE_LOG_EVENT_GOTO_WAIT (SMEM_LOG_TIMETICK_EVENT_BASE + 1) +#define TIME_REMOTE_LOG_EVENT_GOTO_INIT (SMEM_LOG_TIMETICK_EVENT_BASE + 2) +#define ERR_ERROR_FATAL (SMEM_LOG_ERROR_EVENT_BASE + 1) +#define ERR_ERROR_FATAL_TASK (SMEM_LOG_ERROR_EVENT_BASE + 2) +#define DCVSAPPS_LOG_IDLE (SMEM_LOG_DCVS_EVENT_BASE + 0x0) +#define DCVSAPPS_LOG_ERR (SMEM_LOG_DCVS_EVENT_BASE + 0x1) +#define DCVSAPPS_LOG_CHG (SMEM_LOG_DCVS_EVENT_BASE + 0x2) +#define DCVSAPPS_LOG_REG (SMEM_LOG_DCVS_EVENT_BASE + 0x3) +#define DCVSAPPS_LOG_DEREG (SMEM_LOG_DCVS_EVENT_BASE + 0x4) +#define SMEM_LOG_EVENT_CB (SMEM_LOG_SMEM_EVENT_BASE + 0) +#define SMEM_LOG_EVENT_START (SMEM_LOG_SMEM_EVENT_BASE + 1) +#define SMEM_LOG_EVENT_INIT (SMEM_LOG_SMEM_EVENT_BASE + 2) +#define SMEM_LOG_EVENT_RUNNING (SMEM_LOG_SMEM_EVENT_BASE + 3) +#define SMEM_LOG_EVENT_STOP (SMEM_LOG_SMEM_EVENT_BASE + 4) +#define SMEM_LOG_EVENT_RESTART (SMEM_LOG_SMEM_EVENT_BASE + 5) +#define SMEM_LOG_EVENT_SS (SMEM_LOG_SMEM_EVENT_BASE + 6) +#define SMEM_LOG_EVENT_READ (SMEM_LOG_SMEM_EVENT_BASE + 7) +#define SMEM_LOG_EVENT_WRITE (SMEM_LOG_SMEM_EVENT_BASE + 8) +#define SMEM_LOG_EVENT_SIGS1 (SMEM_LOG_SMEM_EVENT_BASE + 9) +#define SMEM_LOG_EVENT_SIGS2 (SMEM_LOG_SMEM_EVENT_BASE + 10) +#define SMEM_LOG_EVENT_WRITE_DM (SMEM_LOG_SMEM_EVENT_BASE + 11) +#define SMEM_LOG_EVENT_READ_DM (SMEM_LOG_SMEM_EVENT_BASE + 12) +#define SMEM_LOG_EVENT_SKIP_DM (SMEM_LOG_SMEM_EVENT_BASE + 13) +#define SMEM_LOG_EVENT_STOP_DM (SMEM_LOG_SMEM_EVENT_BASE + 14) +#define SMEM_LOG_EVENT_ISR (SMEM_LOG_SMEM_EVENT_BASE + 15) +#define SMEM_LOG_EVENT_TASK (SMEM_LOG_SMEM_EVENT_BASE + 16) +#define SMEM_LOG_EVENT_RS (SMEM_LOG_SMEM_EVENT_BASE + 17) +#define ONCRPC_LOG_EVENT_SMD_WAIT (SMEM_LOG_ONCRPC_EVENT_BASE + 0) +#define ONCRPC_LOG_EVENT_RPC_WAIT (SMEM_LOG_ONCRPC_EVENT_BASE + 1) +#define ONCRPC_LOG_EVENT_RPC_BOTH_WAIT (SMEM_LOG_ONCRPC_EVENT_BASE + 2) +#define ONCRPC_LOG_EVENT_RPC_INIT (SMEM_LOG_ONCRPC_EVENT_BASE + 3) +#define ONCRPC_LOG_EVENT_RUNNING (SMEM_LOG_ONCRPC_EVENT_BASE + 4) +#define ONCRPC_LOG_EVENT_APIS_INITED (SMEM_LOG_ONCRPC_EVENT_BASE + 5) +#define ONCRPC_LOG_EVENT_AMSS_RESET (SMEM_LOG_ONCRPC_EVENT_BASE + 6) +#define ONCRPC_LOG_EVENT_SMD_RESET (SMEM_LOG_ONCRPC_EVENT_BASE + 7) +#define ONCRPC_LOG_EVENT_ONCRPC_RESET (SMEM_LOG_ONCRPC_EVENT_BASE + 8) +#define ONCRPC_LOG_EVENT_CB (SMEM_LOG_ONCRPC_EVENT_BASE + 9) +#define ONCRPC_LOG_EVENT_STD_CALL (SMEM_LOG_ONCRPC_EVENT_BASE + 10) +#define ONCRPC_LOG_EVENT_STD_REPLY (SMEM_LOG_ONCRPC_EVENT_BASE + 11) +#define ONCRPC_LOG_EVENT_STD_CALL_ASYNC (SMEM_LOG_ONCRPC_EVENT_BASE + 12) +#define NO_SLEEP_OLD (SMEM_LOG_SLEEP_EVENT_BASE + 0x1) +#define INSUF_TIME (SMEM_LOG_SLEEP_EVENT_BASE + 0x2) +#define MOD_UART_CLOCK (SMEM_LOG_SLEEP_EVENT_BASE + 0x3) +#define SLEEP_INFO (SMEM_LOG_SLEEP_EVENT_BASE + 0x4) +#define MOD_TCXO_END (SMEM_LOG_SLEEP_EVENT_BASE + 0x5) +#define MOD_ENTER_TCXO (SMEM_LOG_SLEEP_EVENT_BASE + 0x6) +#define NO_SLEEP_NEW (SMEM_LOG_SLEEP_EVENT_BASE + 0x7) +#define RPC_ROUTER_LOG_EVENT_UNKNOWN (SMEM_LOG_RPC_ROUTER_EVENT_BASE) +#define RPC_ROUTER_LOG_EVENT_MSG_READ (SMEM_LOG_RPC_ROUTER_EVENT_BASE + 1) +#define RPC_ROUTER_LOG_EVENT_MSG_WRITTEN (SMEM_LOG_RPC_ROUTER_EVENT_BASE + 2) +#define RPC_ROUTER_LOG_EVENT_MSG_CFM_REQ (SMEM_LOG_RPC_ROUTER_EVENT_BASE + 3) +#define RPC_ROUTER_LOG_EVENT_MSG_CFM_SNT (SMEM_LOG_RPC_ROUTER_EVENT_BASE + 4) +#define RPC_ROUTER_LOG_EVENT_MID_READ (SMEM_LOG_RPC_ROUTER_EVENT_BASE + 5) +#define RPC_ROUTER_LOG_EVENT_MID_WRITTEN (SMEM_LOG_RPC_ROUTER_EVENT_BASE + 6) +#define RPC_ROUTER_LOG_EVENT_MID_CFM_REQ (SMEM_LOG_RPC_ROUTER_EVENT_BASE + 7) + +void smem_log_event(uint32_t id, uint32_t data1, uint32_t data2, + uint32_t data3); +void smem_log_event6(uint32_t id, uint32_t data1, uint32_t data2, + uint32_t data3, uint32_t data4, uint32_t data5, + uint32_t data6); +void smem_log_event_to_static(uint32_t id, uint32_t data1, uint32_t data2, + uint32_t data3); +void smem_log_event6_to_static(uint32_t id, uint32_t data1, uint32_t data2, + uint32_t data3, uint32_t data4, uint32_t data5, + uint32_t data6); + diff --git a/arch/arm/mach-msm/include/mach/usbdiag.h b/arch/arm/mach-msm/include/mach/usbdiag.h new file mode 100644 index 000000000000..a2b89650f4c9 --- /dev/null +++ b/arch/arm/mach-msm/include/mach/usbdiag.h @@ -0,0 +1,44 @@ +/* include/asm-arm/arch-msm/usbdiag.h + * + * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * All source code in this file is licensed under the following license except + * where indicated. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License 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. + * You should have received a copy of the GNU General Public License + * along with this program; if not, you can find it at http://www.fsf.org + */ + +#ifndef _DRIVERS_USB_DIAG_H_ +#define _DRIVERS_USB_DIAG_H_ +#define ENOREQ -1 +struct diag_operations { + + int (*diag_connect)(void); + int (*diag_disconnect)(void); + int (*diag_char_write_complete)(unsigned char * , int, int); + int (*diag_char_read_complete)(unsigned char *, int , int); +}; + +struct diag_request { + char *buf; + int length; +}; +int diag_open(int); +void diag_close(void); +int diag_read(unsigned char *, int); +int diag_write(unsigned char *, int); + +int diag_usb_register(struct diag_operations *); +int diag_usb_unregister(void); +int diag_read_from_cb(unsigned char * , int); +#endif diff --git a/arch/arm/mach-msm/include/mach/vmalloc.h b/arch/arm/mach-msm/include/mach/vmalloc.h index 05f81fd8623c..b70059d432ac 100644 --- a/arch/arm/mach-msm/include/mach/vmalloc.h +++ b/arch/arm/mach-msm/include/mach/vmalloc.h @@ -16,7 +16,7 @@ #ifndef __ASM_ARCH_MSM_VMALLOC_H #define __ASM_ARCH_MSM_VMALLOC_H -#define VMALLOC_END (PAGE_OFFSET + 0x10000000) +#define VMALLOC_END (PAGE_OFFSET + 0x20000000) #endif diff --git a/arch/arm/mach-msm/include/mach/vreg.h b/arch/arm/mach-msm/include/mach/vreg.h index 9f9e25cb718e..6626e7864e28 100644 --- a/arch/arm/mach-msm/include/mach/vreg.h +++ b/arch/arm/mach-msm/include/mach/vreg.h @@ -23,7 +23,7 @@ struct vreg *vreg_get(struct device *dev, const char *id); void vreg_put(struct vreg *vreg); int vreg_enable(struct vreg *vreg); -void vreg_disable(struct vreg *vreg); +int vreg_disable(struct vreg *vreg); int vreg_set_level(struct vreg *vreg, unsigned mv); #endif diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c index 59d0ff42600f..c66d50196064 100644 --- a/arch/arm/mach-msm/io.c +++ b/arch/arm/mach-msm/io.c @@ -1,8 +1,9 @@ /* arch/arm/mach-msm/io.c * - * MSM7K io support + * MSM7K, QSD io support * * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. * Author: Brian Swetland * * This software is licensed under the terms of the GNU General Public @@ -35,6 +36,11 @@ .type = MT_DEVICE_NONSHARED, \ } +/* msm_shared_ram_phys default value of 0x00100000 is the most common value + * and should work as-is for any target without stacked memory. + */ +int msm_shared_ram_phys = 0x00100000; + static struct map_desc msm_io_desc[] __initdata = { MSM_DEVICE(VIC), MSM_DEVICE(CSR), @@ -45,10 +51,61 @@ static struct map_desc msm_io_desc[] __initdata = { MSM_DEVICE(CLK_CTL), #ifdef CONFIG_MSM_DEBUG_UART MSM_DEVICE(DEBUG_UART), +#endif +#ifdef CONFIG_CACHE_L2X0 + { + .virtual = (unsigned long) MSM_L2CC_BASE, + .pfn = __phys_to_pfn(MSM_L2CC_PHYS), + .length = MSM_L2CC_SIZE, + .type = MT_DEVICE, + }, +#endif + { + .virtual = (unsigned long) MSM_SHARED_RAM_BASE, + .length = MSM_SHARED_RAM_SIZE, + .type = MT_DEVICE, + }, +}; + +static struct map_desc qsd8x50_io_desc[] __initdata = { + MSM_DEVICE(VIC), + MSM_DEVICE(CSR), + MSM_DEVICE(GPT), + MSM_DEVICE(DMOV), + MSM_DEVICE(GPIO1), + MSM_DEVICE(GPIO2), + MSM_DEVICE(CLK_CTL), + MSM_DEVICE(SIRC), + MSM_DEVICE(SCPLL), + MSM_DEVICE(AD5), + MSM_DEVICE(MDC), +#ifdef CONFIG_MSM_DEBUG_UART + MSM_DEVICE(DEBUG_UART), +#endif + { + .virtual = (unsigned long) MSM_SHARED_RAM_BASE, + .length = MSM_SHARED_RAM_SIZE, + .type = MT_DEVICE, + }, +}; + +static struct map_desc comet_io_desc[] __initdata = { + MSM_DEVICE(VIC), + MSM_DEVICE(CSR), + MSM_DEVICE(GPT), + MSM_DEVICE(DMOV), + MSM_DEVICE(GPIO1), + MSM_DEVICE(GPIO2), + MSM_DEVICE(CLK_CTL), + MSM_DEVICE(SIRC), + MSM_DEVICE(SCPLL), + MSM_DEVICE(AD5), + MSM_DEVICE(MDC), +#ifdef CONFIG_MSM_DEBUG_UART + MSM_DEVICE(DEBUG_UART), #endif { .virtual = (unsigned long) MSM_SHARED_RAM_BASE, - .pfn = __phys_to_pfn(MSM_SHARED_RAM_PHYS), .length = MSM_SHARED_RAM_SIZE, .type = MT_DEVICE, }, @@ -56,15 +113,52 @@ static struct map_desc msm_io_desc[] __initdata = { void __init msm_map_common_io(void) { + int i; + /* Make sure the peripheral register window is closed, since * we will use PTE flags (TEX[1]=1,B=0,C=1) to determine which * pages are peripheral interface or not. */ asm("mcr p15, 0, %0, c15, c2, 4" : : "r" (0)); + BUG_ON(!ARRAY_SIZE(msm_io_desc)); + for (i = 0; i < ARRAY_SIZE(msm_io_desc); i++) + if (msm_io_desc[i].virtual == + (unsigned long)MSM_SHARED_RAM_BASE) + msm_io_desc[i].pfn = + __phys_to_pfn(msm_shared_ram_phys); + iotable_init(msm_io_desc, ARRAY_SIZE(msm_io_desc)); } +void __init msm_map_qsd8x50_io(void) +{ + int i; + + BUG_ON(!ARRAY_SIZE(qsd8x50_io_desc)); + for (i = 0; i < ARRAY_SIZE(qsd8x50_io_desc); i++) + if (qsd8x50_io_desc[i].virtual == + (unsigned long)MSM_SHARED_RAM_BASE) + qsd8x50_io_desc[i].pfn = + __phys_to_pfn(msm_shared_ram_phys); + + iotable_init(qsd8x50_io_desc, ARRAY_SIZE(qsd8x50_io_desc)); +} + +void __init msm_map_comet_io(void) +{ + int i; + + BUG_ON(!ARRAY_SIZE(comet_io_desc)); + for (i = 0; i < ARRAY_SIZE(comet_io_desc); i++) + if (comet_io_desc[i].virtual == + (unsigned long)MSM_SHARED_RAM_BASE) + comet_io_desc[i].pfn = + __phys_to_pfn(msm_shared_ram_phys); + + iotable_init(comet_io_desc, ARRAY_SIZE(comet_io_desc)); +} + void __iomem * __msm_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype) { diff --git a/arch/arm/mach-msm/irq.c b/arch/arm/mach-msm/irq.c index cb4bda509879..399147e8fc6d 100644 --- a/arch/arm/mach-msm/irq.c +++ b/arch/arm/mach-msm/irq.c @@ -1,6 +1,7 @@ /* linux/arch/arm/mach-msm/irq.c * * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2009, Code Aurora Forum. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -56,9 +57,17 @@ module_param_named(debug_mask, msm_irq_debug_mask, int, S_IRUGO | S_IWUSR | S_IW #define VIC_INT_POLARITY0 VIC_REG(0x0050) /* 1: NEG, 0: POS */ #define VIC_INT_POLARITY1 VIC_REG(0x0054) /* 1: NEG, 0: POS */ #define VIC_NO_PEND_VAL VIC_REG(0x0060) + +#if defined(CONFIG_ARCH_QSD) +#define VIC_NO_PEND_VAL_FIQ VIC_REG(0x0064) +#define VIC_INT_MASTEREN VIC_REG(0x0068) /* 1: IRQ, 2: FIQ */ +#define VIC_CONFIG VIC_REG(0x006C) /* 1: USE SC VIC */ +#else #define VIC_INT_MASTEREN VIC_REG(0x0064) /* 1: IRQ, 2: FIQ */ #define VIC_PROTECTION VIC_REG(0x006C) /* 1: ENABLE */ #define VIC_CONFIG VIC_REG(0x0068) /* 1: USE ARM1136 VIC */ +#endif + #define VIC_IRQ_STATUS0 VIC_REG(0x0080) #define VIC_IRQ_STATUS1 VIC_REG(0x0084) #define VIC_FIQ_STATUS0 VIC_REG(0x0090) @@ -72,9 +81,22 @@ module_param_named(debug_mask, msm_irq_debug_mask, int, S_IRUGO | S_IWUSR | S_IW #define VIC_IRQ_VEC_RD VIC_REG(0x00D0) /* pending int # */ #define VIC_IRQ_VEC_PEND_RD VIC_REG(0x00D4) /* pending vector addr */ #define VIC_IRQ_VEC_WR VIC_REG(0x00D8) + +#if defined(CONFIG_ARCH_QSD) +#define VIC_FIQ_VEC_RD VIC_REG(0x00DC) +#define VIC_FIQ_VEC_PEND_RD VIC_REG(0x00E0) +#define VIC_FIQ_VEC_WR VIC_REG(0x00E4) +#define VIC_IRQ_IN_SERVICE VIC_REG(0x00E8) +#define VIC_IRQ_IN_STACK VIC_REG(0x00EC) +#define VIC_FIQ_IN_SERVICE VIC_REG(0x00F0) +#define VIC_FIQ_IN_STACK VIC_REG(0x00F4) +#define VIC_TEST_BUS_SEL VIC_REG(0x00F8) +#define VIC_IRQ_CTRL_CONFIG VIC_REG(0x00FC) +#else #define VIC_IRQ_IN_SERVICE VIC_REG(0x00E0) #define VIC_IRQ_IN_STACK VIC_REG(0x00E4) #define VIC_TEST_BUS_SEL VIC_REG(0x00E8) +#endif #define VIC_VECTPRIORITY(n) VIC_REG(0x0200+((n) * 4)) #define VIC_VECTADDR(n) VIC_REG(0x0400+((n) * 4)) @@ -89,7 +111,7 @@ static struct { static uint32_t msm_irq_idle_disable[2]; #define SMSM_FAKE_IRQ (0xff) -static uint8_t msm_irq_to_smsm[NR_MSM_IRQS] = { +static uint8_t msm_irq_to_smsm[NR_IRQS] = { [INT_MDDI_EXT] = 1, [INT_MDDI_PRI] = 2, [INT_MDDI_CLIENT] = 3, @@ -138,6 +160,11 @@ static uint8_t msm_irq_to_smsm[NR_MSM_IRQS] = { [INT_A9_M2A_5] = SMSM_FAKE_IRQ, [INT_GP_TIMER_EXP] = SMSM_FAKE_IRQ, [INT_DEBUG_TIMER_EXP] = SMSM_FAKE_IRQ, + [INT_ADSP_A11] = SMSM_FAKE_IRQ, +#if defined(CONFIG_ARCH_QSD) + [INT_SIRC_0] = SMSM_FAKE_IRQ, + [INT_SIRC_1] = SMSM_FAKE_IRQ, +#endif }; static void msm_irq_ack(unsigned int irq) @@ -252,19 +279,29 @@ int msm_irq_idle_sleep_allowed(void) return !(msm_irq_idle_disable[0] || msm_irq_idle_disable[1]); } -/* If arm9_wake is set: pass control to the other core. - * If from_idle is not set: disable non-wakeup interrupts. +/* + * Prepare interrupt subsystem for entering sleep -- phase 1. + * If arm9_wake is true, return currently enabled interrupts in *irq_mask. */ -void msm_irq_enter_sleep1(bool arm9_wake, int from_idle) +void msm_irq_enter_sleep1(bool arm9_wake, int from_idle, uint32_t *irq_mask) { - struct smsm_interrupt_info int_info; if (arm9_wake) { - int_info.aArm_en_mask = msm_irq_smsm_wake_enable[!from_idle]; - int_info.aArm_interrupts_pending = 0; - smsm_set_interrupt_info(&int_info); + *irq_mask = msm_irq_smsm_wake_enable[!from_idle]; + if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP) + printk(KERN_INFO + "%s irq_mask %x\n", __func__, *irq_mask); } } +/* + * Prepare interrupt subsystem for entering sleep -- phase 2. + * Detect any pending interrupts and configure interrupt hardware. + * + * Return value: + * -EAGAIN: there are pending interrupt(s); interrupt configuration + * is not changed. + * 0: success + */ int msm_irq_enter_sleep2(bool arm9_wake, int from_idle) { int limit = 10; @@ -277,21 +314,23 @@ int msm_irq_enter_sleep2(bool arm9_wake, int from_idle) WARN_ON_ONCE(!arm9_wake && !from_idle); if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP) - printk(KERN_INFO "msm_irq_enter_sleep change irq, pend %x %x\n", - readl(VIC_IRQ_STATUS0), readl(VIC_IRQ_STATUS1)); + printk(KERN_INFO "%s change irq, pend %x %x\n", __func__, + readl(VIC_IRQ_STATUS0), readl(VIC_IRQ_STATUS1)); + pending0 = readl(VIC_IRQ_STATUS0); pending1 = readl(VIC_IRQ_STATUS1); pending0 &= msm_irq_shadow_reg[0].int_en[!from_idle]; /* Clear INT_A9_M2A_5 since requesting sleep triggers it */ pending0 &= ~(1U << INT_A9_M2A_5); pending1 &= msm_irq_shadow_reg[1].int_en[!from_idle]; + if (pending0 || pending1) { if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP_ABORT) - printk(KERN_INFO "msm_irq_enter_sleep2 abort %x %x\n", - pending0, pending1); + printk(KERN_INFO "%s abort %x %x\n", __func__, + pending0, pending1); return -EAGAIN; } - + writel(0, VIC_INT_EN0); writel(0, VIC_INT_EN1); @@ -302,8 +341,8 @@ int msm_irq_enter_sleep2(bool arm9_wake, int from_idle) break; pend_irq = readl(VIC_IRQ_VEC_PEND_RD); if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP_INT) - printk(KERN_INFO "msm_irq_enter_sleep cleared " - "int %d (%d)\n", irq, pend_irq); + printk(KERN_INFO "%s cleared int %d (%d)\n", + __func__, irq, pend_irq); } if (arm9_wake) { @@ -313,95 +352,104 @@ int msm_irq_enter_sleep2(bool arm9_wake, int from_idle) writel(msm_irq_shadow_reg[0].int_en[1], VIC_INT_ENSET0); writel(msm_irq_shadow_reg[1].int_en[1], VIC_INT_ENSET1); } + return 0; } -void msm_irq_exit_sleep1(void) +/* + * Restore interrupt subsystem from sleep -- phase 1. + * Configure interrupt hardware. + */ +void msm_irq_exit_sleep1(uint32_t irq_mask, uint32_t wakeup_reason, + uint32_t pending_irqs) { - struct smsm_interrupt_info *int_info; int i; msm_irq_ack(INT_A9_M2A_6); + for (i = 0; i < 2; i++) { - writel(msm_irq_shadow_reg[i].int_type, VIC_INT_TYPE0 + i * 4); - writel(msm_irq_shadow_reg[i].int_polarity, VIC_INT_POLARITY0 + i * 4); - writel(msm_irq_shadow_reg[i].int_en[0], VIC_INT_EN0 + i * 4); - writel(msm_irq_shadow_reg[i].int_select, VIC_INT_SELECT0 + i * 4); + writel(msm_irq_shadow_reg[i].int_type, + VIC_INT_TYPE0 + i * 4); + writel(msm_irq_shadow_reg[i].int_polarity, + VIC_INT_POLARITY0 + i * 4); + writel(msm_irq_shadow_reg[i].int_en[0], + VIC_INT_EN0 + i * 4); + writel(msm_irq_shadow_reg[i].int_select, + VIC_INT_SELECT0 + i * 4); } + writel(3, VIC_INT_MASTEREN); - int_info = smem_alloc(SMEM_SMSM_INT_INFO, sizeof(*int_info)); - if (int_info == NULL) { - printk(KERN_ERR "msm_irq_exit_sleep \n"); - return; - } + if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP) - printk(KERN_INFO "msm_irq_exit_sleep1 %x %x %x now %x %x\n", - int_info->aArm_en_mask, - int_info->aArm_interrupts_pending, - int_info->aArm_wakeup_reason, - readl(VIC_IRQ_STATUS0), readl(VIC_IRQ_STATUS1)); + printk(KERN_INFO "%s %x %x %x now %x %x\n", + __func__, irq_mask, pending_irqs, wakeup_reason, + readl(VIC_IRQ_STATUS0), readl(VIC_IRQ_STATUS1)); } -void msm_irq_exit_sleep2(void) +/* + * Restore interrupt subsystem from sleep -- phase 2. + * Poke the specified pending interrupts into interrupt hardware. + */ +void msm_irq_exit_sleep2(uint32_t irq_mask, uint32_t wakeup_reason, + uint32_t pending) { int i; - uint32_t pending; - struct smsm_interrupt_info *int_info; - int_info = smem_alloc(SMEM_SMSM_INT_INFO, sizeof(*int_info)); - if (int_info == NULL) { - printk(KERN_ERR "msm_irq_exit_sleep \n"); - return; - } + if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP) - printk(KERN_INFO "msm_irq_exit_sleep2 %x %x %x now %x %x\n", - int_info->aArm_en_mask, - int_info->aArm_interrupts_pending, - int_info->aArm_wakeup_reason, - readl(VIC_IRQ_STATUS0), readl(VIC_IRQ_STATUS1)); - pending = int_info->aArm_interrupts_pending; + printk(KERN_INFO "%s %x %x %x now %x %x\n", + __func__, irq_mask, pending, wakeup_reason, + readl(VIC_IRQ_STATUS0), readl(VIC_IRQ_STATUS1)); + for (i = 0; pending && i < ARRAY_SIZE(msm_irq_to_smsm); i++) { unsigned reg_offset = (i & 32) ? 4 : 0; uint32_t reg_mask = 1UL << (i & 31); int smsm_irq = msm_irq_to_smsm[i]; uint32_t smsm_mask; + if (smsm_irq == 0) continue; + smsm_mask = 1U << (smsm_irq - 1); if (!(pending & smsm_mask)) continue; + pending &= ~smsm_mask; if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP_INT) - printk(KERN_INFO "msm_irq_exit_sleep2: irq %d " - "still pending %x now %x %x\n", i, pending, - readl(VIC_IRQ_STATUS0), readl(VIC_IRQ_STATUS1)); + printk(KERN_INFO + "%s: irq %d still pending %x now %x %x\n", + __func__, i, pending, + readl(VIC_IRQ_STATUS0), + readl(VIC_IRQ_STATUS1)); #if 0 /* debug intetrrupt trigger */ if (readl(VIC_IRQ_STATUS0 + reg_offset) & reg_mask) writel(reg_mask, VIC_INT_CLEAR0 + reg_offset); #endif if (readl(VIC_IRQ_STATUS0 + reg_offset) & reg_mask) continue; + writel(reg_mask, VIC_SOFTINT0 + reg_offset); + if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP_INT_TRIGGER) - printk(KERN_INFO "msm_irq_exit_sleep2: irq %d need " - "trigger, now %x %x\n", i, - readl(VIC_IRQ_STATUS0), readl(VIC_IRQ_STATUS1)); + printk(KERN_INFO + "%s: irq %d need trigger, now %x %x\n", + __func__, i, + readl(VIC_IRQ_STATUS0), + readl(VIC_IRQ_STATUS1)); } } -void msm_irq_exit_sleep3(void) +/* + * Restore interrupt subsystem from sleep -- phase 3. + * Print debug information. + */ +void msm_irq_exit_sleep3(uint32_t irq_mask, uint32_t wakeup_reason, + uint32_t pending_irqs) { - struct smsm_interrupt_info *int_info; - int_info = smem_alloc(SMEM_SMSM_INT_INFO, sizeof(*int_info)); - if (int_info == NULL) { - printk(KERN_ERR "msm_irq_exit_sleep \n"); - return; - } if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP) - printk(KERN_INFO "msm_irq_exit_sleep3 %x %x %x now %x %x " - "state %x\n", int_info->aArm_en_mask, - int_info->aArm_interrupts_pending, - int_info->aArm_wakeup_reason, readl(VIC_IRQ_STATUS0), - readl(VIC_IRQ_STATUS1), smsm_get_state()); + printk(KERN_INFO "%s %x %x %x now %x %x state %x\n", + __func__, irq_mask, pending_irqs, wakeup_reason, + readl(VIC_IRQ_STATUS0), readl(VIC_IRQ_STATUS1), + smsm_get_state(SMSM_MODEM_STATE)); } static struct irq_chip msm_irq_chip = { diff --git a/arch/arm/mach-msm/irq.h b/arch/arm/mach-msm/irq.h new file mode 100644 index 000000000000..40028485cc7c --- /dev/null +++ b/arch/arm/mach-msm/irq.h @@ -0,0 +1,72 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef _ARCH_ARM_MACH_MSM_IRQ_H_ +#define _ARCH_ARM_MACH_MSM_IRQ_H_ + +int msm_irq_idle_sleep_allowed(void); +int msm_irq_pending(void); +void msm_irq_enter_sleep1(bool arm9_wake, int from_idle, uint32_t *irq_mask); +int msm_irq_enter_sleep2(bool arm9_wake, int from_idle); +void msm_irq_exit_sleep1 + (uint32_t irq_mask, uint32_t wakeup_reason, uint32_t pending_irqs); +void msm_irq_exit_sleep2 + (uint32_t irq_mask, uint32_t wakeup_reason, uint32_t pending); +void msm_irq_exit_sleep3 + (uint32_t irq_mask, uint32_t wakeup_reason, uint32_t pending_irqs); + +#endif diff --git a/arch/arm/mach-msm/keypad-surf-ffa.c b/arch/arm/mach-msm/keypad-surf-ffa.c new file mode 100644 index 000000000000..1ea72af71a47 --- /dev/null +++ b/arch/arm/mach-msm/keypad-surf-ffa.c @@ -0,0 +1,316 @@ +/* + * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * Author: Brian Swetland + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 + +/* don't turn this on without updating the ffa support */ +#define SCAN_FUNCTION_KEYS 0 + +/* FFA: + 36: KEYSENSE_N(0) + 37: KEYSENSE_N(1) + 38: KEYSENSE_N(2) + 39: KEYSENSE_N(3) + 40: KEYSENSE_N(4) + + 31: KYPD_17 + 32: KYPD_15 + 33: KYPD_13 + 34: KYPD_11 + 35: KYPD_9 + 41: KYPD_MEMO +*/ + +static unsigned int keypad_row_gpios[] = { + 31, 32, 33, 34, 35, 41 +#if SCAN_FUNCTION_KEYS + , 42 +#endif +}; + +static unsigned int keypad_col_gpios[] = { 36, 37, 38, 39, 40 }; + +static unsigned int keypad_row_gpios_8k_ffa[] = {31, 32, 33, 34, 35, 36}; +static unsigned int keypad_col_gpios_8k_ffa[] = {38, 39, 40, 41, 42}; + +#define KEYMAP_INDEX(row, col) ((row)*ARRAY_SIZE(keypad_col_gpios) + (col)) +#define FFA_8K_KEYMAP_INDEX(row, col) ((row)* \ + ARRAY_SIZE(keypad_col_gpios_8k_ffa) + (col)) + +static const unsigned short keypad_keymap_surf[ARRAY_SIZE(keypad_col_gpios) * + ARRAY_SIZE(keypad_row_gpios)] = { + [KEYMAP_INDEX(0, 0)] = KEY_5, + [KEYMAP_INDEX(0, 1)] = KEY_9, + [KEYMAP_INDEX(0, 2)] = 229, /* SOFT1 */ + [KEYMAP_INDEX(0, 3)] = KEY_6, + [KEYMAP_INDEX(0, 4)] = KEY_LEFT, + + [KEYMAP_INDEX(1, 0)] = KEY_0, + [KEYMAP_INDEX(1, 1)] = KEY_RIGHT, + [KEYMAP_INDEX(1, 2)] = KEY_1, + [KEYMAP_INDEX(1, 3)] = 228, /* KEY_SHARP */ + [KEYMAP_INDEX(1, 4)] = KEY_SEND, + + [KEYMAP_INDEX(2, 0)] = KEY_VOLUMEUP, + [KEYMAP_INDEX(2, 1)] = KEY_HOME, /* FA */ + [KEYMAP_INDEX(2, 2)] = KEY_F8, /* QCHT */ + [KEYMAP_INDEX(2, 3)] = KEY_F6, /* R+ */ + [KEYMAP_INDEX(2, 4)] = KEY_F7, /* R- */ + + [KEYMAP_INDEX(3, 0)] = KEY_UP, + [KEYMAP_INDEX(3, 1)] = KEY_CLEAR, + [KEYMAP_INDEX(3, 2)] = KEY_4, + [KEYMAP_INDEX(3, 3)] = KEY_MUTE, /* SPKR */ + [KEYMAP_INDEX(3, 4)] = KEY_2, + + [KEYMAP_INDEX(4, 0)] = 230, /* SOFT2 */ + [KEYMAP_INDEX(4, 1)] = 232, /* KEY_CENTER */ + [KEYMAP_INDEX(4, 2)] = KEY_DOWN, + [KEYMAP_INDEX(4, 3)] = KEY_BACK, /* FB */ + [KEYMAP_INDEX(4, 4)] = KEY_8, + + [KEYMAP_INDEX(5, 0)] = KEY_VOLUMEDOWN, + [KEYMAP_INDEX(5, 1)] = 227, /* KEY_STAR */ + [KEYMAP_INDEX(5, 2)] = KEY_MAIL, /* MESG */ + [KEYMAP_INDEX(5, 3)] = KEY_3, + [KEYMAP_INDEX(5, 4)] = KEY_7, + +#if SCAN_FUNCTION_KEYS + [KEYMAP_INDEX(6, 0)] = KEY_F5, + [KEYMAP_INDEX(6, 1)] = KEY_F4, + [KEYMAP_INDEX(6, 2)] = KEY_F3, + [KEYMAP_INDEX(6, 3)] = KEY_F2, + [KEYMAP_INDEX(6, 4)] = KEY_F1 +#endif +}; + +static const unsigned short keypad_keymap_ffa[ARRAY_SIZE(keypad_col_gpios) * + ARRAY_SIZE(keypad_row_gpios)] = { + /*[KEYMAP_INDEX(0, 0)] = ,*/ + /*[KEYMAP_INDEX(0, 1)] = ,*/ + [KEYMAP_INDEX(0, 2)] = KEY_1, + [KEYMAP_INDEX(0, 3)] = KEY_SEND, + [KEYMAP_INDEX(0, 4)] = KEY_LEFT, + + [KEYMAP_INDEX(1, 0)] = KEY_3, + [KEYMAP_INDEX(1, 1)] = KEY_RIGHT, + [KEYMAP_INDEX(1, 2)] = KEY_VOLUMEUP, + /*[KEYMAP_INDEX(1, 3)] = ,*/ + [KEYMAP_INDEX(1, 4)] = KEY_6, + + [KEYMAP_INDEX(2, 0)] = KEY_HOME, /* A */ + [KEYMAP_INDEX(2, 1)] = KEY_BACK, /* B */ + [KEYMAP_INDEX(2, 2)] = KEY_0, + [KEYMAP_INDEX(2, 3)] = 228, /* KEY_SHARP */ + [KEYMAP_INDEX(2, 4)] = KEY_9, + + [KEYMAP_INDEX(3, 0)] = KEY_UP, + [KEYMAP_INDEX(3, 1)] = 232, /* KEY_CENTER */ /* i */ + [KEYMAP_INDEX(3, 2)] = KEY_4, + /*[KEYMAP_INDEX(3, 3)] = ,*/ + [KEYMAP_INDEX(3, 4)] = KEY_2, + + [KEYMAP_INDEX(4, 0)] = KEY_VOLUMEDOWN, + [KEYMAP_INDEX(4, 1)] = KEY_SOUND, + [KEYMAP_INDEX(4, 2)] = KEY_DOWN, + [KEYMAP_INDEX(4, 3)] = KEY_8, + [KEYMAP_INDEX(4, 4)] = KEY_5, + + /*[KEYMAP_INDEX(5, 0)] = ,*/ + [KEYMAP_INDEX(5, 1)] = 227, /* KEY_STAR */ + [KEYMAP_INDEX(5, 2)] = 230, /*SOFT2*/ /* 2 */ + [KEYMAP_INDEX(5, 3)] = KEY_MENU, /* 1 */ + [KEYMAP_INDEX(5, 4)] = KEY_7, +}; + +#define QSD8x50_FFA_KEYMAP_SIZE (ARRAY_SIZE(keypad_col_gpios_8k_ffa) * \ + ARRAY_SIZE(keypad_row_gpios_8k_ffa)) + +static const unsigned short keypad_keymap_8k_ffa[QSD8x50_FFA_KEYMAP_SIZE] = { + + [FFA_8K_KEYMAP_INDEX(0, 0)] = KEY_VOLUMEDOWN, + /*[KEYMAP_INDEX(0, 1)] = ,*/ + [FFA_8K_KEYMAP_INDEX(0, 2)] = KEY_DOWN, + [FFA_8K_KEYMAP_INDEX(0, 3)] = KEY_8, + [FFA_8K_KEYMAP_INDEX(0, 4)] = KEY_5, + + [FFA_8K_KEYMAP_INDEX(1, 0)] = KEY_UP, + [FFA_8K_KEYMAP_INDEX(1, 1)] = KEY_CLEAR, + [FFA_8K_KEYMAP_INDEX(1, 2)] = KEY_4, + /*[KEYMAP_INDEX(1, 3)] = ,*/ + [FFA_8K_KEYMAP_INDEX(1, 4)] = KEY_2, + + [FFA_8K_KEYMAP_INDEX(2, 0)] = KEY_HOME, /* A */ + [FFA_8K_KEYMAP_INDEX(2, 1)] = KEY_BACK, /* B */ + [FFA_8K_KEYMAP_INDEX(2, 2)] = KEY_0, + [FFA_8K_KEYMAP_INDEX(2, 3)] = 228, /* KEY_SHARP */ + [FFA_8K_KEYMAP_INDEX(2, 4)] = KEY_9, + + [FFA_8K_KEYMAP_INDEX(3, 0)] = KEY_3, + [FFA_8K_KEYMAP_INDEX(3, 1)] = KEY_RIGHT, + [FFA_8K_KEYMAP_INDEX(3, 2)] = KEY_VOLUMEUP, + /*[KEYMAP_INDEX(3, 3)] = ,*/ + [FFA_8K_KEYMAP_INDEX(3, 4)] = KEY_6, + + [FFA_8K_KEYMAP_INDEX(4, 0)] = 232, /* OK */ + [FFA_8K_KEYMAP_INDEX(4, 1)] = KEY_SOUND, + [FFA_8K_KEYMAP_INDEX(4, 2)] = KEY_1, + [FFA_8K_KEYMAP_INDEX(4, 3)] = KEY_SEND, + [FFA_8K_KEYMAP_INDEX(4, 4)] = KEY_LEFT, + + /*[KEYMAP_INDEX(5, 0)] = ,*/ + [FFA_8K_KEYMAP_INDEX(5, 1)] = 227, /* KEY_STAR */ + [FFA_8K_KEYMAP_INDEX(5, 2)] = 230, /*SOFT2*/ /* 2 */ + [FFA_8K_KEYMAP_INDEX(5, 3)] = KEY_MENU, /* 1 */ + [FFA_8K_KEYMAP_INDEX(5, 4)] = KEY_7, +}; + +static const unsigned short keypad_virtual_keys[] = { + KEY_END, + KEY_POWER +}; + +static int keypad_gpio_event_matrix_func(struct input_dev *input_dev, + struct gpio_event_info *info, + void **data, int func); + +/* SURF keypad platform device information */ +static struct gpio_event_matrix_info surf_keypad_matrix_info = { + .info.func = keypad_gpio_event_matrix_func, + .keymap = keypad_keymap_surf, + .output_gpios = keypad_row_gpios, + .input_gpios = keypad_col_gpios, + .noutputs = ARRAY_SIZE(keypad_row_gpios), + .ninputs = ARRAY_SIZE(keypad_col_gpios), + .settle_time.tv.nsec = 0, + .poll_time.tv.nsec = 20 * NSEC_PER_MSEC, + .flags = GPIOKPF_LEVEL_TRIGGERED_IRQ | GPIOKPF_DRIVE_INACTIVE | + GPIOKPF_PRINT_UNMAPPED_KEYS +}; + +static struct gpio_event_info *surf_keypad_info[] = { + &surf_keypad_matrix_info.info +}; + +static struct gpio_event_platform_data surf_keypad_data = { + .name = "surf_keypad", + .info = surf_keypad_info, + .info_count = ARRAY_SIZE(surf_keypad_info) +}; + +struct platform_device keypad_device_surf = { + .name = GPIO_EVENT_DEV_NAME, + .id = -1, + .dev = { + .platform_data = &surf_keypad_data, + }, +}; + +/* 8k FFA keypad platform device information */ +static struct gpio_event_matrix_info keypad_matrix_info_8k_ffa = { + .info.func = keypad_gpio_event_matrix_func, + .keymap = keypad_keymap_8k_ffa, + .output_gpios = keypad_row_gpios_8k_ffa, + .input_gpios = keypad_col_gpios_8k_ffa, + .noutputs = ARRAY_SIZE(keypad_row_gpios_8k_ffa), + .ninputs = ARRAY_SIZE(keypad_col_gpios_8k_ffa), + .settle_time.tv.nsec = 0, + .poll_time.tv.nsec = 20 * NSEC_PER_MSEC, + .flags = GPIOKPF_LEVEL_TRIGGERED_IRQ | GPIOKPF_DRIVE_INACTIVE | + GPIOKPF_PRINT_UNMAPPED_KEYS +}; + +static struct gpio_event_info *keypad_info_8k_ffa[] = { + &keypad_matrix_info_8k_ffa.info +}; + +static struct gpio_event_platform_data keypad_data_8k_ffa = { + .name = "8k_ffa_keypad", + .info = keypad_info_8k_ffa, + .info_count = ARRAY_SIZE(keypad_info_8k_ffa) +}; + +struct platform_device keypad_device_8k_ffa = { + .name = GPIO_EVENT_DEV_NAME, + .id = -1, + .dev = { + .platform_data = &keypad_data_8k_ffa, + }, +}; + +/* 7k FFA keypad platform device information */ +static struct gpio_event_matrix_info keypad_matrix_info_7k_ffa = { + .info.func = keypad_gpio_event_matrix_func, + .keymap = keypad_keymap_ffa, + .output_gpios = keypad_row_gpios, + .input_gpios = keypad_col_gpios, + .noutputs = ARRAY_SIZE(keypad_row_gpios), + .ninputs = ARRAY_SIZE(keypad_col_gpios), + .settle_time.tv.nsec = 0, + .poll_time.tv.nsec = 20 * NSEC_PER_MSEC, + .flags = GPIOKPF_LEVEL_TRIGGERED_IRQ | GPIOKPF_DRIVE_INACTIVE | + GPIOKPF_PRINT_UNMAPPED_KEYS +}; + +static struct gpio_event_info *keypad_info_7k_ffa[] = { + &keypad_matrix_info_7k_ffa.info +}; + +static struct gpio_event_platform_data keypad_data_7k_ffa = { + .name = "7k_ffa_keypad", + .info = keypad_info_7k_ffa, + .info_count = ARRAY_SIZE(keypad_info_7k_ffa) +}; + +struct platform_device keypad_device_7k_ffa = { + .name = GPIO_EVENT_DEV_NAME, + .id = -1, + .dev = { + .platform_data = &keypad_data_7k_ffa, + }, +}; + +static struct input_dev *keypad_dev; + +static int keypad_gpio_event_matrix_func(struct input_dev *input_dev, + struct gpio_event_info *info, + void **data, int func) +{ + int err; + int i; + + err = gpio_event_matrix_func(input_dev, info, data, func); + + if (func == GPIO_EVENT_FUNC_INIT && !err) { + keypad_dev = input_dev; + for (i = 0; i < ARRAY_SIZE(keypad_virtual_keys); i++) + set_bit(keypad_virtual_keys[i] & KEY_MAX, + input_dev->keybit); + } else if (func == GPIO_EVENT_FUNC_UNINIT) { + keypad_dev = NULL; + } + + return err; +} + +struct input_dev *msm_keypad_get_input_dev(void) +{ + return keypad_dev; +} + diff --git a/arch/arm/mach-msm/keypad-surf-ffa.h b/arch/arm/mach-msm/keypad-surf-ffa.h new file mode 100644 index 000000000000..2a29307fddfb --- /dev/null +++ b/arch/arm/mach-msm/keypad-surf-ffa.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#ifndef _KEYPAD_SURF_FFA_H +#define _KEYPAD_SURF_FFA_H + +#include + +#if defined(CONFIG_SURF_FFA_GPIO_KEYPAD) +struct input_dev *msm_keypad_get_input_dev(void); +#else +static struct input_dev *msm_keypad_get_input_dev(void) +{ + return NULL; +} +#endif + +#endif diff --git a/arch/arm/mach-msm/memory.c b/arch/arm/mach-msm/memory.c new file mode 100644 index 000000000000..e87bbddc58b0 --- /dev/null +++ b/arch/arm/mach-msm/memory.c @@ -0,0 +1,86 @@ +/* arch/arm/mach-msm/memory.c + * + * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 + +int arch_io_remap_pfn_range(struct vm_area_struct *vma, unsigned long addr, + unsigned long pfn, unsigned long size, pgprot_t prot) +{ + unsigned long pfn_addr = pfn << PAGE_SHIFT; + if ((pfn_addr >= 0x88000000) && (pfn_addr < 0xD0000000)) { + prot = pgprot_device(prot); + printk("remapping device %lx\n", prot); + } + return remap_pfn_range(vma, addr, pfn, size, prot); +} + +void *zero_page_strongly_ordered; + +static void map_zero_page_strongly_ordered(void) +{ + if (zero_page_strongly_ordered) + return; + + zero_page_strongly_ordered = + ioremap_strongly_ordered(page_to_pfn(empty_zero_page) + << PAGE_SHIFT, PAGE_SIZE); +} + +void write_to_strongly_ordered_memory(void) +{ + map_zero_page_strongly_ordered(); + *(int *)zero_page_strongly_ordered = 0; +} + +void flush_axi_bus_buffer(void) +{ + __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" \ + : : "r" (0) : "memory"); + write_to_strongly_ordered_memory(); +} + +void *alloc_bootmem_aligned(unsigned long size, unsigned long alignment) +{ + void *unused_addr = NULL; + unsigned long addr, tmp_size, unused_size; + + /* Allocate maximum size needed, see where it ends up. + * Then free it -- in this path there are no other allocators + * so we can depend on getting the same address back + * when we allocate a smaller piece that is aligned + * at the end (if necessary) and the piece we really want, + * then free the unused first piece. + */ + + tmp_size = size + alignment - PAGE_SIZE; + addr = (unsigned long)alloc_bootmem(tmp_size); + free_bootmem(__pa(addr), tmp_size); + + unused_size = alignment - (addr % alignment); + if (unused_size) + unused_addr = alloc_bootmem(unused_size); + + addr = (unsigned long)alloc_bootmem(size); + if (unused_size) + free_bootmem(__pa(unused_addr), unused_size); + + return (void *)addr; +} diff --git a/arch/arm/mach-msm/modem_notifier.c b/arch/arm/mach-msm/modem_notifier.c new file mode 100644 index 000000000000..532757065aa9 --- /dev/null +++ b/arch/arm/mach-msm/modem_notifier.c @@ -0,0 +1,237 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +/* + * Modem Restart Notifier -- Provides notification + * of modem restart events. + */ + +#include +#include +#include +#include +#include + +#include "modem_notifier.h" + +#define DEBUG + +static struct srcu_notifier_head modem_notifier_list; +static struct workqueue_struct *modem_notifier_wq; + +static void notify_work_start_reset(struct work_struct *work) +{ + modem_notify(0, MODEM_NOTIFIER_START_RESET); +} +static DECLARE_WORK(modem_notifier_start_reset_work, ¬ify_work_start_reset); + +void modem_queue_start_reset_notify(void) +{ + int ret; + + ret = queue_work(modem_notifier_wq, &modem_notifier_start_reset_work); + + if (!ret) + printk(KERN_ERR "%s\n", __func__); +} +EXPORT_SYMBOL(modem_queue_start_reset_notify); + +static void notify_work_end_reset(struct work_struct *work) +{ + modem_notify(0, MODEM_NOTIFIER_END_RESET); +} +static DECLARE_WORK(modem_notifier_end_reset_work, ¬ify_work_end_reset); + +void modem_queue_end_reset_notify(void) +{ + int ret; + + ret = queue_work(modem_notifier_wq, &modem_notifier_end_reset_work); + + if (!ret) + printk(KERN_ERR "%s\n", __func__); +} +EXPORT_SYMBOL(modem_queue_end_reset_notify); + +int modem_register_notifier(struct notifier_block *nb) +{ + int ret; + + ret = srcu_notifier_chain_register( + &modem_notifier_list, nb); + + return ret; +} +EXPORT_SYMBOL(modem_register_notifier); + +int modem_unregister_notifier(struct notifier_block *nb) +{ + int ret; + + ret = srcu_notifier_chain_unregister( + &modem_notifier_list, nb); + + return ret; +} +EXPORT_SYMBOL(modem_unregister_notifier); + +void modem_notify(void *data, unsigned int state) +{ + srcu_notifier_call_chain(&modem_notifier_list, state, data); +} +EXPORT_SYMBOL(modem_notify); + +#if defined(CONFIG_DEBUG_FS) +static int debug_reset_start(const char __user *buf, int count) +{ + modem_queue_start_reset_notify(); + return 0; +} + +static int debug_reset_end(const char __user *buf, int count) +{ + modem_queue_end_reset_notify(); + return 0; +} + +static ssize_t debug_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + int (*fling)(const char __user *buf, int max) = file->private_data; + fling(buf, count); + return count; +} + +static int debug_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static const struct file_operations debug_ops = { + .write = debug_write, + .open = debug_open, +}; + +static void debug_create(const char *name, mode_t mode, + struct dentry *dent, + int (*fling)(const char __user *buf, int max)) +{ + debugfs_create_file(name, mode, dent, fling, &debug_ops); +} + +static void modem_notifier_debugfs_init(void) +{ + struct dentry *dent; + + dent = debugfs_create_dir("modem_notifier", 0); + if (IS_ERR(dent)) + return; + + debug_create("reset_start", 0444, dent, debug_reset_start); + debug_create("reset_end", 0444, dent, debug_reset_end); +} +#else +static void modem_notifier_debugfs_init(void) {} +#endif + +#if defined(DEBUG) +static int modem_notifier_test_call(struct notifier_block *this, + unsigned long code, + void *_cmd) +{ + switch (code) { + case MODEM_NOTIFIER_START_RESET: + printk(KERN_ERR "Notify: start reset\n"); + break; + case MODEM_NOTIFIER_END_RESET: + printk(KERN_ERR "Notify: end reset\n"); + break; + default: + printk(KERN_ERR "Notify: general\n"); + break; + } + return NOTIFY_DONE; +} + +static struct notifier_block nb = { + .notifier_call = modem_notifier_test_call, +}; + +static void register_test_notifier(void) +{ + modem_register_notifier(&nb); +} +#endif + +static int __init init_modem_notifier_list(void) +{ + srcu_init_notifier_head(&modem_notifier_list); + modem_notifier_debugfs_init(); +#if defined(DEBUG) + register_test_notifier(); +#endif + + /* Create the workqueue */ + modem_notifier_wq = create_singlethread_workqueue("modem_notifier"); + if (!modem_notifier_wq) { + srcu_cleanup_notifier_head(&modem_notifier_list); + return -ENOMEM; + } + + return 0; +} +module_init(init_modem_notifier_list); diff --git a/arch/arm/mach-msm/modem_notifier.h b/arch/arm/mach-msm/modem_notifier.h new file mode 100644 index 000000000000..ceaabc95c560 --- /dev/null +++ b/arch/arm/mach-msm/modem_notifier.h @@ -0,0 +1,77 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +/* + * Modem Restart Notifier API + * + */ + +#ifndef _MODEM_NOTIFIER_H +#define _MODEM_NOTIFIER_H + +#include + +#define MODEM_NOTIFIER_START_RESET 0x1 +#define MODEM_NOTIFIER_END_RESET 0x2 + +extern int modem_register_notifier(struct notifier_block *nb); +extern int modem_unregister_notifier(struct notifier_block *nb); +extern void modem_notify(void *data, unsigned int state); +extern void modem_queue_start_reset_notify(void); +extern void modem_queue_end_reset_notify(void); + + +#endif /* _MODEM_NOTIFIER_H */ diff --git a/arch/arm/mach-msm/mpp.c b/arch/arm/mach-msm/mpp.c new file mode 100644 index 000000000000..1b992d2ab1d5 --- /dev/null +++ b/arch/arm/mach-msm/mpp.c @@ -0,0 +1,163 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* Qualcomm PMIC Multi-Purpose Pin Configurations */ + +#include +#include +#include +#include + +#include + +#include "proc_comm.h" + +#define MPP(_name, _id, _status) { .name = _name, .id = _id, .status = _status} + +static struct mpp mpps[] = { + MPP("mpp1", 0, 0), + MPP("mpp2", 1, 0), + MPP("mpp3", 2, 0), + MPP("mpp4", 3, 0), + MPP("mpp5", 4, 0), + MPP("mpp6", 5, 0), + MPP("mpp7", 6, 0), + MPP("mpp8", 7, 0), + MPP("mpp9", 8, 0), + MPP("mpp10", 9, 0), + MPP("mpp11", 10, 0), + MPP("mpp12", 11, 0), + MPP("mpp13", 12, 0), + MPP("mpp14", 13, 0), + MPP("mpp15", 14, 0), + MPP("mpp16", 15, 0), + MPP("mpp17", 16, 0), + MPP("mpp18", 17, 0), + MPP("mpp19", 18, 0), + MPP("mpp20", 19, 0), + MPP("mpp21", 20, 0), + MPP("mpp22", 21, 0), +}; + +struct mpp *mpp_get(struct device *dev, const char *id) +{ + int n; + for (n = 0; n < ARRAY_SIZE(mpps); n++) { + if (!strcmp(mpps[n].name, id)) + return mpps + n; + } + return NULL; +} +EXPORT_SYMBOL(mpp_get); + +int mpp_config_digital_out(struct mpp *mpp, unsigned config) +{ + unsigned id = mpp->id; + int err; + err = msm_proc_comm(PCOM_PM_MPP_CONFIG, &id, &config); + mpp->status = err; + return err; +} +EXPORT_SYMBOL(mpp_config_digital_out); + +#if defined(CONFIG_DEBUG_FS) +static int mpp_debug_set(void *data, u64 val) +{ + int err; + struct mpp *mpp = data; + + err = mpp_config_digital_out(mpp, (unsigned)val); + if (err) { + printk(KERN_ERR + "%s: mpp_config_digital_out \ + [%s(%d) = 0x%x] failed\n", + __func__, mpp->name, mpp->id, (unsigned)val); + } + return 0; +} + +static int mpp_debug_get(void *data, u64 *val) +{ + struct mpp *mpp = data; + int status = mpp->status; + if (!status) + *val = 0; + else + *val = 1; + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(mpp_fops, mpp_debug_get, mpp_debug_set, "%llu\n"); + +static int __init mpp_debug_init(void) +{ + struct dentry *dent; + int n; + + dent = debugfs_create_dir("mpp", 0); + if (IS_ERR(dent)) + return 0; + + for (n = 0; n < ARRAY_SIZE(mpps); n++) + debugfs_create_file(mpps[n].name, 0644, dent, mpps + n, + &mpp_fops); + + return 0; +} + +device_initcall(mpp_debug_init); +#endif diff --git a/arch/arm/mach-msm/msm-keypad-devices.h b/arch/arm/mach-msm/msm-keypad-devices.h new file mode 100644 index 000000000000..469564a754ad --- /dev/null +++ b/arch/arm/mach-msm/msm-keypad-devices.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#ifndef _MSM_KEYPAD_DEVICES_H +#define _MSM_KEYPAD_DEVICES_H + +extern struct platform_device keypad_device_7k_ffa; +extern struct platform_device keypad_device_8k_ffa; +extern struct platform_device keypad_device_surf; + +#endif diff --git a/arch/arm/mach-msm/nand_partitions.c b/arch/arm/mach-msm/nand_partitions.c index 482e6958504b..fc874470339b 100644 --- a/arch/arm/mach-msm/nand_partitions.c +++ b/arch/arm/mach-msm/nand_partitions.c @@ -4,6 +4,7 @@ * bootloader. * * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. * Author: Brian Swetland * * This software is licensed under the terms of the GNU General Public @@ -22,7 +23,7 @@ #include #include -#include +#include #include @@ -32,13 +33,13 @@ #include #include +#include "smd_private.h" /* configuration tags specific to msm */ #define ATAG_MSM_PARTITION 0x4d534D70 /* MSMp */ -struct msm_ptbl_entry -{ +struct msm_ptbl_entry { char name[16]; __u32 offset; __u32 size; @@ -73,6 +74,10 @@ static int __init parse_tag_msm_partition(const struct tag *tag) ptn->offset = entry->offset * 64 * 2048; ptn->size = entry->size * 64 * 2048; + printk(KERN_INFO "Partition (from atag) %s " + "-- Offset:%llx Size:%llx\n", + ptn->name, ptn->offset, ptn->size); + name += 16; entry++; ptn++; @@ -85,3 +90,98 @@ static int __init parse_tag_msm_partition(const struct tag *tag) } __tagtable(ATAG_MSM_PARTITION, parse_tag_msm_partition); + +#define FLASH_PART_MAGIC1 0x55EE73AA +#define FLASH_PART_MAGIC2 0xE35EBDDB +#define FLASH_PARTITION_VERSION 0x3 + +#define LINUX_FS_PARTITION_NAME "0:EFS2APPS" + +struct flash_partition_entry { + char name[16]; + u32 offset; /* Offset in blocks from beginning of device */ + u32 length; /* Length of the partition in blocks */ + u8 attrib1; + u8 attrib2; + u8 attrib3; + u8 which_flash; /* Numeric ID (first = 0, second = 1) */ +}; +struct flash_partition_table { + u32 magic1; + u32 magic2; + u32 version; + u32 numparts; + struct flash_partition_entry part_entry[16]; +}; + +static int get_nand_partitions(void) +{ + struct flash_partition_table *partition_table; + struct flash_partition_entry *part_entry; + struct mtd_partition *ptn = msm_nand_partitions; + char *name = msm_nand_names; + int part; + + if (msm_nand_data.nr_parts) + return 0; + + partition_table = (struct flash_partition_table *) + smem_alloc(SMEM_AARM_PARTITION_TABLE, + sizeof(struct flash_partition_table)); + + if (!partition_table) { + printk(KERN_WARNING "%s: no flash partition table in shared " + "memory\n", __func__); + return -ENOENT; + } + + if ((partition_table->magic1 != (u32) FLASH_PART_MAGIC1) || + (partition_table->magic2 != (u32) FLASH_PART_MAGIC2) || + (partition_table->version != (u32) FLASH_PARTITION_VERSION)) { + printk(KERN_WARNING "%s: version mismatch -- magic1=%#x, " + "magic2=%#x, version=%#x\n", __func__, + partition_table->magic1, + partition_table->magic2, + partition_table->version); + return -EFAULT; + } + + msm_nand_data.nr_parts = 0; + + /* Get the LINUX FS partition info */ + for (part = 0; part < partition_table->numparts; part++) { + part_entry = &partition_table->part_entry[part]; + + /* Find a match for the Linux file system partition */ + if (strcmp(part_entry->name, LINUX_FS_PARTITION_NAME) == 0) { + strcpy(name, part_entry->name); + ptn->name = name; + + /*TODO: Get block count and size info */ + ptn->offset = part_entry->offset * 64 * 2048; + + /* For SMEM, -1 indicates remaining space in flash, + * but for MTD it is 0 + */ + if (part_entry->length == (u32)-1) + ptn->size = 0; + else + ptn->size = part_entry->length * 64 * 2048; + + msm_nand_data.nr_parts = 1; + msm_nand_data.parts = msm_nand_partitions; + + printk(KERN_INFO "Partition(from smem) %s " + "-- Offset:%llx Size:%llx\n", + ptn->name, ptn->offset, ptn->size); + + return 0; + } + } + + printk(KERN_WARNING "%s: no partition table found!", __func__); + + return -ENODEV; +} + +device_initcall(get_nand_partitions); diff --git a/arch/arm/mach-msm/nohlt.c b/arch/arm/mach-msm/nohlt.c new file mode 100644 index 000000000000..a680fbb8f82d --- /dev/null +++ b/arch/arm/mach-msm/nohlt.c @@ -0,0 +1,86 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +/* + * MSM architecture driver to control arm halt behavior + */ + +#include +#include +#include +#include + +#ifdef CONFIG_DEBUG_FS +static int set_nohalt(void *data, u64 val) +{ + if (val) + disable_hlt(); + else + enable_hlt(); + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(nohalt_ops, NULL, set_nohalt, "%llu\n"); + +static int __init init_hlt_debug(void) +{ + debugfs_create_file("nohlt", 0200, NULL, NULL, &nohalt_ops); + + return 0; +} + +late_initcall(init_hlt_debug); +#endif diff --git a/arch/arm/mach-msm/pm.c b/arch/arm/mach-msm/pm.c index 17de9f20e408..b61b592841c9 100644 --- a/arch/arm/mach-msm/pm.c +++ b/arch/arm/mach-msm/pm.c @@ -3,6 +3,7 @@ * MSM Power Management Routines * * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -21,20 +22,29 @@ #include #include #include +#include #include #include #include +#include #include #include #include -#include "smd_private.h" -#include "acpuclock.h" -#include "proc_comm.h" #ifdef CONFIG_HAS_WAKELOCK #include #endif +#include "smd_private.h" +#include "acpuclock.h" +#include "clock.h" +#include "proc_comm.h" +#include "idle.h" +#include "irq.h" +#include "gpio.h" +#include "timer.h" +#include "pm.h" + enum { MSM_PM_DEBUG_SUSPEND = 1U << 0, MSM_PM_DEBUG_POWER_COLLAPSE = 1U << 1, @@ -47,13 +57,12 @@ enum { static int msm_pm_debug_mask; module_param_named(debug_mask, msm_pm_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP); -enum { - MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND, - MSM_PM_SLEEP_MODE_POWER_COLLAPSE, - MSM_PM_SLEEP_MODE_APPS_SLEEP, - MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT, - MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT, -}; +#ifdef CONFIG_MSM_SLEEP_TIME_OVERRIDE +static int msm_pm_sleep_time_override; +module_param_named(sleep_time_override, + msm_pm_sleep_time_override, int, S_IRUGO | S_IWUSR | S_IWGRP); +#endif + static int msm_pm_sleep_mode = CONFIG_MSM7X00A_SLEEP_MODE; module_param_named(sleep_mode, msm_pm_sleep_mode, int, S_IRUGO | S_IWUSR | S_IWGRP); static int msm_pm_idle_sleep_mode = CONFIG_MSM7X00A_IDLE_SLEEP_MODE; @@ -68,18 +77,31 @@ module_param_named(idle_spin_time, msm_pm_idle_spin_time, int, S_IRUGO | S_IWUSR #define A11S_STANDBY_CTL (MSM_CSR_BASE + 0x108) #define A11RAMBACKBIAS (MSM_CSR_BASE + 0x508) -int msm_pm_collapse(void); -int msm_arch_idle(void); -void msm_pm_collapse_exit(void); +enum { + SLEEP_LIMIT_NONE = 0, + SLEEP_LIMIT_NO_TCXO_SHUTDOWN = 2 +}; -int64_t msm_timer_enter_idle(void); -void msm_timer_exit_idle(int low_power); -int msm_irq_idle_sleep_allowed(void); -int msm_irq_pending(void); +static atomic_t msm_pm_init_done = ATOMIC_INIT(0); +struct smsm_interrupt_info_ext { + uint32_t aArm_en_mask; + uint32_t aArm_interrupts_pending; + uint32_t aArm_wakeup_reason; + uint32_t aArm_rpc_prog; + uint32_t aArm_rpc_proc; + char aArm_smd_port_name[20]; + uint32_t aArm_gpio_info; +}; +static struct msm_pm_smem_addr_t { + uint32_t *sleep_delay; + uint32_t *limit_sleep; + struct smsm_interrupt_info *int_info; + struct smsm_interrupt_info_ext *int_info_ext; +} msm_pm_sma; static uint32_t *msm_pm_reset_vector; - static uint32_t msm_pm_max_sleep_time; +static struct msm_pm_platform_data *msm_pm_modes; #ifdef CONFIG_MSM_IDLE_STATS enum msm_pm_time_stats_id { @@ -88,12 +110,17 @@ enum msm_pm_time_stats_id { MSM_PM_STAT_IDLE_WFI, MSM_PM_STAT_IDLE_SLEEP, MSM_PM_STAT_IDLE_FAILED_SLEEP, + MSM_PM_STAT_IDLE_POWER_COLLAPSE, + MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE, + MSM_PM_STAT_SUSPEND, + MSM_PM_STAT_FAILED_SUSPEND, MSM_PM_STAT_NOT_IDLE, MSM_PM_STAT_COUNT }; static struct msm_pm_time_stats { const char *name; + int64_t first_bucket_time; int bucket[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT]; int64_t min_time[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT]; int64_t max_time[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT]; @@ -101,11 +128,45 @@ static struct msm_pm_time_stats { int64_t total_time; } msm_pm_stats[MSM_PM_STAT_COUNT] = { [MSM_PM_STAT_REQUESTED_IDLE].name = "idle-request", + [MSM_PM_STAT_REQUESTED_IDLE].first_bucket_time = + CONFIG_MSM_IDLE_STATS_FIRST_BUCKET, + [MSM_PM_STAT_IDLE_SPIN].name = "idle-spin", + [MSM_PM_STAT_IDLE_SPIN].first_bucket_time = + CONFIG_MSM_IDLE_STATS_FIRST_BUCKET, + [MSM_PM_STAT_IDLE_WFI].name = "idle-wfi", + [MSM_PM_STAT_IDLE_WFI].first_bucket_time = + CONFIG_MSM_IDLE_STATS_FIRST_BUCKET, + [MSM_PM_STAT_IDLE_SLEEP].name = "idle-sleep", + [MSM_PM_STAT_IDLE_SLEEP].first_bucket_time = + CONFIG_MSM_IDLE_STATS_FIRST_BUCKET, + [MSM_PM_STAT_IDLE_FAILED_SLEEP].name = "idle-failed-sleep", + [MSM_PM_STAT_IDLE_FAILED_SLEEP].first_bucket_time = + CONFIG_MSM_IDLE_STATS_FIRST_BUCKET, + + [MSM_PM_STAT_IDLE_POWER_COLLAPSE].name = "idle-power-collapse", + [MSM_PM_STAT_IDLE_POWER_COLLAPSE].first_bucket_time = + CONFIG_MSM_IDLE_STATS_FIRST_BUCKET, + + [MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE].name = + "idle-failed-power-collapse", + [MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE].first_bucket_time = + CONFIG_MSM_IDLE_STATS_FIRST_BUCKET, + + [MSM_PM_STAT_SUSPEND].name = "suspend", + [MSM_PM_STAT_SUSPEND].first_bucket_time = + CONFIG_MSM_SUSPEND_STATS_FIRST_BUCKET, + + [MSM_PM_STAT_FAILED_SUSPEND].name = "failed-suspend", + [MSM_PM_STAT_FAILED_SUSPEND].first_bucket_time = + CONFIG_MSM_IDLE_STATS_FIRST_BUCKET, + [MSM_PM_STAT_NOT_IDLE].name = "not-idle", + [MSM_PM_STAT_NOT_IDLE].first_bucket_time = + CONFIG_MSM_IDLE_STATS_FIRST_BUCKET, }; static void msm_pm_add_stat(enum msm_pm_time_stats_id id, int64_t t) @@ -115,7 +176,7 @@ static void msm_pm_add_stat(enum msm_pm_time_stats_id id, int64_t t) msm_pm_stats[id].total_time += t; msm_pm_stats[id].count++; bt = t; - do_div(bt, CONFIG_MSM_IDLE_STATS_FIRST_BUCKET); + do_div(bt, msm_pm_stats[id].first_bucket_time); if (bt < 1ULL << (CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT * (CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1))) i = DIV_ROUND_UP(fls((uint32_t)bt), @@ -128,6 +189,9 @@ static void msm_pm_add_stat(enum msm_pm_time_stats_id id, int64_t t) if (t > msm_pm_stats[id].max_time[i]) msm_pm_stats[id].max_time[i] = t; } + +static uint32_t msm_pm_sleep_limit = SLEEP_LIMIT_NONE; +static DECLARE_BITMAP(msm_pm_clocks_no_tcxo_shutdown, NR_CLKS); #endif static int @@ -138,7 +202,7 @@ msm_pm_wait_state(uint32_t wait_state_all_set, uint32_t wait_state_all_clear, uint32_t state; for (i = 0; i < 100000; i++) { - state = smsm_get_state(); + state = smsm_get_state(SMSM_MODEM_STATE); if (((state & wait_state_all_set) == wait_state_all_set) && ((~state & wait_state_all_clear) == wait_state_all_clear) && (wait_state_any_set == 0 || (state & wait_state_any_set) || @@ -151,18 +215,11 @@ msm_pm_wait_state(uint32_t wait_state_all_set, uint32_t wait_state_all_clear, return -ETIMEDOUT; } -static int msm_sleep(int sleep_mode, uint32_t sleep_delay, int from_idle) +static int msm_sleep(int sleep_mode, uint32_t sleep_delay, + uint32_t sleep_limit, int from_idle) { uint32_t saved_vector[2]; int collapsed; - void msm_irq_enter_sleep1(bool arm9_wake, int from_idle); - int msm_irq_enter_sleep2(bool arm9_wake, int from_idle); - void msm_irq_exit_sleep1(void); - void msm_irq_exit_sleep2(void); - void msm_irq_exit_sleep3(void); - void msm_gpio_enter_sleep(int from_idle); - void msm_gpio_exit_sleep(void); - void smd_sleep_exit(void); uint32_t enter_state; uint32_t enter_wait_set = 0; uint32_t enter_wait_clear = 0; @@ -174,8 +231,9 @@ static int msm_sleep(int sleep_mode, uint32_t sleep_delay, int from_idle) int rv = -EINTR; if (msm_pm_debug_mask & MSM_PM_DEBUG_SUSPEND) - printk(KERN_INFO "msm_sleep(): mode %d delay %u idle %d\n", - sleep_mode, sleep_delay, from_idle); + printk(KERN_INFO "msm_sleep(): " + "mode %d delay %u limit %u idle %d\n", + sleep_mode, sleep_delay, sleep_limit, from_idle); switch (sleep_mode) { case MSM_PM_SLEEP_MODE_POWER_COLLAPSE: @@ -200,14 +258,26 @@ static int msm_sleep(int sleep_mode, uint32_t sleep_delay, int from_idle) exit_state = 0; } - msm_irq_enter_sleep1(!!enter_state, from_idle); + if (enter_state && !(smsm_get_state(SMSM_MODEM_STATE) & SMSM_RUN)) { + if ((MSM_PM_DEBUG_POWER_COLLAPSE | MSM_PM_DEBUG_SUSPEND) & + msm_pm_debug_mask) + printk(KERN_INFO "msm_sleep(): modem not ready\n"); + rv = -EBUSY; + goto check_failed; + } + + memset(msm_pm_sma.int_info, 0, sizeof(*msm_pm_sma.int_info)); + msm_irq_enter_sleep1(!!enter_state, from_idle, + &msm_pm_sma.int_info->aArm_en_mask); msm_gpio_enter_sleep(from_idle); if (enter_state) { if (sleep_delay == 0 && sleep_mode >= MSM_PM_SLEEP_MODE_APPS_SLEEP) sleep_delay = 192000*5; /* APPS_SLEEP does not allow infinite timeout */ - smsm_set_sleep_duration(sleep_delay); - ret = smsm_change_state(SMSM_RUN, enter_state); + + *msm_pm_sma.sleep_delay = sleep_delay; + *msm_pm_sma.limit_sleep = sleep_limit; + ret = smsm_change_state(SMSM_APPS_STATE, SMSM_RUN, enter_state); if (ret) { printk(KERN_ERR "msm_sleep(): smsm_change_state %x failed\n", enter_state); enter_state = 0; @@ -215,7 +285,9 @@ static int msm_sleep(int sleep_mode, uint32_t sleep_delay, int from_idle) } ret = msm_pm_wait_state(enter_wait_set, enter_wait_clear, 0, 0); if (ret) { - printk(KERN_INFO "msm_sleep(): msm_pm_wait_state failed, %x\n", smsm_get_state()); + printk(KERN_INFO "msm_sleep(): " + "msm_pm_wait_state failed, %x\n", + smsm_get_state(SMSM_MODEM_STATE)); goto enter_failed; } } @@ -233,7 +305,8 @@ static int msm_sleep(int sleep_mode, uint32_t sleep_delay, int from_idle) printk(KERN_INFO "msm_sleep(): enter " "A11S_CLK_SLEEP_EN %x, A11S_PWRDOWN %x, " "smsm_get_state %x\n", readl(A11S_CLK_SLEEP_EN), - readl(A11S_PWRDOWN), smsm_get_state()); + readl(A11S_PWRDOWN), + smsm_get_state(SMSM_MODEM_STATE)); } if (sleep_mode <= MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT) { @@ -245,8 +318,16 @@ static int msm_sleep(int sleep_mode, uint32_t sleep_delay, int from_idle) goto ramp_down_failed; } if (sleep_mode < MSM_PM_SLEEP_MODE_APPS_SLEEP) { +#ifdef CONFIG_MSM_ADM_OFF_AT_POWER_COLLAPSE + unsigned id = ADM_CLK; + msm_proc_comm(PCOM_CLKCTL_RPC_DISABLE, &id, NULL); +#endif if (msm_pm_debug_mask & MSM_PM_DEBUG_SMSM_STATE) - smsm_print_sleep_info(); + smsm_print_sleep_info(*msm_pm_sma.sleep_delay, + *msm_pm_sma.limit_sleep, + msm_pm_sma.int_info->aArm_en_mask, + msm_pm_sma.int_info->aArm_wakeup_reason, + msm_pm_sma.int_info->aArm_interrupts_pending); saved_vector[0] = msm_pm_reset_vector[0]; saved_vector[1] = msm_pm_reset_vector[1]; msm_pm_reset_vector[0] = 0xE51FF004; /* ldr pc, 4 */ @@ -267,7 +348,18 @@ static int msm_sleep(int sleep_mode, uint32_t sleep_delay, int from_idle) printk(KERN_INFO "msm_pm_collapse(): returned %d\n", collapsed); if (msm_pm_debug_mask & MSM_PM_DEBUG_SMSM_STATE) - smsm_print_sleep_info(); + smsm_print_sleep_info(*msm_pm_sma.sleep_delay, + *msm_pm_sma.limit_sleep, + msm_pm_sma.int_info->aArm_en_mask, + msm_pm_sma.int_info->aArm_wakeup_reason, + msm_pm_sma.int_info->aArm_interrupts_pending); +#ifdef CONFIG_MSM_ADM_OFF_AT_POWER_COLLAPSE + id = ADM_CLK; + if (msm_proc_comm(PCOM_CLKCTL_RPC_ENABLE, &id, NULL) < 0 || + id < 0) + printk(KERN_ERR + "msm_sleep(): failed to turn on ADM clock\n"); +#endif } else { msm_arch_idle(); rv = 0; @@ -277,7 +369,7 @@ static int msm_sleep(int sleep_mode, uint32_t sleep_delay, int from_idle) if (msm_pm_debug_mask & MSM_PM_DEBUG_CLOCK) printk(KERN_INFO "msm_sleep(): exit power collapse %ld" "\n", pm_saved_acpu_clk_rate); - if (acpuclk_set_rate(pm_saved_acpu_clk_rate, 1) < 0) + if (acpuclk_set_rate(pm_saved_acpu_clk_rate, SETRATE_PC) < 0) printk(KERN_ERR "msm_sleep(): clk_set_rate %ld " "failed\n", pm_saved_acpu_clk_rate); } @@ -285,65 +377,126 @@ static int msm_sleep(int sleep_mode, uint32_t sleep_delay, int from_idle) printk(KERN_INFO "msm_sleep(): exit A11S_CLK_SLEEP_EN %x, " "A11S_PWRDOWN %x, smsm_get_state %x\n", readl(A11S_CLK_SLEEP_EN), readl(A11S_PWRDOWN), - smsm_get_state()); + smsm_get_state(SMSM_MODEM_STATE)); ramp_down_failed: - msm_irq_exit_sleep1(); + msm_irq_exit_sleep1(msm_pm_sma.int_info->aArm_en_mask, + msm_pm_sma.int_info->aArm_wakeup_reason, + msm_pm_sma.int_info->aArm_interrupts_pending); enter_failed: if (enter_state) { writel(0x00, A11S_CLK_SLEEP_EN); writel(0, A11S_PWRDOWN); - smsm_change_state(enter_state, exit_state); + smsm_change_state(SMSM_APPS_STATE, enter_state, exit_state); msm_pm_wait_state(exit_wait_set, exit_wait_clear, 0, 0); if (msm_pm_debug_mask & MSM_PM_DEBUG_STATE) printk(KERN_INFO "msm_sleep(): sleep exit " "A11S_CLK_SLEEP_EN %x, A11S_PWRDOWN %x, " "smsm_get_state %x\n", readl(A11S_CLK_SLEEP_EN), - readl(A11S_PWRDOWN), smsm_get_state()); + readl(A11S_PWRDOWN), + smsm_get_state(SMSM_MODEM_STATE)); if (msm_pm_debug_mask & MSM_PM_DEBUG_SMSM_STATE) - smsm_print_sleep_info(); + smsm_print_sleep_info(*msm_pm_sma.sleep_delay, + *msm_pm_sma.limit_sleep, + msm_pm_sma.int_info->aArm_en_mask, + msm_pm_sma.int_info->aArm_wakeup_reason, + msm_pm_sma.int_info->aArm_interrupts_pending); } - msm_irq_exit_sleep2(); + msm_irq_exit_sleep2(msm_pm_sma.int_info->aArm_en_mask, + msm_pm_sma.int_info->aArm_wakeup_reason, + msm_pm_sma.int_info->aArm_interrupts_pending); if (enter_state) { - smsm_change_state(exit_state, SMSM_RUN); + smsm_change_state(SMSM_APPS_STATE, exit_state, SMSM_RUN); msm_pm_wait_state(SMSM_RUN, 0, 0, 0); if (msm_pm_debug_mask & MSM_PM_DEBUG_STATE) printk(KERN_INFO "msm_sleep(): sleep exit " "A11S_CLK_SLEEP_EN %x, A11S_PWRDOWN %x, " "smsm_get_state %x\n", readl(A11S_CLK_SLEEP_EN), - readl(A11S_PWRDOWN), smsm_get_state()); + readl(A11S_PWRDOWN), + smsm_get_state(SMSM_MODEM_STATE)); } - msm_irq_exit_sleep3(); + msm_irq_exit_sleep3(msm_pm_sma.int_info->aArm_en_mask, + msm_pm_sma.int_info->aArm_wakeup_reason, + msm_pm_sma.int_info->aArm_interrupts_pending); msm_gpio_exit_sleep(); smd_sleep_exit(); + +check_failed: return rv; } +void msm_pm_set_max_sleep_time(int64_t max_sleep_time_ns) +{ + int64_t max_sleep_time_bs = max_sleep_time_ns; + + /* Convert from ns -> BS units */ + do_div(max_sleep_time_bs, NSEC_PER_SEC / 32768); + + if (max_sleep_time_bs > 0x6DDD000) + msm_pm_max_sleep_time = (uint32_t) 0x6DDD000; + else + msm_pm_max_sleep_time = (uint32_t) max_sleep_time_bs; + + if (msm_pm_debug_mask & MSM_PM_DEBUG_SUSPEND) + printk(KERN_INFO "%s: Requested %lldns (%lldbs), Giving %ubs\n", + __func__, max_sleep_time_ns, + max_sleep_time_bs, + msm_pm_max_sleep_time); +} +EXPORT_SYMBOL(msm_pm_set_max_sleep_time); + void arch_idle(void) { int ret; int spin; int64_t sleep_time; int low_power = 0; + struct msm_pm_platform_data *mode; #ifdef CONFIG_MSM_IDLE_STATS + DECLARE_BITMAP(clk_ids, NR_CLKS); int64_t t1; static int64_t t2; int exit_stat; #endif + int latency_qos = pm_qos_requirement(PM_QOS_CPU_DMA_LATENCY); + uint32_t sleep_limit = SLEEP_LIMIT_NONE; int allow_sleep = msm_pm_idle_sleep_mode < MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT && #ifdef CONFIG_HAS_WAKELOCK !has_wake_lock(WAKE_LOCK_IDLE) && #endif msm_irq_idle_sleep_allowed(); - if (msm_pm_reset_vector == NULL) + + if (!atomic_read(&msm_pm_init_done)) return; sleep_time = msm_timer_enter_idle(); + #ifdef CONFIG_MSM_IDLE_STATS t1 = ktime_to_ns(ktime_get()); msm_pm_add_stat(MSM_PM_STAT_NOT_IDLE, t1 - t2); msm_pm_add_stat(MSM_PM_STAT_REQUESTED_IDLE, sleep_time); #endif + + mode = &msm_pm_modes[MSM_PM_SLEEP_MODE_POWER_COLLAPSE]; + if (mode->latency >= latency_qos) + sleep_limit = SLEEP_LIMIT_NO_TCXO_SHUTDOWN; + + mode = &msm_pm_modes[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN]; + if (mode->latency >= latency_qos) + allow_sleep = false; + + mode = &msm_pm_modes[ + MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT]; + if (mode->latency >= latency_qos) { + /* no time even for SWFI */ + while (!msm_irq_pending()) + udelay(1); +#ifdef CONFIG_MSM_IDLE_STATS + exit_stat = MSM_PM_STAT_IDLE_SPIN; +#endif + goto abort_idle; + } + if (msm_pm_debug_mask & MSM_PM_DEBUG_IDLE) printk(KERN_INFO "arch_idle: sleep time %llu, allow_sleep %d\n", sleep_time, allow_sleep); @@ -363,33 +516,68 @@ void arch_idle(void) if (msm_pm_debug_mask & MSM_PM_DEBUG_CLOCK) printk(KERN_DEBUG "arch_idle: clk %ld -> swfi\n", saved_rate); - if (saved_rate) + if (saved_rate) { msm_arch_idle(); - else +#ifdef CONFIG_MSM_IDLE_STATS + exit_stat = MSM_PM_STAT_IDLE_WFI; +#endif + } else { while (!msm_irq_pending()) udelay(1); +#ifdef CONFIG_MSM_IDLE_STATS + exit_stat = MSM_PM_STAT_IDLE_SPIN; +#endif + } if (msm_pm_debug_mask & MSM_PM_DEBUG_CLOCK) printk(KERN_DEBUG "msm_sleep: clk swfi -> %ld\n", saved_rate); - if (saved_rate && acpuclk_set_rate(saved_rate, 1) < 0) + if (saved_rate + && acpuclk_set_rate(saved_rate, SETRATE_SWFI) < 0) printk(KERN_ERR "msm_sleep(): clk_set_rate %ld " "failed\n", saved_rate); + } else { #ifdef CONFIG_MSM_IDLE_STATS - exit_stat = MSM_PM_STAT_IDLE_WFI; + ret = msm_clock_require_tcxo(clk_ids, NR_CLKS); +#elif defined(CONFIG_CLOCK_BASED_SLEEP_LIMIT) + ret = msm_clock_require_tcxo(NULL, 0); #endif - } else { + +#ifdef CONFIG_CLOCK_BASED_SLEEP_LIMIT + if (ret) + sleep_limit = SLEEP_LIMIT_NO_TCXO_SHUTDOWN; +#endif + low_power = 1; do_div(sleep_time, NSEC_PER_SEC / 32768); if (sleep_time > 0x6DDD000) { printk("sleep_time too big %lld\n", sleep_time); sleep_time = 0x6DDD000; } - ret = msm_sleep(msm_pm_idle_sleep_mode, sleep_time, 1); + ret = msm_sleep(msm_pm_idle_sleep_mode, sleep_time, + sleep_limit, 1); #ifdef CONFIG_MSM_IDLE_STATS - if (ret) - exit_stat = MSM_PM_STAT_IDLE_FAILED_SLEEP; - else - exit_stat = MSM_PM_STAT_IDLE_SLEEP; + switch (msm_pm_idle_sleep_mode) { + case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND: + case MSM_PM_SLEEP_MODE_POWER_COLLAPSE: + if (ret) + exit_stat = + MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE; + else { + exit_stat = MSM_PM_STAT_IDLE_POWER_COLLAPSE; + msm_pm_sleep_limit = sleep_limit; + bitmap_copy(msm_pm_clocks_no_tcxo_shutdown, + clk_ids, NR_CLKS); + } + break; + case MSM_PM_SLEEP_MODE_APPS_SLEEP: + if (ret) + exit_stat = MSM_PM_STAT_IDLE_FAILED_SLEEP; + else + exit_stat = MSM_PM_STAT_IDLE_SLEEP; + break; + default: + exit_stat = MSM_PM_STAT_IDLE_WFI; + } #endif } abort_idle: @@ -402,7 +590,65 @@ abort_idle: static int msm_pm_enter(suspend_state_t state) { - msm_sleep(msm_pm_sleep_mode, msm_pm_max_sleep_time, 0); + uint32_t sleep_limit; + int ret; +#ifdef CONFIG_MSM_IDLE_STATS + DECLARE_BITMAP(clk_ids, NR_CLKS); + int64_t period = 0; + int64_t time = 0; + + time = msm_timer_get_smem_clock_time(&period); + ret = msm_clock_require_tcxo(clk_ids, NR_CLKS); +#elif defined(CONFIG_CLOCK_BASED_SLEEP_LIMIT) + ret = msm_clock_require_tcxo(NULL, 0); +#endif /* CONFIG_MSM_IDLE_STATS */ + +#ifdef CONFIG_CLOCK_BASED_SLEEP_LIMIT + sleep_limit = ret ? SLEEP_LIMIT_NO_TCXO_SHUTDOWN : SLEEP_LIMIT_NONE; +#else + sleep_limit = SLEEP_LIMIT_NONE; +#endif + +#ifdef CONFIG_MSM_SLEEP_TIME_OVERRIDE + if (msm_pm_sleep_time_override > 0) { + int64_t ns = NSEC_PER_SEC * (int64_t)msm_pm_sleep_time_override; + msm_pm_set_max_sleep_time(ns); + msm_pm_sleep_time_override = 0; + } +#endif + + ret = msm_sleep(msm_pm_sleep_mode, + msm_pm_max_sleep_time, sleep_limit, 0); + +#ifdef CONFIG_MSM_IDLE_STATS + if (msm_pm_sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND || + msm_pm_sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE) { + enum msm_pm_time_stats_id id; + int64_t end_time; + + if (ret) + id = MSM_PM_STAT_FAILED_SUSPEND; + else { + id = MSM_PM_STAT_SUSPEND; + msm_pm_sleep_limit = sleep_limit; + bitmap_copy(msm_pm_clocks_no_tcxo_shutdown, clk_ids, + NR_CLKS); + } + + if (time != 0) { + end_time = msm_timer_get_smem_clock_time(NULL); + if (end_time != 0) { + time = end_time - time; + if (time < 0) + time += period; + } else + time = 0; + } + + msm_pm_add_stat(id, time); + } +#endif + return 0; } @@ -425,11 +671,13 @@ static void msm_pm_restart(char str) * is the default, prefer that to the (slower) proc_comm * reset command. */ +#if 0 if ((restart_reason == 0x776655AA) && msm_hw_reset_hook) { msm_hw_reset_hook(); } else { msm_proc_comm(PCOM_RESET_CHIP, &restart_reason, 0); } +#endif for (;;) ; } @@ -459,94 +707,230 @@ static struct notifier_block msm_reboot_notifier = }; #ifdef CONFIG_MSM_IDLE_STATS -static int msm_pm_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) +/* + * Helper function of snprintf where buf is auto-incremented, size is auto- + * decremented, and there is no return value. + * + * NOTE: buf and size must be l-values (e.g. variables) + */ +#define SNPRINTF(buf, size, format, ...) \ + do { \ + if (size > 0) { \ + int ret; \ + ret = snprintf(buf, size, format, ## __VA_ARGS__); \ + if (ret > size) { \ + buf += size; \ + size = 0; \ + } else { \ + buf += ret; \ + size -= ret; \ + } \ + } \ + } while (0) + +/* + * Write out the power management statistics. + */ +static int msm_pm_read_proc( + char *page, char **start, off_t off, int count, int *eof, void *data) { - int len = 0; - int i, j; + int i; char *p = page; + char clk_name[16]; - for (i = 0; i < ARRAY_SIZE(msm_pm_stats); i++) { + if (count < 1024) { + *start = (char *) 0; + *eof = 0; + return 0; + } + + if (!off) { + SNPRINTF(p, count, "Clocks against last TCXO shutdown:\n"); + for_each_bit(i, msm_pm_clocks_no_tcxo_shutdown, NR_CLKS) { + clk_name[0] = '\0'; + msm_clock_get_name(i, clk_name, sizeof(clk_name)); + SNPRINTF(p, count, " %s (id=%d)\n", clk_name, i); + } + + SNPRINTF(p, count, "Last power collapse voted "); + if (msm_pm_sleep_limit == SLEEP_LIMIT_NONE) + SNPRINTF(p, count, "for TCXO shutdown\n\n"); + else + SNPRINTF(p, count, "against TCXO shutdown\n\n"); + + *start = (char *) 1; + *eof = 0; + } else if (--off < ARRAY_SIZE(msm_pm_stats)) { int64_t bucket_time; int64_t s; uint32_t ns; - s = msm_pm_stats[i].total_time; + + s = msm_pm_stats[off].total_time; ns = do_div(s, NSEC_PER_SEC); - p += sprintf(p, + SNPRINTF(p, count, "%s:\n" " count: %7d\n" " total_time: %lld.%09u\n", - msm_pm_stats[i].name, - msm_pm_stats[i].count, + msm_pm_stats[off].name, + msm_pm_stats[off].count, s, ns); - bucket_time = CONFIG_MSM_IDLE_STATS_FIRST_BUCKET; - for (j = 0; j < CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1; j++) { + + bucket_time = msm_pm_stats[off].first_bucket_time; + for (i = 0; i < CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1; i++) { s = bucket_time; ns = do_div(s, NSEC_PER_SEC); - p += sprintf(p, " <%2lld.%09u: %7d (%lld-%lld)\n", - s, ns, msm_pm_stats[i].bucket[j], - msm_pm_stats[i].min_time[j], - msm_pm_stats[i].max_time[j]); + SNPRINTF(p, count, + " <%6lld.%09u: %7d (%lld-%lld)\n", + s, ns, msm_pm_stats[off].bucket[i], + msm_pm_stats[off].min_time[i], + msm_pm_stats[off].max_time[i]); + bucket_time <<= CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT; } - p += sprintf(p, " >=%2lld.%09u: %7d (%lld-%lld)\n", - s, ns, msm_pm_stats[i].bucket[j], - msm_pm_stats[i].min_time[j], - msm_pm_stats[i].max_time[j]); - } - *start = page + off; - len = p - page; - if (len > off) - len -= off; - else - len = 0; + SNPRINTF(p, count, " >=%6lld.%09u: %7d (%lld-%lld)\n", + s, ns, msm_pm_stats[off].bucket[i], + msm_pm_stats[off].min_time[i], + msm_pm_stats[off].max_time[i]); - return len < count ? len : count; + *start = (char *) 1; + *eof = (off + 1 >= ARRAY_SIZE(msm_pm_stats)); + } + + return p - page; } -#endif +#undef SNPRINTF -void msm_pm_set_max_sleep_time(int64_t max_sleep_time_ns) +#define MSM_PM_STATS_RESET "reset" + +/* + * Reset the power management statistics values. + */ +static int msm_pm_write_proc(struct file *file, const char __user *buffer, + unsigned long count, void *data) { - int64_t max_sleep_time_bs = max_sleep_time_ns; + char buf[sizeof(MSM_PM_STATS_RESET)]; + int ret; + unsigned long flags; + int i; - /* Convert from ns -> BS units */ - do_div(max_sleep_time_bs, NSEC_PER_SEC / 32768); + if (count < strlen(MSM_PM_STATS_RESET)) { + ret = -EINVAL; + goto write_proc_failed; + } - if (max_sleep_time_bs > 0x6DDD000) - msm_pm_max_sleep_time = (uint32_t) 0x6DDD000; - else - msm_pm_max_sleep_time = (uint32_t) max_sleep_time_bs; + if (copy_from_user(buf, buffer, strlen(MSM_PM_STATS_RESET))) { + ret = -EFAULT; + goto write_proc_failed; + } - if (msm_pm_debug_mask & MSM_PM_DEBUG_SUSPEND) - printk("%s: Requested %lldns (%lldbs), Giving %ubs\n", - __func__, max_sleep_time_ns, - max_sleep_time_bs, - msm_pm_max_sleep_time); + if (memcmp(buf, MSM_PM_STATS_RESET, strlen(MSM_PM_STATS_RESET))) { + ret = -EINVAL; + goto write_proc_failed; + } + + local_irq_save(flags); + for (i = 0; i < ARRAY_SIZE(msm_pm_stats); i++) { + memset(msm_pm_stats[i].bucket, + 0, sizeof(msm_pm_stats[i].bucket)); + memset(msm_pm_stats[i].min_time, + 0, sizeof(msm_pm_stats[i].min_time)); + memset(msm_pm_stats[i].max_time, + 0, sizeof(msm_pm_stats[i].max_time)); + msm_pm_stats[i].count = 0; + msm_pm_stats[i].total_time = 0; + } + + msm_pm_sleep_limit = SLEEP_LIMIT_NONE; + bitmap_zero(msm_pm_clocks_no_tcxo_shutdown, NR_CLKS); + local_irq_restore(flags); + + return count; + +write_proc_failed: + return ret; } -EXPORT_SYMBOL(msm_pm_set_max_sleep_time); +#undef MSM_PM_STATS_RESET +#endif /* CONFIG_MSM_IDLE_STATS */ static int __init msm_pm_init(void) { +#ifdef CONFIG_MSM_IDLE_STATS + struct proc_dir_entry *d_entry; +#endif + pm_power_off = msm_pm_power_off; arm_pm_restart = msm_pm_restart; msm_pm_max_sleep_time = 0; register_reboot_notifier(&msm_reboot_notifier); + msm_pm_sma.sleep_delay = smem_alloc(SMEM_SMSM_SLEEP_DELAY, + sizeof(*msm_pm_sma.sleep_delay)); + if (msm_pm_sma.sleep_delay == NULL) { + printk(KERN_ERR "msm_pm_init: failed get SLEEP_DELAY\n"); + return -ENODEV; + } + + msm_pm_sma.limit_sleep = smem_alloc(SMEM_SMSM_LIMIT_SLEEP, + sizeof(*msm_pm_sma.limit_sleep)); + if (msm_pm_sma.limit_sleep == NULL) { + printk(KERN_ERR "msm_pm_init: failed get LIMIT_SLEEP\n"); + return -ENODEV; + } + + msm_pm_sma.int_info_ext = smem_alloc(SMEM_SMSM_INT_INFO, + sizeof(*msm_pm_sma.int_info_ext)); + + if (msm_pm_sma.int_info_ext) + msm_pm_sma.int_info = (struct smsm_interrupt_info *) + msm_pm_sma.int_info_ext; + else + msm_pm_sma.int_info = smem_alloc(SMEM_SMSM_INT_INFO, + sizeof(*msm_pm_sma.int_info)); + + if (msm_pm_sma.int_info == NULL) { + printk(KERN_ERR "msm_pm_init: failed get INT_INFO\n"); + return -ENODEV; + } + +#if defined(CONFIG_ARCH_QSD) + /* The bootloader is responsible for initializing many of Scorpion's + * coprocessor registers for things like cache timing. The state of + * these coprocessor registers is lost on reset, so part of the + * bootloader must be re-executed. Do not overwrite the reset vector + * or bootloader area. + */ + msm_pm_reset_vector = PAGE_OFFSET; +#else msm_pm_reset_vector = ioremap(0, PAGE_SIZE); if (msm_pm_reset_vector == NULL) { printk(KERN_ERR "msm_pm_init: failed to map reset vector\n"); return -ENODEV; } +#endif /* CONFIG_ARCH_QSD */ + BUG_ON(msm_pm_modes == NULL); + + atomic_set(&msm_pm_init_done, 1); suspend_set_ops(&msm_pm_ops); #ifdef CONFIG_MSM_IDLE_STATS - create_proc_read_entry("msm_pm_stats", S_IRUGO, - NULL, msm_pm_read_proc, NULL); + d_entry = create_proc_entry("msm_pm_stats", + S_IRUGO | S_IWUSR | S_IWGRP, NULL); + if (d_entry) { + d_entry->read_proc = msm_pm_read_proc; + d_entry->write_proc = msm_pm_write_proc; + d_entry->data = NULL; + } #endif + return 0; } -__initcall(msm_pm_init); +void __init msm_pm_set_platform_data(struct msm_pm_platform_data *data) +{ + msm_pm_modes = data; +} + +late_initcall(msm_pm_init); diff --git a/arch/arm/mach-msm/pm.h b/arch/arm/mach-msm/pm.h index 159a7a610d75..b6e60e9683ce 100644 --- a/arch/arm/mach-msm/pm.h +++ b/arch/arm/mach-msm/pm.h @@ -1,6 +1,7 @@ /* arch/arm/mach-msm/pm.h * * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2009, Code Aurora Forum. All rights reserved. * Author: San Mehat * * This software is licensed under the terms of the GNU General Public @@ -17,15 +18,25 @@ #ifndef __ARCH_ARM_MACH_MSM_PM_H #define __ARCH_ARM_MACH_MSM_PM_H -#include +enum { + MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND, + MSM_PM_SLEEP_MODE_POWER_COLLAPSE, + MSM_PM_SLEEP_MODE_APPS_SLEEP, + MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT, + MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT, + MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN, + MSM_PM_SLEEP_MODE_NR +}; -#define A11S_CLK_SLEEP_EN_ADDR MSM_CSR_BASE + 0x11c +struct msm_pm_platform_data { + u8 supported; + u8 suspend_enabled; /* enabled for suspend */ + u8 idle_enabled; /* enabled for idle low power */ + u32 latency; /* interrupt latency in microseconds when entering + and exiting the low power mode */ + u32 residency; /* time threshold in microseconds beyond which + staying in the low power mode saves power */ +}; -#define CLK_SLEEP_EN_ARM11_CORE 0x01 -#define CLK_SLEEP_EN_ARM11_AHB 0x02 -#define CLK_SLEEP_EN_ID_BRIDGE 0x04 -#define CLK_SLEEP_EN_DMA_BRIDGE 0x08 -#define CLK_SLEEP_EN_PBUS 0x10 -#define CLK_SLEEP_EN_DEBUG_TIME 0x20 -#define CLK_SLEEP_EN_GP_TIMER 0x40 +void msm_pm_set_platform_data(struct msm_pm_platform_data *data); #endif diff --git a/arch/arm/mach-msm/pm2.c b/arch/arm/mach-msm/pm2.c new file mode 100644 index 000000000000..faef1daef944 --- /dev/null +++ b/arch/arm/mach-msm/pm2.c @@ -0,0 +1,1606 @@ +/* arch/arm/mach-msm/pm2.c + * + * MSM Power Management Routines + * + * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 +#ifdef CONFIG_CACHE_L2X0 +#include +#endif + +#include "smd_private.h" +#include "acpuclock.h" +#include "clock.h" +#include "proc_comm.h" +#include "idle.h" +#include "irq.h" +#include "gpio.h" +#include "timer.h" +#include "pm.h" + +/****************************************************************************** + * Debug Definitions + *****************************************************************************/ + +enum { + MSM_PM_DEBUG_SUSPEND = 1U << 0, + MSM_PM_DEBUG_POWER_COLLAPSE = 1U << 1, + MSM_PM_DEBUG_STATE = 1U << 2, + MSM_PM_DEBUG_CLOCK = 1U << 3, + MSM_PM_DEBUG_RESET_VECTOR = 1U << 4, + MSM_PM_DEBUG_SMSM_STATE = 1U << 5, + MSM_PM_DEBUG_IDLE = 1U << 6, +}; + +static int msm_pm_debug_mask; +module_param_named( + debug_mask, msm_pm_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP +); + +#define MSM_PM_DPRINTK(mask, level, message, ...) \ + do { \ + if ((mask) & msm_pm_debug_mask) \ + printk(level message, ## __VA_ARGS__); \ + } while (0) + +#define MSM_PM_DEBUG_PRINT_STATE(tag) \ + do { \ + MSM_PM_DPRINTK(MSM_PM_DEBUG_STATE, \ + KERN_INFO, "%s: " \ + "APPS_CLK_SLEEP_EN %x, APPS_PWRDOWN %x, " \ + "SMSM_POWER_MASTER_DEM %x, SMSM_MODEM_STATE %x, " \ + "SMSM_APPS_DEM %x\n", \ + tag, \ + readl(APPS_CLK_SLEEP_EN), readl(APPS_PWRDOWN), \ + smsm_get_state(SMSM_POWER_MASTER_DEM), \ + smsm_get_state(SMSM_MODEM_STATE), \ + smsm_get_state(SMSM_APPS_DEM)); \ + } while (0) + +#define MSM_PM_DEBUG_PRINT_SLEEP_INFO() \ + do { \ + if (msm_pm_debug_mask & MSM_PM_DEBUG_SMSM_STATE) \ + smsm_print_sleep_info(msm_pm_smem_data->sleep_time, \ + msm_pm_smem_data->resources_used, \ + msm_pm_smem_data->irq_mask, \ + msm_pm_smem_data->wakeup_reason, \ + msm_pm_smem_data->pending_irqs); \ + } while (0) + + +/****************************************************************************** + * Sleep Modes and Parameters + *****************************************************************************/ + +static int msm_pm_sleep_mode = CONFIG_MSM7X00A_SLEEP_MODE; +module_param_named( + sleep_mode, msm_pm_sleep_mode, + int, S_IRUGO | S_IWUSR | S_IWGRP +); + +static int msm_pm_idle_sleep_mode = CONFIG_MSM7X00A_IDLE_SLEEP_MODE; +module_param_named( + idle_sleep_mode, msm_pm_idle_sleep_mode, + int, S_IRUGO | S_IWUSR | S_IWGRP +); + +static int msm_pm_idle_sleep_min_time = CONFIG_MSM7X00A_IDLE_SLEEP_MIN_TIME; +module_param_named( + idle_sleep_min_time, msm_pm_idle_sleep_min_time, + int, S_IRUGO | S_IWUSR | S_IWGRP +); + +#define MSM_PM_MODE_ATTR_SUSPEND_ENABLED "suspend_enabled" +#define MSM_PM_MODE_ATTR_IDLE_ENABLED "idle_enabled" +#define MSM_PM_MODE_ATTR_LATENCY "latency" +#define MSM_PM_MODE_ATTR_RESIDENCY "residency" +#define MSM_PM_MODE_ATTR_NR (4) + +static char *msm_pm_sleep_mode_labels[MSM_PM_SLEEP_MODE_NR] = { + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND] = " ", + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE] = "power_collapse", + [MSM_PM_SLEEP_MODE_APPS_SLEEP] = "apps_sleep", + [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT] = + "ramp_down_and_wfi", + [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT] = "wfi", + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN] = + "power_collapse_no_xo_shutdown", +}; + +static struct msm_pm_platform_data *msm_pm_modes; + +static struct kobject *msm_pm_mode_kobjs[MSM_PM_SLEEP_MODE_NR]; +static struct attribute_group *msm_pm_mode_attr_group[MSM_PM_SLEEP_MODE_NR]; +static struct attribute **msm_pm_mode_attrs[MSM_PM_SLEEP_MODE_NR]; +static struct kobj_attribute *msm_pm_mode_kobj_attrs[MSM_PM_SLEEP_MODE_NR]; + +/* + * Write out the attribute. + */ +static ssize_t msm_pm_mode_attr_show( + struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + int ret = -EINVAL; + int i; + + for (i = 0; i < MSM_PM_SLEEP_MODE_NR; i++) { + struct kernel_param kp; + + if (strcmp(kobj->name, msm_pm_sleep_mode_labels[i])) + continue; + + if (!strcmp(attr->attr.name, + MSM_PM_MODE_ATTR_SUSPEND_ENABLED)) { + u32 arg = msm_pm_modes[i].suspend_enabled; + kp.arg = &arg; + ret = param_get_ulong(buf, &kp); + } else if (!strcmp(attr->attr.name, + MSM_PM_MODE_ATTR_IDLE_ENABLED)) { + u32 arg = msm_pm_modes[i].idle_enabled; + kp.arg = &arg; + ret = param_get_ulong(buf, &kp); + } else if (!strcmp(attr->attr.name, + MSM_PM_MODE_ATTR_LATENCY)) { + kp.arg = &msm_pm_modes[i].latency; + ret = param_get_ulong(buf, &kp); + } else if (!strcmp(attr->attr.name, + MSM_PM_MODE_ATTR_RESIDENCY)) { + kp.arg = &msm_pm_modes[i].residency; + ret = param_get_ulong(buf, &kp); + } + + break; + } + + if (ret > 0) { + strcat(buf, "\n"); + ret++; + } + + return ret; +} + +/* + * Read in the new attribute value. + */ +static ssize_t msm_pm_mode_attr_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count) +{ + int ret = -EINVAL; + int i; + + for (i = 0; i < MSM_PM_SLEEP_MODE_NR; i++) { + struct kernel_param kp; + + if (strcmp(kobj->name, msm_pm_sleep_mode_labels[i])) + continue; + + if (!strcmp(attr->attr.name, + MSM_PM_MODE_ATTR_SUSPEND_ENABLED)) { + kp.arg = &msm_pm_modes[i].suspend_enabled; + ret = param_set_byte(buf, &kp); + } else if (!strcmp(attr->attr.name, + MSM_PM_MODE_ATTR_IDLE_ENABLED)) { + kp.arg = &msm_pm_modes[i].idle_enabled; + ret = param_set_byte(buf, &kp); + } else if (!strcmp(attr->attr.name, + MSM_PM_MODE_ATTR_LATENCY)) { + kp.arg = &msm_pm_modes[i].latency; + ret = param_set_ulong(buf, &kp); + } else if (!strcmp(attr->attr.name, + MSM_PM_MODE_ATTR_RESIDENCY)) { + kp.arg = &msm_pm_modes[i].residency; + ret = param_set_ulong(buf, &kp); + } + + break; + } + + return ret ? ret : count; +} + +/* + * Add sysfs entries for the sleep modes. + */ +static int __init msm_pm_mode_sysfs_add(void) +{ + struct kobject *module_kobj = NULL; + struct kobject *modes_kobj = NULL; + + struct kobject *kobj; + struct attribute_group *attr_group; + struct attribute **attrs; + struct kobj_attribute *kobj_attrs; + + int i, k; + int ret; + + module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME); + if (!module_kobj) { + printk(KERN_ERR "%s: cannot find kobject for module %s\n", + __func__, KBUILD_MODNAME); + ret = -ENOENT; + goto mode_sysfs_add_cleanup; + } + + modes_kobj = kobject_create_and_add("modes", module_kobj); + if (!modes_kobj) { + printk(KERN_ERR "%s: cannot create modes kobject\n", __func__); + ret = -ENOMEM; + goto mode_sysfs_add_cleanup; + } + + for (i = 0; i < ARRAY_SIZE(msm_pm_mode_kobjs); i++) { + if (!msm_pm_modes[i].supported) + continue; + + kobj = kobject_create_and_add( + msm_pm_sleep_mode_labels[i], modes_kobj); + attr_group = kzalloc(sizeof(*attr_group), GFP_KERNEL); + attrs = kzalloc(sizeof(*attrs) * (MSM_PM_MODE_ATTR_NR + 1), + GFP_KERNEL); + kobj_attrs = kzalloc(sizeof(*kobj_attrs) * MSM_PM_MODE_ATTR_NR, + GFP_KERNEL); + + if (!kobj || !attr_group || !attrs || !kobj_attrs) { + printk(KERN_ERR + "%s: cannot create kobject or attributes\n", + __func__); + ret = -ENOMEM; + goto mode_sysfs_add_abort; + } + + kobj_attrs[0].attr.name = MSM_PM_MODE_ATTR_SUSPEND_ENABLED; + kobj_attrs[1].attr.name = MSM_PM_MODE_ATTR_IDLE_ENABLED; + kobj_attrs[2].attr.name = MSM_PM_MODE_ATTR_LATENCY; + kobj_attrs[3].attr.name = MSM_PM_MODE_ATTR_RESIDENCY; + + for (k = 0; k < MSM_PM_MODE_ATTR_NR; k++) { + kobj_attrs[k].attr.mode = 0644; + kobj_attrs[k].show = msm_pm_mode_attr_show; + kobj_attrs[k].store = msm_pm_mode_attr_store; + + attrs[k] = &kobj_attrs[k].attr; + } + attrs[MSM_PM_MODE_ATTR_NR] = NULL; + + attr_group->attrs = attrs; + ret = sysfs_create_group(kobj, attr_group); + if (ret) { + printk(KERN_ERR + "%s: cannot create kobject attribute group\n", + __func__); + goto mode_sysfs_add_abort; + } + + msm_pm_mode_kobjs[i] = kobj; + msm_pm_mode_attr_group[i] = attr_group; + msm_pm_mode_attrs[i] = attrs; + msm_pm_mode_kobj_attrs[i] = kobj_attrs; + } + + return 0; + +mode_sysfs_add_abort: + kfree(kobj_attrs); + kfree(attrs); + kfree(attr_group); + kobject_put(kobj); + +mode_sysfs_add_cleanup: + for (i = ARRAY_SIZE(msm_pm_mode_kobjs) - 1; i >= 0; i--) { + if (!msm_pm_mode_kobjs[i]) + continue; + + sysfs_remove_group( + msm_pm_mode_kobjs[i], msm_pm_mode_attr_group[i]); + + kfree(msm_pm_mode_kobj_attrs[i]); + kfree(msm_pm_mode_attrs[i]); + kfree(msm_pm_mode_attr_group[i]); + kobject_put(msm_pm_mode_kobjs[i]); + } + + return ret; +} + +void __init msm_pm_set_platform_data(struct msm_pm_platform_data *data) +{ + msm_pm_modes = data; +} + + +/****************************************************************************** + * Sleep Limitations + *****************************************************************************/ +enum { + SLEEP_LIMIT_NONE = 0, + SLEEP_LIMIT_NO_TCXO_SHUTDOWN = 2 +}; + + +/****************************************************************************** + * Configure Hardware for Power Down/Up + *****************************************************************************/ + +#define APPS_CLK_SLEEP_EN (MSM_CSR_BASE + 0x11c) +#define APPS_PWRDOWN (MSM_CSR_BASE + 0x440) +#define APPS_STANDBY_CTL (MSM_CSR_BASE + 0x108) + +/* + * Configure hardware registers in preparation for Apps power down. + */ +static void msm_pm_config_hw_before_power_down(void) +{ + writel(0x1f, APPS_CLK_SLEEP_EN); + writel(1, APPS_PWRDOWN); + writel(0, APPS_STANDBY_CTL); +} + +/* + * Clear hardware registers after Apps powers up. + */ +static void msm_pm_config_hw_after_power_up(void) +{ + writel(0x00, APPS_CLK_SLEEP_EN); + writel(0, APPS_PWRDOWN); +} + + +/****************************************************************************** + * State Polling Definitions + *****************************************************************************/ + +struct msm_pm_polled_group { + uint32_t group_id; + + uint32_t bits_all_set; + uint32_t bits_all_clear; + uint32_t bits_any_set; + uint32_t bits_any_clear; + + uint32_t value_read; +}; + +/* + * Return true if all bits indicated by flag are set in source. + */ +static inline bool msm_pm_all_set(uint32_t source, uint32_t flag) +{ + return (source & flag) == flag; +} + +/* + * Return true if any bit indicated by flag are set in source. + */ +static inline bool msm_pm_any_set(uint32_t source, uint32_t flag) +{ + return !flag || (source & flag); +} + +/* + * Return true if all bits indicated by flag are cleared in source. + */ +static inline bool msm_pm_all_clear(uint32_t source, uint32_t flag) +{ + return (~source & flag) == flag; +} + +/* + * Return true if any bit indicated by flag are cleared in source. + */ +static inline bool msm_pm_any_clear(uint32_t source, uint32_t flag) +{ + return !flag || (~source & flag); +} + +/* + * Poll the shared memory states as indicated by the poll groups. + * + * nr_grps: number of groups in the array + * grps: array of groups + * + * The function returns when conditions specified by any of the poll + * groups become true. The conditions specified by a poll group are + * deemed true when 1) at least one bit from bits_any_set is set OR one + * bit from bits_any_clear is cleared; and 2) all bits in bits_all_set + * are set; and 3) all bits in bits_all_clear are cleared. + * + * Return value: + * >=0: index of the poll group whose conditions have become true + * -ETIMEDOUT: timed out + */ +static int msm_pm_poll_state(int nr_grps, struct msm_pm_polled_group *grps) +{ + int i, k; + + for (i = 0; i < 100000; i++) + for (k = 0; k < nr_grps; k++) { + bool all_set, all_clear; + bool any_set, any_clear; + + grps[k].value_read = smsm_get_state(grps[k].group_id); + + all_set = msm_pm_all_set(grps[k].value_read, + grps[k].bits_all_set); + all_clear = msm_pm_all_clear(grps[k].value_read, + grps[k].bits_all_clear); + any_set = msm_pm_any_set(grps[k].value_read, + grps[k].bits_any_set); + any_clear = msm_pm_any_clear(grps[k].value_read, + grps[k].bits_any_clear); + + if (all_set && all_clear && (any_set || any_clear)) + return k; + } + + printk(KERN_ERR "%s failed:\n", __func__); + for (k = 0; k < nr_grps; k++) + printk(KERN_ERR "(%x, %x, %x, %x) %x\n", + grps[k].bits_all_set, grps[k].bits_all_clear, + grps[k].bits_any_set, grps[k].bits_any_clear, + grps[k].value_read); + + return -ETIMEDOUT; +} + + +/****************************************************************************** + * Suspend Max Sleep Time + *****************************************************************************/ + +#define SCLK_HZ (32768) +#define MSM_PM_SLEEP_TICK_LIMIT (0x6DDD000) + +#ifdef CONFIG_MSM_SLEEP_TIME_OVERRIDE +static int msm_pm_sleep_time_override; +module_param_named(sleep_time_override, + msm_pm_sleep_time_override, int, S_IRUGO | S_IWUSR | S_IWGRP); +#endif + +static uint32_t msm_pm_max_sleep_time; + +/* + * Convert time from nanoseconds to slow clock ticks, then cap it to the + * specified limit + */ +static int64_t msm_pm_convert_and_cap_time(int64_t time_ns, int64_t limit) +{ + do_div(time_ns, NSEC_PER_SEC / SCLK_HZ); + return (time_ns > limit) ? limit : time_ns; +} + +/* + * Set the sleep time for suspend. 0 means infinite sleep time. + */ +void msm_pm_set_max_sleep_time(int64_t max_sleep_time_ns) +{ + unsigned long flags; + + local_irq_save(flags); + if (max_sleep_time_ns == 0) { + msm_pm_max_sleep_time = 0; + } else { + msm_pm_max_sleep_time = (uint32_t)msm_pm_convert_and_cap_time( + max_sleep_time_ns, MSM_PM_SLEEP_TICK_LIMIT); + + if (msm_pm_max_sleep_time == 0) + msm_pm_max_sleep_time = 1; + } + + MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND, KERN_INFO, + "%s(): Requested %lld ns Giving %u sclk ticks\n", __func__, + max_sleep_time_ns, msm_pm_max_sleep_time); + local_irq_restore(flags); +} +EXPORT_SYMBOL(msm_pm_set_max_sleep_time); + + +/****************************************************************************** + * CONFIG_MSM_IDLE_STATS + *****************************************************************************/ + +#ifdef CONFIG_MSM_IDLE_STATS +enum msm_pm_time_stats_id { + MSM_PM_STAT_REQUESTED_IDLE, + MSM_PM_STAT_IDLE_SPIN, + MSM_PM_STAT_IDLE_WFI, + MSM_PM_STAT_IDLE_SLEEP, + MSM_PM_STAT_IDLE_FAILED_SLEEP, + MSM_PM_STAT_IDLE_POWER_COLLAPSE, + MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE, + MSM_PM_STAT_SUSPEND, + MSM_PM_STAT_FAILED_SUSPEND, + MSM_PM_STAT_NOT_IDLE, + MSM_PM_STAT_COUNT +}; + +static struct msm_pm_time_stats { + const char *name; + int64_t first_bucket_time; + int bucket[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT]; + int64_t min_time[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT]; + int64_t max_time[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT]; + int count; + int64_t total_time; +} msm_pm_stats[MSM_PM_STAT_COUNT] = { + [MSM_PM_STAT_REQUESTED_IDLE].name = "idle-request", + [MSM_PM_STAT_REQUESTED_IDLE].first_bucket_time = + CONFIG_MSM_IDLE_STATS_FIRST_BUCKET, + + [MSM_PM_STAT_IDLE_SPIN].name = "idle-spin", + [MSM_PM_STAT_IDLE_SPIN].first_bucket_time = + CONFIG_MSM_IDLE_STATS_FIRST_BUCKET, + + [MSM_PM_STAT_IDLE_WFI].name = "idle-wfi", + [MSM_PM_STAT_IDLE_WFI].first_bucket_time = + CONFIG_MSM_IDLE_STATS_FIRST_BUCKET, + + [MSM_PM_STAT_IDLE_SLEEP].name = "idle-sleep", + [MSM_PM_STAT_IDLE_SLEEP].first_bucket_time = + CONFIG_MSM_IDLE_STATS_FIRST_BUCKET, + + [MSM_PM_STAT_IDLE_FAILED_SLEEP].name = "idle-failed-sleep", + [MSM_PM_STAT_IDLE_FAILED_SLEEP].first_bucket_time = + CONFIG_MSM_IDLE_STATS_FIRST_BUCKET, + + [MSM_PM_STAT_IDLE_POWER_COLLAPSE].name = "idle-power-collapse", + [MSM_PM_STAT_IDLE_POWER_COLLAPSE].first_bucket_time = + CONFIG_MSM_IDLE_STATS_FIRST_BUCKET, + + [MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE].name = + "idle-failed-power-collapse", + [MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE].first_bucket_time = + CONFIG_MSM_IDLE_STATS_FIRST_BUCKET, + + [MSM_PM_STAT_SUSPEND].name = "suspend", + [MSM_PM_STAT_SUSPEND].first_bucket_time = + CONFIG_MSM_SUSPEND_STATS_FIRST_BUCKET, + + [MSM_PM_STAT_FAILED_SUSPEND].name = "failed-suspend", + [MSM_PM_STAT_FAILED_SUSPEND].first_bucket_time = + CONFIG_MSM_IDLE_STATS_FIRST_BUCKET, + + [MSM_PM_STAT_NOT_IDLE].name = "not-idle", + [MSM_PM_STAT_NOT_IDLE].first_bucket_time = + CONFIG_MSM_IDLE_STATS_FIRST_BUCKET, +}; + +static uint32_t msm_pm_sleep_limit = SLEEP_LIMIT_NONE; +static DECLARE_BITMAP(msm_pm_clocks_no_tcxo_shutdown, NR_CLKS); + +/* + * Add the given time data to the statistics collection. + */ +static void msm_pm_add_stat(enum msm_pm_time_stats_id id, int64_t t) +{ + int i; + int64_t bt; + + msm_pm_stats[id].total_time += t; + msm_pm_stats[id].count++; + + bt = t; + do_div(bt, msm_pm_stats[id].first_bucket_time); + + if (bt < 1ULL << (CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT * + (CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1))) + i = DIV_ROUND_UP(fls((uint32_t)bt), + CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT); + else + i = CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1; + + msm_pm_stats[id].bucket[i]++; + + if (t < msm_pm_stats[id].min_time[i] || !msm_pm_stats[id].max_time[i]) + msm_pm_stats[id].min_time[i] = t; + if (t > msm_pm_stats[id].max_time[i]) + msm_pm_stats[id].max_time[i] = t; +} + +/* + * Helper function of snprintf where buf is auto-incremented, size is auto- + * decremented, and there is no return value. + * + * NOTE: buf and size must be l-values (e.g. variables) + */ +#define SNPRINTF(buf, size, format, ...) \ + do { \ + if (size > 0) { \ + int ret; \ + ret = snprintf(buf, size, format, ## __VA_ARGS__); \ + if (ret > size) { \ + buf += size; \ + size = 0; \ + } else { \ + buf += ret; \ + size -= ret; \ + } \ + } \ + } while (0) + +/* + * Write out the power management statistics. + */ +static int msm_pm_read_proc + (char *page, char **start, off_t off, int count, int *eof, void *data) +{ + int i; + char *p = page; + char clk_name[16]; + + if (count < 1024) { + *start = (char *) 0; + *eof = 0; + return 0; + } + + if (!off) { + SNPRINTF(p, count, "Clocks against last TCXO shutdown:\n"); + for_each_bit(i, msm_pm_clocks_no_tcxo_shutdown, NR_CLKS) { + clk_name[0] = '\0'; + msm_clock_get_name(i, clk_name, sizeof(clk_name)); + SNPRINTF(p, count, " %s (id=%d)\n", clk_name, i); + } + + SNPRINTF(p, count, "Last power collapse voted "); + if (msm_pm_sleep_limit == SLEEP_LIMIT_NONE) + SNPRINTF(p, count, "for TCXO shutdown\n\n"); + else + SNPRINTF(p, count, "against TCXO shutdown\n\n"); + + *start = (char *) 1; + *eof = 0; + } else if (--off < ARRAY_SIZE(msm_pm_stats)) { + int64_t bucket_time; + int64_t s; + uint32_t ns; + + s = msm_pm_stats[off].total_time; + ns = do_div(s, NSEC_PER_SEC); + SNPRINTF(p, count, + "%s:\n" + " count: %7d\n" + " total_time: %lld.%09u\n", + msm_pm_stats[off].name, + msm_pm_stats[off].count, + s, ns); + + bucket_time = msm_pm_stats[off].first_bucket_time; + for (i = 0; i < CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1; i++) { + s = bucket_time; + ns = do_div(s, NSEC_PER_SEC); + SNPRINTF(p, count, + " <%6lld.%09u: %7d (%lld-%lld)\n", + s, ns, msm_pm_stats[off].bucket[i], + msm_pm_stats[off].min_time[i], + msm_pm_stats[off].max_time[i]); + + bucket_time <<= CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT; + } + + SNPRINTF(p, count, " >=%6lld.%09u: %7d (%lld-%lld)\n", + s, ns, msm_pm_stats[off].bucket[i], + msm_pm_stats[off].min_time[i], + msm_pm_stats[off].max_time[i]); + + *start = (char *) 1; + *eof = (off + 1 >= ARRAY_SIZE(msm_pm_stats)); + } + + return p - page; +} +#undef SNPRINTF + +#define MSM_PM_STATS_RESET "reset" + +/* + * Reset the power management statistics values. + */ +static int msm_pm_write_proc(struct file *file, const char __user *buffer, + unsigned long count, void *data) +{ + char buf[sizeof(MSM_PM_STATS_RESET)]; + int ret; + unsigned long flags; + int i; + + if (count < strlen(MSM_PM_STATS_RESET)) { + ret = -EINVAL; + goto write_proc_failed; + } + + if (copy_from_user(buf, buffer, strlen(MSM_PM_STATS_RESET))) { + ret = -EFAULT; + goto write_proc_failed; + } + + if (memcmp(buf, MSM_PM_STATS_RESET, strlen(MSM_PM_STATS_RESET))) { + ret = -EINVAL; + goto write_proc_failed; + } + + local_irq_save(flags); + for (i = 0; i < ARRAY_SIZE(msm_pm_stats); i++) { + memset(msm_pm_stats[i].bucket, + 0, sizeof(msm_pm_stats[i].bucket)); + memset(msm_pm_stats[i].min_time, + 0, sizeof(msm_pm_stats[i].min_time)); + memset(msm_pm_stats[i].max_time, + 0, sizeof(msm_pm_stats[i].max_time)); + msm_pm_stats[i].count = 0; + msm_pm_stats[i].total_time = 0; + } + + msm_pm_sleep_limit = SLEEP_LIMIT_NONE; + bitmap_zero(msm_pm_clocks_no_tcxo_shutdown, NR_CLKS); + local_irq_restore(flags); + + return count; + +write_proc_failed: + return ret; +} +#undef MSM_PM_STATS_RESET +#endif /* CONFIG_MSM_IDLE_STATS */ + + +/****************************************************************************** + * Shared Memory Bits + *****************************************************************************/ + +#define DEM_MASTER_BITS_PER_CPU 5 + +/* Power Master State Bits - Per CPU */ +#define DEM_MASTER_SMSM_RUN \ + (0x01UL << (DEM_MASTER_BITS_PER_CPU * SMSM_APPS_STATE)) +#define DEM_MASTER_SMSM_RSA \ + (0x02UL << (DEM_MASTER_BITS_PER_CPU * SMSM_APPS_STATE)) +#define DEM_MASTER_SMSM_PWRC_EARLY_EXIT \ + (0x04UL << (DEM_MASTER_BITS_PER_CPU * SMSM_APPS_STATE)) +#define DEM_MASTER_SMSM_SLEEP_EXIT \ + (0x08UL << (DEM_MASTER_BITS_PER_CPU * SMSM_APPS_STATE)) +#define DEM_MASTER_SMSM_READY \ + (0x10UL << (DEM_MASTER_BITS_PER_CPU * SMSM_APPS_STATE)) + +/* Power Slave State Bits */ +#define DEM_SLAVE_SMSM_RUN (0x0001) +#define DEM_SLAVE_SMSM_PWRC (0x0002) +#define DEM_SLAVE_SMSM_PWRC_DELAY (0x0004) +#define DEM_SLAVE_SMSM_PWRC_EARLY_EXIT (0x0008) +#define DEM_SLAVE_SMSM_WFPI (0x0010) +#define DEM_SLAVE_SMSM_SLEEP (0x0020) +#define DEM_SLAVE_SMSM_SLEEP_EXIT (0x0040) +#define DEM_SLAVE_SMSM_MSGS_REDUCED (0x0080) +#define DEM_SLAVE_SMSM_RESET (0x0100) +#define DEM_SLAVE_SMSM_PWRC_SUSPEND (0x0200) + +/* Time Slave State Bits */ +#define DEM_TIME_SLAVE_TIME_REQUEST (0x0400) +#define DEM_TIME_SLAVE_TIME_POLL (0x0800) +#define DEM_TIME_SLAVE_TIME_INIT (0x1000) + + +/****************************************************************************** + * Shared Memory Data + *****************************************************************************/ + +#define DEM_MAX_PORT_NAME_LEN (20) + +struct msm_pm_smem_t { + uint32_t sleep_time; + uint32_t irq_mask; + uint32_t resources_used; + uint32_t reserved1; + + uint32_t wakeup_reason; + uint32_t pending_irqs; + uint32_t rpc_prog; + uint32_t rpc_proc; + char smd_port_name[DEM_MAX_PORT_NAME_LEN]; + uint32_t reserved2; +}; + + +/****************************************************************************** + * + *****************************************************************************/ +static struct msm_pm_smem_t *msm_pm_smem_data; +static uint32_t *msm_pm_reset_vector; +static atomic_t msm_pm_init_done = ATOMIC_INIT(0); + +/* + * Power collapse the Apps processor. This function executes the handshake + * protocol with Modem. + * + * Return value: + * -EAGAIN: modem reset occurred or early exit from power collapse + * -EBUSY: modem not ready for our power collapse -- no power loss + * -ETIMEDOUT: timed out waiting for modem's handshake -- no power loss + * 0: success + */ +static int msm_pm_power_collapse + (bool from_idle, uint32_t sleep_delay, uint32_t sleep_limit) +{ + struct msm_pm_polled_group state_grps[2]; + unsigned long saved_acpuclk_rate; + uint32_t saved_vector[2]; + int collapsed = 0; + int ret; +#ifdef CONFIG_MSM_ADM_OFF_AT_POWER_COLLAPSE + unsigned id; +#endif + + MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE, + KERN_INFO, "%s(): idle %d, delay %u, limit %u\n", __func__, + (int)from_idle, sleep_delay, sleep_limit); + + if (!(smsm_get_state(SMSM_POWER_MASTER_DEM) & DEM_MASTER_SMSM_READY)) { + MSM_PM_DPRINTK( + MSM_PM_DEBUG_SUSPEND | MSM_PM_DEBUG_POWER_COLLAPSE, + KERN_INFO, "%s(): master not ready\n", __func__); + ret = -EBUSY; + goto power_collapse_bail; + } + + memset(msm_pm_smem_data, 0, sizeof(*msm_pm_smem_data)); + + msm_irq_enter_sleep1(true, from_idle, &msm_pm_smem_data->irq_mask); + msm_gpio_enter_sleep(from_idle); + + msm_pm_smem_data->sleep_time = sleep_delay; + msm_pm_smem_data->resources_used = sleep_limit; + + smsm_change_state(SMSM_APPS_DEM, + DEM_TIME_SLAVE_TIME_REQUEST | DEM_TIME_SLAVE_TIME_POLL, + DEM_TIME_SLAVE_TIME_INIT); + + /* Enter PWRC/PWRC_SUSPEND */ + + if (from_idle) + smsm_change_state(SMSM_APPS_DEM, DEM_SLAVE_SMSM_RUN, + DEM_SLAVE_SMSM_PWRC); + else + smsm_change_state(SMSM_APPS_DEM, DEM_SLAVE_SMSM_RUN, + DEM_SLAVE_SMSM_PWRC | DEM_SLAVE_SMSM_PWRC_SUSPEND); + + MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): PWRC"); + MSM_PM_DEBUG_PRINT_SLEEP_INFO(); + + memset(state_grps, 0, sizeof(state_grps)); + state_grps[0].group_id = SMSM_POWER_MASTER_DEM; + state_grps[0].bits_all_set = DEM_MASTER_SMSM_RSA; + state_grps[1].group_id = SMSM_MODEM_STATE; + state_grps[1].bits_all_set = SMSM_RESET; + + ret = msm_pm_poll_state(ARRAY_SIZE(state_grps), state_grps); + + if (ret < 0) { + MSM_PM_DPRINTK( + MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE, + KERN_INFO, + "%s(): msm_pm_poll_state failed, %d\n", __func__, ret); + goto power_collapse_restore_gpio_bail; + } + + if (ret == 1) { + MSM_PM_DPRINTK( + MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE, + KERN_INFO, + "%s(): msm_pm_poll_state detected Modem reset\n", + __func__); + ret = -EAGAIN; + goto power_collapse_restore_gpio_bail; + } + + /* DEM Master in RSA */ + + MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): PWRC RSA"); + + ret = msm_irq_enter_sleep2(true, from_idle); + if (ret < 0) { + MSM_PM_DPRINTK( + MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE, + KERN_INFO, + "%s(): msm_irq_enter_sleep2 aborted, %d\n", __func__, + ret); + goto power_collapse_early_exit; + } + +#ifdef CONFIG_MSM_ADM_OFF_AT_POWER_COLLAPSE + id = ADM_CLK; + msm_proc_comm(PCOM_CLKCTL_RPC_DISABLE, &id, NULL); +#endif + + msm_pm_config_hw_before_power_down(); + MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): pre power down"); + + saved_acpuclk_rate = acpuclk_power_collapse(); + MSM_PM_DPRINTK(MSM_PM_DEBUG_CLOCK, KERN_INFO, + "%s(): change clock rate (old rate = %lu)\n", __func__, + saved_acpuclk_rate); + + if (saved_acpuclk_rate == 0) { + msm_pm_config_hw_after_power_up(); + goto power_collapse_early_exit; + } + + saved_vector[0] = msm_pm_reset_vector[0]; + saved_vector[1] = msm_pm_reset_vector[1]; + msm_pm_reset_vector[0] = 0xE51FF004; /* ldr pc, 4 */ + msm_pm_reset_vector[1] = virt_to_phys(msm_pm_collapse_exit); + + MSM_PM_DPRINTK(MSM_PM_DEBUG_RESET_VECTOR, KERN_INFO, + "%s(): vector %x %x -> %x %x\n", __func__, + saved_vector[0], saved_vector[1], + msm_pm_reset_vector[0], msm_pm_reset_vector[1]); + +#ifdef CONFIG_CACHE_L2X0 + l2x0_suspend(); +#endif + + collapsed = msm_pm_collapse(); + +#ifdef CONFIG_CACHE_L2X0 + l2x0_resume(collapsed); +#endif + + msm_pm_reset_vector[0] = saved_vector[0]; + msm_pm_reset_vector[1] = saved_vector[1]; + + if (collapsed) { + cpu_init(); + local_fiq_enable(); + } + + MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND | MSM_PM_DEBUG_POWER_COLLAPSE, + KERN_INFO, + "%s(): msm_pm_collapse returned %d\n", __func__, collapsed); + + MSM_PM_DPRINTK(MSM_PM_DEBUG_CLOCK, KERN_INFO, + "%s(): restore clock rate to %lu\n", __func__, + saved_acpuclk_rate); + if (acpuclk_set_rate(saved_acpuclk_rate, SETRATE_PC) < 0) + printk(KERN_ERR "%s(): failed to restore clock rate(%lu)\n", + __func__, saved_acpuclk_rate); + +#ifdef CONFIG_MSM_ADM_OFF_AT_POWER_COLLAPSE + id = ADM_CLK; + if (msm_proc_comm(PCOM_CLKCTL_RPC_ENABLE, &id, NULL) < 0 || id < 0) + printk(KERN_ERR + "%s(): failed to turn on ADM clock\n", __func__); +#endif + + msm_irq_exit_sleep1(msm_pm_smem_data->irq_mask, + msm_pm_smem_data->wakeup_reason, + msm_pm_smem_data->pending_irqs); + + msm_pm_config_hw_after_power_up(); + MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): post power up"); + + do { + memset(state_grps, 0, sizeof(state_grps)); + state_grps[0].group_id = SMSM_POWER_MASTER_DEM; + state_grps[0].bits_any_set = + DEM_MASTER_SMSM_RSA | DEM_MASTER_SMSM_PWRC_EARLY_EXIT; + state_grps[1].group_id = SMSM_MODEM_STATE; + state_grps[1].bits_all_set = SMSM_RESET; + + ret = msm_pm_poll_state(ARRAY_SIZE(state_grps), state_grps); + } while (ret < 0); + + if (ret == 1) { + MSM_PM_DPRINTK( + MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE, + KERN_INFO, + "%s(): msm_pm_poll_state detected Modem reset\n", + __func__); + ret = -EAGAIN; + goto power_collapse_restore_gpio_bail; + } + + /* Sanity check */ + if (collapsed) { + BUG_ON(!(state_grps[0].value_read & DEM_MASTER_SMSM_RSA)); + } else { + BUG_ON(!(state_grps[0].value_read & + DEM_MASTER_SMSM_PWRC_EARLY_EXIT)); + goto power_collapse_early_exit; + } + + /* Enter WFPI */ + + smsm_change_state(SMSM_APPS_DEM, + DEM_SLAVE_SMSM_PWRC | DEM_SLAVE_SMSM_PWRC_SUSPEND, + DEM_SLAVE_SMSM_WFPI); + + MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): WFPI"); + + do { + memset(state_grps, 0, sizeof(state_grps)); + state_grps[0].group_id = SMSM_POWER_MASTER_DEM; + state_grps[0].bits_all_set = DEM_MASTER_SMSM_RUN; + state_grps[1].group_id = SMSM_MODEM_STATE; + state_grps[1].bits_all_set = SMSM_RESET; + + ret = msm_pm_poll_state(ARRAY_SIZE(state_grps), state_grps); + } while (ret < 0); + + if (ret == 1) { + MSM_PM_DPRINTK( + MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE, + KERN_INFO, + "%s(): msm_pm_poll_state detected Modem reset\n", + __func__); + ret = -EAGAIN; + goto power_collapse_restore_gpio_bail; + } + + /* DEM Master == RUN */ + + MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): WFPI RUN"); + MSM_PM_DEBUG_PRINT_SLEEP_INFO(); + + msm_irq_exit_sleep2(msm_pm_smem_data->irq_mask, + msm_pm_smem_data->wakeup_reason, + msm_pm_smem_data->pending_irqs); + msm_irq_exit_sleep3(msm_pm_smem_data->irq_mask, + msm_pm_smem_data->wakeup_reason, + msm_pm_smem_data->pending_irqs); + msm_gpio_exit_sleep(); + + smsm_change_state(SMSM_APPS_DEM, + DEM_SLAVE_SMSM_WFPI, DEM_SLAVE_SMSM_RUN); + + MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): RUN"); + + smd_sleep_exit(); + return 0; + +power_collapse_early_exit: + /* Enter PWRC_EARLY_EXIT */ + + smsm_change_state(SMSM_APPS_DEM, + DEM_SLAVE_SMSM_PWRC | DEM_SLAVE_SMSM_PWRC_SUSPEND, + DEM_SLAVE_SMSM_PWRC_EARLY_EXIT); + + MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): EARLY_EXIT"); + + do { + memset(state_grps, 0, sizeof(state_grps)); + state_grps[0].group_id = SMSM_POWER_MASTER_DEM; + state_grps[0].bits_all_set = DEM_MASTER_SMSM_PWRC_EARLY_EXIT; + state_grps[1].group_id = SMSM_MODEM_STATE; + state_grps[1].bits_all_set = SMSM_RESET; + + ret = msm_pm_poll_state(ARRAY_SIZE(state_grps), state_grps); + } while (ret < 0); + + MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): EARLY_EXIT EE"); + + if (ret == 1) { + MSM_PM_DPRINTK( + MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE, + KERN_INFO, + "%s(): msm_pm_poll_state detected Modem reset\n", + __func__); + } + + /* DEM Master == RESET or PWRC_EARLY_EXIT */ + + ret = -EAGAIN; + +power_collapse_restore_gpio_bail: + msm_gpio_exit_sleep(); + + /* Enter RUN */ + smsm_change_state(SMSM_APPS_DEM, + DEM_SLAVE_SMSM_PWRC | DEM_SLAVE_SMSM_PWRC_SUSPEND | + DEM_SLAVE_SMSM_PWRC_EARLY_EXIT, DEM_SLAVE_SMSM_RUN); + + MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): RUN"); + + if (collapsed) + smd_sleep_exit(); + +power_collapse_bail: + return ret; +} + +/* + * Apps-sleep the Apps processor. This function execute the handshake + * protocol with Modem. + * + * Return value: + * -ENOSYS: function not implemented yet + */ +static int msm_pm_apps_sleep(uint32_t sleep_delay, uint32_t sleep_limit) +{ + return -ENOSYS; +} + +/* + * Bring the Apps processor to SWFI. + * + * Return value: + * -EIO: could not ramp Apps processor clock + * 0: success + */ +static int msm_pm_swfi(bool ramp_acpu) +{ + unsigned long saved_acpuclk_rate = 0; + + if (ramp_acpu) { + saved_acpuclk_rate = acpuclk_wait_for_irq(); + MSM_PM_DPRINTK(MSM_PM_DEBUG_CLOCK, KERN_INFO, + "%s(): change clock rate (old rate = %lu)\n", __func__, + saved_acpuclk_rate); + + if (!saved_acpuclk_rate) + return -EIO; + } + + msm_arch_idle(); + + if (ramp_acpu) { + MSM_PM_DPRINTK(MSM_PM_DEBUG_CLOCK, KERN_INFO, + "%s(): restore clock rate to %lu\n", __func__, + saved_acpuclk_rate); + if (acpuclk_set_rate(saved_acpuclk_rate, SETRATE_SWFI) < 0) + printk(KERN_ERR + "%s(): failed to restore clock rate(%lu)\n", + __func__, saved_acpuclk_rate); + } + + return 0; +} + + +/****************************************************************************** + * External Idle/Suspend Functions + *****************************************************************************/ + +/* + * Put CPU in low power mode. + */ +void arch_idle(void) +{ + bool allow[MSM_PM_SLEEP_MODE_NR]; + uint32_t sleep_limit = SLEEP_LIMIT_NONE; + + int latency_qos; + int64_t timer_expiration; + + int low_power; + int ret; + int i; + +#ifdef CONFIG_MSM_IDLE_STATS + DECLARE_BITMAP(clk_ids, NR_CLKS); + int64_t t1; + static int64_t t2; + int exit_stat; +#endif /* CONFIG_MSM_IDLE_STATS */ + + if (!atomic_read(&msm_pm_init_done)) + return; + + latency_qos = pm_qos_requirement(PM_QOS_CPU_DMA_LATENCY); + timer_expiration = msm_timer_enter_idle(); + +#ifdef CONFIG_MSM_IDLE_STATS + t1 = ktime_to_ns(ktime_get()); + msm_pm_add_stat(MSM_PM_STAT_NOT_IDLE, t1 - t2); + msm_pm_add_stat(MSM_PM_STAT_REQUESTED_IDLE, timer_expiration); +#endif /* CONFIG_MSM_IDLE_STATS */ + + for (i = 0; i < ARRAY_SIZE(allow); i++) + allow[i] = true; + + switch (msm_pm_idle_sleep_mode) { + case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT: + allow[MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT] = + false; + /* fall through */ + case MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT: + allow[MSM_PM_SLEEP_MODE_APPS_SLEEP] = false; + /* fall through */ + case MSM_PM_SLEEP_MODE_APPS_SLEEP: + allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN] = false; + allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] = false; + /* fall through */ + case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND: + case MSM_PM_SLEEP_MODE_POWER_COLLAPSE: + break; + default: + printk(KERN_ERR "idle sleep mode is invalid: %d\n", + msm_pm_idle_sleep_mode); +#ifdef CONFIG_MSM_IDLE_STATS + exit_stat = MSM_PM_STAT_IDLE_SPIN; +#endif /* CONFIG_MSM_IDLE_STATS */ + low_power = 0; + goto arch_idle_exit; + } + + if ((timer_expiration < msm_pm_idle_sleep_min_time) || + !msm_irq_idle_sleep_allowed()) { + allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] = false; + allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN] = false; + allow[MSM_PM_SLEEP_MODE_APPS_SLEEP] = false; + } + + for (i = 0; i < ARRAY_SIZE(allow); i++) { + struct msm_pm_platform_data *mode = &msm_pm_modes[i]; + if (!mode->supported || !mode->idle_enabled || + mode->latency >= latency_qos || + mode->residency >= timer_expiration) + allow[i] = false; + } + +#ifdef CONFIG_MSM_IDLE_STATS + ret = msm_clock_require_tcxo(clk_ids, NR_CLKS); +#elif defined(CONFIG_CLOCK_BASED_SLEEP_LIMIT) + ret = msm_clock_require_tcxo(NULL, 0); +#endif /* CONFIG_MSM_IDLE_STATS */ + +#ifdef CONFIG_CLOCK_BASED_SLEEP_LIMIT + if (ret) + sleep_limit = SLEEP_LIMIT_NO_TCXO_SHUTDOWN; +#endif + + MSM_PM_DPRINTK(MSM_PM_DEBUG_IDLE, KERN_INFO, + "%s(): next timer %lld, sleep limit %u\n", + __func__, timer_expiration, sleep_limit); + + for (i = 0; i < ARRAY_SIZE(allow); i++) + MSM_PM_DPRINTK(MSM_PM_DEBUG_IDLE, KERN_INFO, + "%s(): allow %s: %d\n", __func__, + msm_pm_sleep_mode_labels[i], (int)allow[i]); + + if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] || + allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN]) { + uint32_t sleep_delay; + + sleep_delay = (uint32_t) msm_pm_convert_and_cap_time( + timer_expiration, MSM_PM_SLEEP_TICK_LIMIT); + if (sleep_delay == 0) /* 0 would mean infinite time */ + sleep_delay = 1; + + if (!allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE]) + sleep_limit = SLEEP_LIMIT_NO_TCXO_SHUTDOWN; + + ret = msm_pm_power_collapse(true, sleep_delay, sleep_limit); + low_power = (ret != -EBUSY && ret != -ETIMEDOUT); + +#ifdef CONFIG_MSM_IDLE_STATS + if (ret) + exit_stat = MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE; + else { + exit_stat = MSM_PM_STAT_IDLE_POWER_COLLAPSE; + msm_pm_sleep_limit = sleep_limit; + bitmap_copy(msm_pm_clocks_no_tcxo_shutdown, clk_ids, + NR_CLKS); + } +#endif /* CONFIG_MSM_IDLE_STATS */ + } else if (allow[MSM_PM_SLEEP_MODE_APPS_SLEEP]) { + uint32_t sleep_delay; + + sleep_delay = (uint32_t) msm_pm_convert_and_cap_time( + timer_expiration, MSM_PM_SLEEP_TICK_LIMIT); + if (sleep_delay == 0) /* 0 would mean infinite time */ + sleep_delay = 1; + + ret = msm_pm_apps_sleep(sleep_delay, sleep_limit); + low_power = 0; + +#ifdef CONFIG_MSM_IDLE_STATS + if (ret) + exit_stat = MSM_PM_STAT_IDLE_FAILED_SLEEP; + else + exit_stat = MSM_PM_STAT_IDLE_SLEEP; +#endif /* CONFIG_MSM_IDLE_STATS */ + } else if (allow[MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT]) { + ret = msm_pm_swfi(true); + if (ret) + while (!msm_irq_pending()) + udelay(1); + low_power = 0; +#ifdef CONFIG_MSM_IDLE_STATS + exit_stat = ret ? MSM_PM_STAT_IDLE_SPIN : MSM_PM_STAT_IDLE_WFI; +#endif /* CONFIG_MSM_IDLE_STATS */ + } else if (allow[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT]) { + msm_pm_swfi(false); + low_power = 0; +#ifdef CONFIG_MSM_IDLE_STATS + exit_stat = MSM_PM_STAT_IDLE_WFI; +#endif /* CONFIG_MSM_IDLE_STATS */ + } else { + while (!msm_irq_pending()) + udelay(1); + low_power = 0; +#ifdef CONFIG_MSM_IDLE_STATS + exit_stat = MSM_PM_STAT_IDLE_SPIN; +#endif /* CONFIG_MSM_IDLE_STATS */ + } + +arch_idle_exit: + msm_timer_exit_idle(low_power); + +#ifdef CONFIG_MSM_IDLE_STATS + t2 = ktime_to_ns(ktime_get()); + msm_pm_add_stat(exit_stat, t2 - t1); +#endif /* CONFIG_MSM_IDLE_STATS */ +} + +/* + * Suspend the Apps processor. + * + * Return value: + * -EAGAIN: modem reset occurred or early exit from suspend + * -EBUSY: modem not ready for our suspend + * -EINVAL: invalid sleep mode + * -EIO: could not ramp Apps processor clock + * -ETIMEDOUT: timed out waiting for modem's handshake + * 0: success + */ +static int msm_pm_enter(suspend_state_t state) +{ + bool allow[MSM_PM_SLEEP_MODE_NR]; + uint32_t sleep_limit = SLEEP_LIMIT_NONE; + int ret; + int i; + +#ifdef CONFIG_MSM_IDLE_STATS + DECLARE_BITMAP(clk_ids, NR_CLKS); + int64_t period = 0; + int64_t time = 0; + + time = msm_timer_get_smem_clock_time(&period); + ret = msm_clock_require_tcxo(clk_ids, NR_CLKS); +#elif defined(CONFIG_CLOCK_BASED_SLEEP_LIMIT) + ret = msm_clock_require_tcxo(NULL, 0); +#endif /* CONFIG_MSM_IDLE_STATS */ + +#ifdef CONFIG_CLOCK_BASED_SLEEP_LIMIT + if (ret) + sleep_limit = SLEEP_LIMIT_NO_TCXO_SHUTDOWN; +#endif + + for (i = 0; i < ARRAY_SIZE(allow); i++) + allow[i] = true; + + switch (msm_pm_sleep_mode) { + case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT: + allow[MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT] = + false; + /* fall through */ + case MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT: + allow[MSM_PM_SLEEP_MODE_APPS_SLEEP] = false; + /* fall through */ + case MSM_PM_SLEEP_MODE_APPS_SLEEP: + allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN] = false; + allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] = false; + /* fall through */ + case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND: + case MSM_PM_SLEEP_MODE_POWER_COLLAPSE: + break; + default: + printk(KERN_ERR "suspend sleep mode is invalid: %d\n", + msm_pm_sleep_mode); + return -EINVAL; + } + + for (i = 0; i < ARRAY_SIZE(allow); i++) { + struct msm_pm_platform_data *mode = &msm_pm_modes[i]; + if (!mode->supported || !mode->suspend_enabled) + allow[i] = false; + } + + ret = 0; + + if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] || + allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN]) { +#ifdef CONFIG_MSM_IDLE_STATS + enum msm_pm_time_stats_id id; + int64_t end_time; +#endif + +#ifdef CONFIG_MSM_SLEEP_TIME_OVERRIDE + if (msm_pm_sleep_time_override > 0) { + int64_t ns; + ns = NSEC_PER_SEC * (int64_t)msm_pm_sleep_time_override; + msm_pm_set_max_sleep_time(ns); + msm_pm_sleep_time_override = 0; + } +#endif + if (!allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE]) + sleep_limit = SLEEP_LIMIT_NO_TCXO_SHUTDOWN; + + ret = msm_pm_power_collapse( + false, msm_pm_max_sleep_time, sleep_limit); + +#ifdef CONFIG_MSM_IDLE_STATS + if (ret) + id = MSM_PM_STAT_FAILED_SUSPEND; + else { + id = MSM_PM_STAT_SUSPEND; + msm_pm_sleep_limit = sleep_limit; + bitmap_copy(msm_pm_clocks_no_tcxo_shutdown, clk_ids, + NR_CLKS); + } + + if (time != 0) { + end_time = msm_timer_get_smem_clock_time(NULL); + if (end_time != 0) { + time = end_time - time; + if (time < 0) + time += period; + } else + time = 0; + } + + msm_pm_add_stat(id, time); +#endif + } else if (allow[MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT]) { + ret = msm_pm_swfi(true); + if (ret) + while (!msm_irq_pending()) + udelay(1); + } else if (allow[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT]) { + msm_pm_swfi(false); + } + + return ret; +} + +static struct platform_suspend_ops msm_pm_ops = { + .enter = msm_pm_enter, + .valid = suspend_valid_only_mem, +}; + + +/****************************************************************************** + * Restart Definitions + *****************************************************************************/ + +static uint32_t restart_reason = 0x776655AA; + +static void msm_pm_power_off(void) +{ + msm_proc_comm(PCOM_POWER_DOWN, 0, 0); + for (;;) + ; +} + +static void msm_pm_restart(char str) +{ + /* If there's a hard reset hook and the restart_reason + * is the default, prefer that to the (slower) proc_comm + * reset command. + */ +#if 0 + if ((restart_reason == 0x776655AA) && msm_reset_hook) + msm_reset_hook(str); + else + msm_proc_comm(PCOM_RESET_CHIP, &restart_reason, 0); +#endif + for (;;) + ; +} + +static int msm_reboot_call + (struct notifier_block *this, unsigned long code, void *_cmd) +{ + if ((code == SYS_RESTART) && _cmd) { + char *cmd = _cmd; + if (!strcmp(cmd, "bootloader")) { + restart_reason = 0x77665500; + } else if (!strcmp(cmd, "recovery")) { + restart_reason = 0x77665502; + } else if (!strcmp(cmd, "eraseflash")) { + restart_reason = 0x776655EF; + } else if (!strncmp(cmd, "oem-", 4)) { + unsigned code = simple_strtoul(cmd + 4, 0, 16) & 0xff; + restart_reason = 0x6f656d00 | code; + } else { + restart_reason = 0x77665501; + } + } + return NOTIFY_DONE; +} + +static struct notifier_block msm_reboot_notifier = { + .notifier_call = msm_reboot_call, +}; + + +/****************************************************************************** + * + *****************************************************************************/ + +/* + * Initialize the power management subsystem. + * + * Return value: + * -ENODEV: initialization failed + * 0: success + */ +static int __init msm_pm_init(void) +{ +#ifdef CONFIG_MSM_IDLE_STATS + struct proc_dir_entry *d_entry; +#endif + + pm_power_off = msm_pm_power_off; + arm_pm_restart = msm_pm_restart; + register_reboot_notifier(&msm_reboot_notifier); + + msm_pm_smem_data = smem_alloc(SMEM_APPS_DEM_SLAVE_DATA, + sizeof(*msm_pm_smem_data)); + if (msm_pm_smem_data == NULL) { + printk(KERN_ERR "%s: failed to get smsm_data\n", __func__); + return -ENODEV; + } + +#ifdef CONFIG_ARCH_QSD + /* The bootloader is responsible for initializing many of Scorpion's + * coprocessor registers for things like cache timing. The state of + * these coprocessor registers is lost on reset, so part of the + * bootloader must be re-executed. Do not overwrite the reset vector + * or bootloader area. + */ + msm_pm_reset_vector = (uint32_t *) PAGE_OFFSET; +#else + msm_pm_reset_vector = ioremap(0, PAGE_SIZE); + if (msm_pm_reset_vector == NULL) { + printk(KERN_ERR "%s: failed to map reset vector\n", __func__); + return -ENODEV; + } +#endif /* CONFIG_ARCH_QSD */ + + BUG_ON(msm_pm_modes == NULL); + + atomic_set(&msm_pm_init_done, 1); + suspend_set_ops(&msm_pm_ops); + + msm_pm_mode_sysfs_add(); +#ifdef CONFIG_MSM_IDLE_STATS + d_entry = create_proc_entry("msm_pm_stats", + S_IRUGO | S_IWUSR | S_IWGRP, NULL); + if (d_entry) { + d_entry->read_proc = msm_pm_read_proc; + d_entry->write_proc = msm_pm_write_proc; + d_entry->data = NULL; + } +#endif + + return 0; +} + +late_initcall(msm_pm_init); diff --git a/arch/arm/mach-msm/pmic.c b/arch/arm/mach-msm/pmic.c new file mode 100644 index 000000000000..e096b908b212 --- /dev/null +++ b/arch/arm/mach-msm/pmic.c @@ -0,0 +1,820 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +#include +#include +#include +#include + +#include + +#include "smd_rpcrouter.h" + +#define TRACE_SPEAKER 0 + +#if TRACE_SPEAKER +#define SPEAKER(x...) printk(KERN_INFO "[SPEAKER] " x) +#else +#define SPEAKER(x...) do {} while (0) +#endif + +/* rpc related */ +#define PMIC_RPC_TIMEOUT (5*HZ) + +#define SPEAKER_PDEV_NAME "rs00010001:00000000" +#define SPEAKER_RPC_PROG 0x30000061 +#define SPEAKER_RPC_VER 0x00010001 + +#define SET_LED_INTENSITY_PROC 16 +#define FLASH_LED_SET_CURRENT_PROC 17 + +#define SPEAKER_CMD_PROC 20 +#define SET_SPEAKER_GAIN_PROC 21 + +#define MIC_EN_PROC 28 +#define MIC_IS_EN_PROC 29 +#define MIC_SET_VOLT_PROC 30 +#define MIC_GET_VOLT_PROC 31 +#define SPKR_EN_RIGHT_CHAN_PROC 32 +#define SPKR_IS_RIGHT_CHAN_EN_PROC 33 +#define SPKR_EN_LEFT_CHAN_PROC 34 +#define SPKR_IS_LEFT_CHAN_EN_PROC 35 +#define SET_SPKR_CONFIGURATION_PROC 36 +#define GET_SPKR_CONFIGURATION_PROC 37 +#define SPKR_GET_GAIN_PROC 38 +#define SPKR_IS_EN_PROC 39 + +/* error bit flags defined by modem side */ +#define PM_ERR_FLAG__PAR1_OUT_OF_RANGE (0x0001) +#define PM_ERR_FLAG__PAR2_OUT_OF_RANGE (0x0002) +#define PM_ERR_FLAG__PAR3_OUT_OF_RANGE (0x0004) +#define PM_ERR_FLAG__PAR4_OUT_OF_RANGE (0x0008) +#define PM_ERR_FLAG__PAR5_OUT_OF_RANGE (0x0010) + +#define PM_ERR_FLAG__ALL_PARMS_OUT_OF_RANGE (0x001F) /* all 5 previous */ + +#define PM_ERR_FLAG__SBI_OPT_ERR (0x0080) +#define PM_ERR_FLAG__FEATURE_NOT_SUPPORTED (0x0100) + +struct std_rpc_req { + struct rpc_request_hdr req; + uint32_t value; +}; + +struct std_rpc_reply { + struct rpc_reply_hdr hdr; + uint32_t result; +}; + +struct get_value_rep { + struct std_rpc_reply reply_hdr; + uint32_t MoreData; + uint32_t value; +}; + +struct std_rpc_req2 { + struct rpc_request_hdr hdr; + uint32_t value1; + uint32_t value2; +}; + +struct set_spkr_configuration_req { + struct rpc_request_hdr hdr; + uint32_t MoreData; + struct spkr_config_mode type; +}; + +struct get_spkr_configuration_rep { + struct std_rpc_reply reply_hdr; + uint32_t MoreData; + struct spkr_config_mode type; +}; + +static struct msm_rpc_endpoint *endpoint; + +static int check_and_connect(void) +{ + if (endpoint != NULL) + return 0; + + endpoint = msm_rpc_connect(SPEAKER_RPC_PROG, SPEAKER_RPC_VER, 0); + if (endpoint == NULL) { + return -ENODEV; + } else if (IS_ERR(endpoint)) { + int rc = PTR_ERR(endpoint); + printk(KERN_ERR "%s: init rpc failed! rc = %d\n", + __func__, rc); + endpoint = NULL; + return rc; + } + return 0; +} + +static int modem_to_linux_err(u16 err_netendian) +{ + u32 err; + if (!err_netendian) + return 0; + + err = be32_to_cpu(err_netendian); + if (err & PM_ERR_FLAG__ALL_PARMS_OUT_OF_RANGE) + return -EINVAL; /* PM_ERR_FLAG__PAR[1..5]_OUT_OF_RANGE */ + + if (err & PM_ERR_FLAG__SBI_OPT_ERR) + return -EIO; + + if (err & PM_ERR_FLAG__FEATURE_NOT_SUPPORTED) + return -ENOSYS; + + return -EPERM; +} + +static int do_remote_value(const uint32_t set_value, + uint32_t * const get_value, + const uint32_t proc) +{ + struct std_rpc_req req; + struct std_rpc_reply std_rep; + struct get_value_rep rep; + void *rep_ptr; + int rep_size, rc = check_and_connect(); + + if (rc) /* connect problem */ + return rc; + + if (get_value != NULL) { /* get value */ + req.value = cpu_to_be32(1); /* output_pointer_not_null */ + rep_size = sizeof(rep); + rep_ptr = &rep; + } else { /* set value */ + req.value = cpu_to_be32(set_value); + rep_size = sizeof(std_rep); + rep_ptr = &std_rep; + } + rc = msm_rpc_call_reply(endpoint, proc, + &req, sizeof(req), + rep_ptr, rep_size, + PMIC_RPC_TIMEOUT); + if (rc < 0) + return rc; + + if (get_value != NULL) { /* get value */ + if (!rep.reply_hdr.result) { + if (!rep.MoreData) + return -ENOMSG; + + *get_value = be32_to_cpu(rep.value); + } + rc = modem_to_linux_err(rep.reply_hdr.result); + } else { + rc = modem_to_linux_err(std_rep.result); + } + return rc; +} + +int spkr_en_right_chan(const unsigned char enable) +{ + return do_remote_value(enable, NULL, SPKR_EN_RIGHT_CHAN_PROC); +} +EXPORT_SYMBOL(spkr_en_right_chan); + +int spkr_is_right_chan_en(unsigned char * const enabled) +{ + uint32_t word_enabled; + int rc; + + if (enabled == NULL) + return modem_to_linux_err(PM_ERR_FLAG__PAR1_OUT_OF_RANGE); + + rc = do_remote_value(0, &word_enabled, SPKR_IS_RIGHT_CHAN_EN_PROC); + if (!rc) + *enabled = (unsigned char)word_enabled; + return rc; +} +EXPORT_SYMBOL(spkr_is_right_chan_en); + +int spkr_en_left_chan(const unsigned char enable) +{ + return do_remote_value(enable, NULL, SPKR_EN_LEFT_CHAN_PROC); +} +EXPORT_SYMBOL(spkr_en_left_chan); + +int spkr_is_left_chan_en(unsigned char * const enabled) +{ + uint32_t word_enabled; + int rc; + + if (enabled == NULL) + return modem_to_linux_err(PM_ERR_FLAG__PAR1_OUT_OF_RANGE); + + rc = do_remote_value(0, &word_enabled, SPKR_IS_LEFT_CHAN_EN_PROC); + if (!rc) + *enabled = (unsigned char)word_enabled; + return rc; +} +EXPORT_SYMBOL(spkr_is_left_chan_en); + +int spkr_is_en(const enum spkr_left_right left_right, + unsigned char * const enabled) +{ + if (left_right >= SPKR_OUT_OF_RANGE) + return -EINVAL; + + return left_right == LEFT_SPKR ? + spkr_is_left_chan_en(enabled) : + spkr_is_right_chan_en(enabled); +} +EXPORT_SYMBOL(spkr_is_en); + +static int do_std_rpc_req2(struct get_value_rep *rep, uint32_t proc, + uint32_t value1, uint32_t value2) +{ + struct std_rpc_req2 req; + int rc; + + rc = check_and_connect(); + if (rc) { + printk(KERN_ERR "%s: can't make rpc connection!\n", __func__); + return rc; + } + + req.value1 = cpu_to_be32(value1); + req.value2 = cpu_to_be32(value2); + + rc = msm_rpc_call_reply(endpoint, proc, + &req, sizeof(req), + rep, sizeof(*rep), + PMIC_RPC_TIMEOUT); + if (rc < 0) { + printk(KERN_ERR + "%s: msm_rpc_call_reply failed! proc=%d rc=%d\n", + __func__, proc, rc); + return rc; + } + + return modem_to_linux_err(rep->reply_hdr.result); +} + +int spkr_get_gain(const enum spkr_left_right left_right, + enum spkr_gain * const gain) +{ + struct get_value_rep rep; + int rc; + + if (left_right >= SPKR_OUT_OF_RANGE) + return -EINVAL; + + if (gain == NULL) + return modem_to_linux_err(PM_ERR_FLAG__PAR1_OUT_OF_RANGE); + + rc = do_std_rpc_req2(&rep, SPKR_GET_GAIN_PROC, (uint32_t)left_right, 1); + + if (!rc && !rep.reply_hdr.result) { + if (!rep.MoreData) + return -ENOMSG; + + *gain = (enum spkr_gain)be32_to_cpu(rep.value); + } + + return rc; +} +EXPORT_SYMBOL(spkr_get_gain); + +int set_speaker_gain(const enum spkr_gain speaker_gain) +{ + if (speaker_gain >= SPKR_GAIN_OUT_OF_RANGE) + return -EINVAL; + + return do_remote_value(speaker_gain, NULL, SET_SPEAKER_GAIN_PROC); +} +EXPORT_SYMBOL(set_speaker_gain); + +int speaker_cmd(const enum spkr_cmd cmd) +{ + if (cmd >= SPKR_CMD_OUT_OF_RANGE) + return -EINVAL; + + return do_remote_value(cmd, NULL, SPEAKER_CMD_PROC); +} +EXPORT_SYMBOL(speaker_cmd); + +int set_spkr_configuration(const struct spkr_config_mode * const t) +{ + struct set_spkr_configuration_req req; + struct std_rpc_reply rep; + int i, rc; + + if (t == NULL) + return modem_to_linux_err(PM_ERR_FLAG__PAR1_OUT_OF_RANGE); + + rc = check_and_connect(); + if (rc) + return rc; + + for (i = 0; i < sizeof(*t)/sizeof(uint32_t); i++) + ((uint32_t *)&req.type)[i] = cpu_to_be32(((uint32_t *)t)[i]); + + req.MoreData = cpu_to_be32(1); + rc = msm_rpc_call_reply(endpoint, SET_SPKR_CONFIGURATION_PROC, + &req, sizeof(req), + &rep, sizeof(rep), + PMIC_RPC_TIMEOUT); + if (rc < 0) + return rc; + + return modem_to_linux_err(rep.result); +} +EXPORT_SYMBOL(set_spkr_configuration); + +int get_spkr_configuration(struct spkr_config_mode * const t) +{ + struct std_rpc_req req; + struct get_spkr_configuration_rep rep; + int rc; + + if (t == NULL) + return modem_to_linux_err(PM_ERR_FLAG__PAR1_OUT_OF_RANGE); + + rc = check_and_connect(); + if (rc) + return rc; + + req.value = cpu_to_be32(1); /* output_pointer_not_null */ + rc = msm_rpc_call_reply(endpoint, GET_SPKR_CONFIGURATION_PROC, + &req, sizeof(req), + &rep, sizeof(rep), + PMIC_RPC_TIMEOUT); + if (rc < 0) + return rc; + + if (!rep.reply_hdr.result) { + int i; + + if (!rep.MoreData) + return -ENOMSG; + + for (i = 0; i < sizeof(*t)/sizeof(uint32_t); i++) + ((uint32_t *)t)[i] = + be32_to_cpu(((uint32_t *)&rep.type)[i]); + } + + return modem_to_linux_err(rep.reply_hdr.result); +} +EXPORT_SYMBOL(get_spkr_configuration); + +int mic_en(const unsigned char enable) +{ + return do_remote_value(enable, NULL, MIC_EN_PROC); +} +EXPORT_SYMBOL(mic_en); + +int mic_is_en(unsigned char * const enabled) +{ + uint32_t word_enabled; + int rc; + + if (enabled == NULL) + return modem_to_linux_err(PM_ERR_FLAG__PAR1_OUT_OF_RANGE); + + rc = do_remote_value(0, &word_enabled, MIC_IS_EN_PROC); + if (!rc) + *enabled = (unsigned char)word_enabled; + + return rc; +} +EXPORT_SYMBOL(mic_is_en); + +int mic_set_volt(const enum mic_volt type) +{ + if (type >= MIC_VOLT_OUT_OF_RANGE) + return -EINVAL; + + return do_remote_value(type, NULL, MIC_SET_VOLT_PROC); +} +EXPORT_SYMBOL(mic_set_volt); + +int mic_get_volt(enum mic_volt * const voltage) +{ + if (voltage == NULL) + return modem_to_linux_err(PM_ERR_FLAG__PAR1_OUT_OF_RANGE); + + return do_remote_value(0, voltage, MIC_GET_VOLT_PROC); +} +EXPORT_SYMBOL(mic_get_volt); + +/* Cannot use 'current' as the parameter name because 'current' is defined as + * a macro to get a pointer to the current task. + */ +int flash_led_set_current(const uint16_t milliamps) +{ + return do_remote_value(milliamps, NULL, FLASH_LED_SET_CURRENT_PROC); +} +EXPORT_SYMBOL(flash_led_set_current); + +int set_led_intensity(const enum ledtype type, int level) +{ + struct get_value_rep rep; + + if (type >= LED_TYPE_OUT_OF_RANGE) + return -EINVAL; + + return do_std_rpc_req2(&rep, SET_LED_INTENSITY_PROC, + (uint32_t)type, level); +} +EXPORT_SYMBOL(set_led_intensity); + +#if defined(CONFIG_DEBUG_FS) +static void debugfs_log_return_status(const int caller_rc, + const char * const caller__func__, + const u64 caller_val) +{ + if (!caller_rc) + printk(KERN_INFO "%s: succeeded, val %llu\n", + caller__func__, caller_val); + else + printk(KERN_ERR "%s: ERROR! val %llu, rc:%d(%#x)\n", + caller__func__, caller_val, caller_rc, caller_rc); +} + +static int debugfs_spkr_en_chan(void *data, u64 val) +{ + int rc = ((enum spkr_left_right)data) == LEFT_SPKR ? + spkr_en_left_chan((const unsigned char)val) : + spkr_en_right_chan((const unsigned char)val); + + debugfs_log_return_status(rc, __func__, val); + return rc; +} + +static int debugfs_spkr_is_chan_en(void *data, u64 *val) +{ + unsigned char enabled; + int rc = ((enum spkr_left_right)data) == LEFT_SPKR ? + spkr_is_left_chan_en(&enabled) : + spkr_is_right_chan_en(&enabled); + + if (!rc) + *val = (u64)enabled; + + debugfs_log_return_status(rc, __func__, *val); + return rc; +} +DEFINE_SIMPLE_ATTRIBUTE(debugfs_spkr_en_chan_fops, + debugfs_spkr_is_chan_en, + debugfs_spkr_en_chan, + "%llu\n"); + +static int debugfs_spkr_get_gain(void *data, u64 *val) +{ + enum spkr_gain gain; + int rc = spkr_get_gain((enum spkr_left_right)data, &gain); + + if (!rc) + *val = (u64)gain; + + debugfs_log_return_status(rc, __func__, *val); + return rc; +} + +static int debugfs_set_speaker_gain(void *data, u64 val) +{ + int rc = set_speaker_gain((enum spkr_gain)val); + + debugfs_log_return_status(rc, __func__, val); + return rc; +} +DEFINE_SIMPLE_ATTRIBUTE(debugfs_spkr_gain_fops, + debugfs_spkr_get_gain, + debugfs_set_speaker_gain, + "%llu\n"); + +static int debugfs_speaker_cmd(void *data, u64 val) +{ + int rc = speaker_cmd((const enum spkr_cmd)val); + + debugfs_log_return_status(rc, __func__, val); + return rc; +} +DEFINE_SIMPLE_ATTRIBUTE(debugfs_speaker_cmd_fops, + NULL, + debugfs_speaker_cmd, + "%llu\n"); + +static int debugfs_spkr_configuration_open(struct inode *inode, + struct file *filp) +{ + filp->private_data = inode->i_private; + return 0; +} + +#define debugfs_speaker_configuration_format_str \ + "%u,%u,%u,%u,%u,%u,%u,%u\n" \ + "is_right_chan_en: %u\n" \ + "is_left_chan_en: %u\n" \ + "is_right_left_chan_added: %u\n" \ + "is_stereo_en: %u\n" \ + "is_usb_with_hpf_20hz: %u\n" \ + "is_mux_bypassed: %u\n" \ + "is_hpf_en: %u\n" \ + "is_sink_curr_from_ref_volt_cir_en: %u\n" + +static ssize_t debugfs_spkr_get_configuration(struct file *filp, + char __user *ubuf, + size_t cnt, loff_t *ppos) +{ + struct spkr_config_mode type; + int rc = get_spkr_configuration(&type); + + if (!rc) { + /* Hopefully, 100 additional chars is enough. The number is + * calculated by having 16 elements with up to 5 digits each + * and then doubling it for paranoia's sake. In any case, + * snprintf will truncate, so no danger of oops or panic. + */ + char speaker_configuration_dump_buf[ + sizeof(debugfs_speaker_configuration_format_str) + 200]; + int bytes_copied = snprintf(speaker_configuration_dump_buf, + sizeof(speaker_configuration_dump_buf), + debugfs_speaker_configuration_format_str, + type.is_right_chan_en, + type.is_left_chan_en, + type.is_right_left_chan_added, + type.is_stereo_en, + type.is_usb_with_hpf_20hz, + type.is_mux_bypassed, + type.is_hpf_en, + type.is_sink_curr_from_ref_volt_cir_en, + type.is_right_chan_en, + type.is_left_chan_en, + type.is_right_left_chan_added, + type.is_stereo_en, + type.is_usb_with_hpf_20hz, + type.is_mux_bypassed, + type.is_hpf_en, + type.is_sink_curr_from_ref_volt_cir_en); + + if (bytes_copied > cnt) { + rc = -EINVAL; + goto out_err; + } + + rc = (int)simple_read_from_buffer(ubuf, cnt, ppos, + speaker_configuration_dump_buf, bytes_copied); + if (rc < 0) + goto out_err; + + printk(KERN_INFO "%s: succeeded, (%d)%d bytes copied\n%s", + __func__, rc, bytes_copied, + speaker_configuration_dump_buf); + } +out_err: + if (rc < 0) + printk(KERN_ERR "%s: ERROR! rc: %d(%#x)\n", __func__, rc, rc); + + return rc; +} + +#define debugfs_spkr_set_configuration_format_str "%u,%u,%u,%u,%u,%u,%u,%u" + +static ssize_t debugfs_spkr_set_configuration(struct file *filp, + const char __user *ubuf, + size_t cnt, loff_t *ppos) +{ + char buf[100]; /* 8 unsigned ints + paranoia */ + struct spkr_config_mode t; + int rc; + + if (cnt >= sizeof(buf)) + return -EINVAL; + + if (copy_from_user(&buf, ubuf, cnt)) + return -EFAULT; + + buf[cnt] = 0; + + rc = sscanf(buf, debugfs_spkr_set_configuration_format_str, + &t.is_right_chan_en, + &t.is_left_chan_en, + &t.is_right_left_chan_added, + &t.is_stereo_en, + &t.is_usb_with_hpf_20hz, + &t.is_mux_bypassed, + &t.is_hpf_en, + &t.is_sink_curr_from_ref_volt_cir_en); + + if (rc < 8) { + printk(KERN_ERR "%s: snprintf failed arg convert" + " after arg #%d on buf %s\n", + __func__, rc, buf); + return -EINVAL; + } + + rc = set_spkr_configuration(&t); + if (!rc) + printk(KERN_INFO "%s: succeeded, %s\n", __func__, buf); + else + printk(KERN_ERR + "%s: set_spkr_configuration error %d(%#x), buf: %s\n", + __func__, rc, rc, buf); + + return rc < 0 ? rc : cnt; +} + +static const struct file_operations debugfs_spkr_configuration_fops = { + .open = debugfs_spkr_configuration_open, + .read = debugfs_spkr_get_configuration, + .write = debugfs_spkr_set_configuration, +}; + +static int debugfs_mic_en(void *data, u64 val) +{ + int rc = mic_en((const unsigned char)val); + + debugfs_log_return_status(rc, __func__, val); + return rc; +} + +static int debugfs_mic_is_en(void *data, u64 *val) +{ + unsigned char enabled; + int rc = mic_is_en(&enabled); + + if (!rc) + *val = (u64)enabled; + + debugfs_log_return_status(rc, __func__, *val); + return rc; +} +DEFINE_SIMPLE_ATTRIBUTE(debugfs_mic_en_fops, + debugfs_mic_is_en, + debugfs_mic_en, + "%llu\n"); + +static int debugfs_mic_set_volt(void *data, u64 val) +{ + int rc = mic_set_volt((const enum mic_volt)val); + + debugfs_log_return_status(rc, __func__, val); + return rc; +} + +static int debugfs_mic_get_volt(void *data, u64 *val) +{ + enum mic_volt voltage; + int rc = mic_get_volt(&voltage); + + if (!rc) + *val = (u64)voltage; + + debugfs_log_return_status(rc, __func__, *val); + return rc; +} +DEFINE_SIMPLE_ATTRIBUTE(debugfs_mic_volt_fops, + debugfs_mic_get_volt, + debugfs_mic_set_volt, + "%llu\n"); + +static uint16_t debugfs_flash_led_milliamps; +static int debugfs_flash_led_set_current_execute(void *data, u64 val) +{ + int rc = flash_led_set_current((const uint16_t)val); + + if (!rc) + debugfs_flash_led_milliamps = (const uint16_t)val; + + debugfs_log_return_status(rc, __func__, val); + return rc; +} + +static int debugfs_flash_led_set_current_get_cached(void *data, u64 *val) +{ + *val = (u64)debugfs_flash_led_milliamps; + + debugfs_log_return_status(0, __func__, *val); + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(debugfs_flash_led_current_fops, + debugfs_flash_led_set_current_get_cached, + debugfs_flash_led_set_current_execute, + "%llu\n"); + +static uint16_t debugfs_lcd_intensity; +static int debugfs_set_lcd_intensity(void *data, u64 val) +{ + int rc = set_led_intensity(LED_LCD, (const uint16_t)val); + + if (!rc) + debugfs_lcd_intensity = (const uint16_t)val; + + debugfs_log_return_status(rc, __func__, val); + return rc; +} + +static int debugfs_set_lcd_intensity_get_cached(void *data, u64 *val) +{ + *val = (u64)debugfs_lcd_intensity; + + debugfs_log_return_status(0, __func__, *val); + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(debugfs_set_lcd_intensity_fops, + debugfs_set_lcd_intensity_get_cached, + debugfs_set_lcd_intensity, + "%llu\n"); + +static int __init debugfs_speaker_init(void) +{ + struct dentry *dent = debugfs_create_dir("pmic", NULL); + + if (IS_ERR(dent)) { + printk(KERN_ERR "%s: debugfs_create_dir fail, error %ld\n", + __func__, PTR_ERR(dent)); + return (int)PTR_ERR(dent); + } + debugfs_create_file("spkr_left_en", 0644, dent, (void *)LEFT_SPKR, + &debugfs_spkr_en_chan_fops); + debugfs_create_file("spkr_right_en", 0644, dent, (void *)RIGHT_SPKR, + &debugfs_spkr_en_chan_fops); + debugfs_create_file("spkr_left_gain", 0644, dent, (void *)LEFT_SPKR, + &debugfs_spkr_gain_fops); + debugfs_create_file("spkr_right_gain", 0644, dent, (void *)RIGHT_SPKR, + &debugfs_spkr_gain_fops); + debugfs_create_file("spkr_cmd", 0644, dent, NULL, + &debugfs_speaker_cmd_fops); + debugfs_create_file("spkr_config", 0644, dent, NULL, + &debugfs_spkr_configuration_fops); + debugfs_create_file("mic_en", 0644, dent, NULL, &debugfs_mic_en_fops); + debugfs_create_file("mic_volt", 0644, dent, NULL, + &debugfs_mic_volt_fops); + debugfs_create_file("flash_led_current", 0644, dent, NULL, + &debugfs_flash_led_current_fops); + debugfs_create_file("set_lcd_intensity", 0644, dent, NULL, + &debugfs_set_lcd_intensity_fops); + return 0; +} + +late_initcall(debugfs_speaker_init); + +static int __init speaker_init(void) +{ + /* try to connect initially, ignore any errors for now */ + check_and_connect(); + return 0; +} + +device_initcall(speaker_init); +#endif diff --git a/arch/arm/mach-msm/proc_comm.c b/arch/arm/mach-msm/proc_comm.c index 915ee704ed3c..d5d498d000fb 100644 --- a/arch/arm/mach-msm/proc_comm.c +++ b/arch/arm/mach-msm/proc_comm.c @@ -1,6 +1,7 @@ /* arch/arm/mach-msm/proc_comm.c * * Copyright (C) 2007-2008 Google, Inc. + * Copyright (c) 2009, Code Aurora Forum. All rights reserved. * Author: Brian Swetland * * This software is licensed under the terms of the GNU General Public @@ -18,6 +19,7 @@ #include #include #include +#include #include #include @@ -43,68 +45,89 @@ static inline void notify_other_proc_comm(void) static DEFINE_SPINLOCK(proc_comm_lock); /* The higher level SMD support will install this to - * provide a way to check for and handle modem restart. + * provide a way to check for and handle modem restart? */ int (*msm_check_for_modem_crash)(void); /* Poll for a state change, checking for possible * modem crashes along the way (so we don't wait - * forever while the ARM9 is blowing up). + * forever while the ARM9 is blowing up. * * Return an error in the event of a modem crash and * restart so the msm_proc_comm() routine can restart * the operation from the beginning. */ -static int proc_comm_wait_for(void __iomem *addr, unsigned value) +static int proc_comm_wait_for(unsigned addr, unsigned value) { - for (;;) { + while (1) { if (readl(addr) == value) return 0; if (msm_check_for_modem_crash) if (msm_check_for_modem_crash()) return -EAGAIN; + + udelay(5); } } +void msm_proc_comm_reset_modem_now(void) +{ + unsigned base = (unsigned)MSM_SHARED_RAM_BASE; + unsigned long flags; + + spin_lock_irqsave(&proc_comm_lock, flags); + +again: + if (proc_comm_wait_for(base + MDM_STATUS, PCOM_READY)) + goto again; + + writel(PCOM_RESET_MODEM, base + APP_COMMAND); + writel(0, base + APP_DATA1); + writel(0, base + APP_DATA2); + + spin_unlock_irqrestore(&proc_comm_lock, flags); + + notify_other_proc_comm(); + + return; +} +EXPORT_SYMBOL(msm_proc_comm_reset_modem_now); + int msm_proc_comm(unsigned cmd, unsigned *data1, unsigned *data2) { - void __iomem *base = MSM_SHARED_RAM_BASE; + unsigned base = (unsigned)MSM_SHARED_RAM_BASE; unsigned long flags; int ret; spin_lock_irqsave(&proc_comm_lock, flags); - for (;;) { - if (proc_comm_wait_for(base + MDM_STATUS, PCOM_READY)) - continue; - - writel(cmd, base + APP_COMMAND); - writel(data1 ? *data1 : 0, base + APP_DATA1); - writel(data2 ? *data2 : 0, base + APP_DATA2); - - notify_other_proc_comm(); - - if (proc_comm_wait_for(base + APP_COMMAND, PCOM_CMD_DONE)) - continue; - - if (readl(base + APP_STATUS) != PCOM_CMD_FAIL) { - if (data1) - *data1 = readl(base + APP_DATA1); - if (data2) - *data2 = readl(base + APP_DATA2); - ret = 0; - } else { - ret = -EIO; - } - break; +again: + if (proc_comm_wait_for(base + MDM_STATUS, PCOM_READY)) + goto again; + + writel(cmd, base + APP_COMMAND); + writel(data1 ? *data1 : 0, base + APP_DATA1); + writel(data2 ? *data2 : 0, base + APP_DATA2); + + notify_other_proc_comm(); + + if (proc_comm_wait_for(base + APP_COMMAND, PCOM_CMD_DONE)) + goto again; + + if (readl(base + APP_STATUS) == PCOM_CMD_SUCCESS) { + if (data1) + *data1 = readl(base + APP_DATA1); + if (data2) + *data2 = readl(base + APP_DATA2); + ret = 0; + } else { + ret = -EIO; } writel(PCOM_CMD_IDLE, base + APP_COMMAND); spin_unlock_irqrestore(&proc_comm_lock, flags); - return ret; } - - +EXPORT_SYMBOL(msm_proc_comm); diff --git a/arch/arm/mach-msm/proc_comm.h b/arch/arm/mach-msm/proc_comm.h index 834760f25692..b071379871a2 100644 --- a/arch/arm/mach-msm/proc_comm.h +++ b/arch/arm/mach-msm/proc_comm.h @@ -1,6 +1,6 @@ /* arch/arm/mach-msm/proc_comm.h * - * Copyright (c) 2007 QUALCOMM Incorporated + * Copyright (c) 2007-2009, Code Aurora Forum. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -13,8 +13,8 @@ * */ -#ifndef _ARCH_ARM_MACH_MSM_PROC_COMM_H_ -#define _ARCH_ARM_MACH_MSM_PROC_COMM_H_ +#ifndef _ARCH_ARM_MACH_MSM_MSM_PROC_COMM_H_ +#define _ARCH_ARM_MACH_MSM_MSM_PROC_COMM_H_ enum { PCOM_CMD_IDLE = 0x0, @@ -62,104 +62,94 @@ enum { PCOM_RESET_CHIP_IMM, PCOM_PM_VID_EN, PCOM_VREG_PULLDOWN, + PCOM_GET_MODEM_VERSION, + PCOM_CLK_REGIME_SEC_RESET, + PCOM_CLK_REGIME_SEC_RESET_ASSERT, + PCOM_CLK_REGIME_SEC_RESET_DEASSERT, + PCOM_CLK_REGIME_SEC_PLL_REQUEST_WRP, + PCOM_CLK_REGIME_SEC_ENABLE, + PCOM_CLK_REGIME_SEC_DISABLE, + PCOM_CLK_REGIME_SEC_IS_ON, + PCOM_CLK_REGIME_SEC_SEL_CLK_INV, + PCOM_CLK_REGIME_SEC_SEL_CLK_SRC, + PCOM_CLK_REGIME_SEC_SEL_CLK_DIV, + PCOM_CLK_REGIME_SEC_ICODEC_CLK_ENABLE, + PCOM_CLK_REGIME_SEC_ICODEC_CLK_DISABLE, + PCOM_CLK_REGIME_SEC_SEL_SPEED, + PCOM_CLK_REGIME_SEC_CONFIG_GP_CLK_WRP, + PCOM_CLK_REGIME_SEC_CONFIG_MDH_CLK_WRP, + PCOM_CLK_REGIME_SEC_USB_XTAL_ON, + PCOM_CLK_REGIME_SEC_USB_XTAL_OFF, + PCOM_CLK_REGIME_SEC_SET_QDSP_DME_MODE, + PCOM_CLK_REGIME_SEC_SWITCH_ADSP_CLK, + PCOM_CLK_REGIME_SEC_GET_MAX_ADSP_CLK_KHZ, + PCOM_CLK_REGIME_SEC_GET_I2C_CLK_KHZ, + PCOM_CLK_REGIME_SEC_MSM_GET_CLK_FREQ_KHZ, + PCOM_CLK_REGIME_SEC_SEL_VFE_SRC, + PCOM_CLK_REGIME_SEC_MSM_SEL_CAMCLK, + PCOM_CLK_REGIME_SEC_MSM_SEL_LCDCLK, + PCOM_CLK_REGIME_SEC_VFE_RAIL_OFF, + PCOM_CLK_REGIME_SEC_VFE_RAIL_ON, + PCOM_CLK_REGIME_SEC_GRP_RAIL_OFF, + PCOM_CLK_REGIME_SEC_GRP_RAIL_ON, + PCOM_CLK_REGIME_SEC_VDC_RAIL_OFF, + PCOM_CLK_REGIME_SEC_VDC_RAIL_ON, + PCOM_CLK_REGIME_SEC_LCD_CTRL, + PCOM_CLK_REGIME_SEC_REGISTER_FOR_CPU_RESOURCE, + PCOM_CLK_REGIME_SEC_DEREGISTER_FOR_CPU_RESOURCE, + PCOM_CLK_REGIME_SEC_RESOURCE_REQUEST_WRP, + PCOM_CLK_REGIME_MSM_SEC_SEL_CLK_OWNER, + PCOM_CLK_REGIME_SEC_DEVMAN_REQUEST_WRP, + PCOM_GPIO_CONFIG, + PCOM_GPIO_CONFIGURE_GROUP, + PCOM_GPIO_TLMM_SET_PORT, + PCOM_GPIO_TLMM_CONFIG_EX, + PCOM_SET_FTM_BOOT_COUNT, + PCOM_RESERVED0, + PCOM_RESERVED1, + PCOM_CUSTOMER_CMD1, + PCOM_CUSTOMER_CMD2, + PCOM_CUSTOMER_CMD3, + PCOM_CLK_REGIME_ENTER_APPSBL_CHG_MODE, + PCOM_CLK_REGIME_EXIT_APPSBL_CHG_MODE, + POCM_CLK_REGIME_SEC_RAIL_DISABLE, + POCM_CLK_REGIME_SEC_RAIL_ENABLE, + POCM_CLK_REGIME_SEC_RAIL_CONTROL, + POCM_SET_SW_WATCHDOG_STATE, + POCM_PM_MPP_CONFIG_DIGITAL_INPUT, + POCM_PM_MPP_CONFIG_I_SINK, + POCM_RESERVED_101, + POCM_MSM_HSUSB_PHY_RESET, + PCOM_GET_BATT_MV_LEVEL, + PCOM_CHG_USB_IS_PC_CONNECTED, + PCOM_CHG_USB_IS_CHARGER_CONNECTED, + PCOM_CHG_USB_IS_DISCONNECTED, + PCOM_CHG_USB_IS_AVAILABLE, + PCOM_CLK_REGIME_SEC_MSM_SEL_FREQ, + PCOM_CLK_REGIME_SEC_SET_PCLK_AXI_POLICY, PCOM_NUM_CMDS, }; enum { - PCOM_INVALID_STATUS = 0x0, - PCOM_READY, - PCOM_CMD_RUNNING, - PCOM_CMD_SUCCESS, - PCOM_CMD_FAIL, + PCOM_INVALID_STATUS = 0x0, + PCOM_READY, + PCOM_CMD_RUNNING, + PCOM_CMD_SUCCESS, + PCOM_CMD_FAIL, + PCOM_CMD_FAIL_FALSE_RETURNED, + PCOM_CMD_FAIL_CMD_OUT_OF_BOUNDS_SERVER, + PCOM_CMD_FAIL_CMD_OUT_OF_BOUNDS_CLIENT, + PCOM_CMD_FAIL_CMD_UNREGISTERED, + PCOM_CMD_FAIL_CMD_LOCKED, + PCOM_CMD_FAIL_SERVER_NOT_YET_READY, + PCOM_CMD_FAIL_BAD_DESTINATION, + PCOM_CMD_FAIL_SERVER_RESET, + PCOM_CMD_FAIL_SMSM_NOT_INIT, + PCOM_CMD_FAIL_PROC_COMM_BUSY, + PCOM_CMD_FAIL_PROC_COMM_NOT_INIT, }; -/* List of VREGs that support the Pull Down Resistor setting. */ -enum { - PM_VREG_PDOWN_MSMA_ID, - PM_VREG_PDOWN_MSMP_ID, - PM_VREG_PDOWN_MSME1_ID, /* Not supported in Panoramix */ - PM_VREG_PDOWN_MSMC1_ID, /* Not supported in PM6620 */ - PM_VREG_PDOWN_MSMC2_ID, /* Supported in PM7500 only */ - PM_VREG_PDOWN_GP3_ID, /* Supported in PM7500 only */ - PM_VREG_PDOWN_MSME2_ID, /* Supported in PM7500 and Panoramix only */ - PM_VREG_PDOWN_GP4_ID, /* Supported in PM7500 only */ - PM_VREG_PDOWN_GP1_ID, /* Supported in PM7500 only */ - PM_VREG_PDOWN_TCXO_ID, - PM_VREG_PDOWN_PA_ID, - PM_VREG_PDOWN_RFTX_ID, - PM_VREG_PDOWN_RFRX1_ID, - PM_VREG_PDOWN_RFRX2_ID, - PM_VREG_PDOWN_SYNT_ID, - PM_VREG_PDOWN_WLAN_ID, - PM_VREG_PDOWN_USB_ID, - PM_VREG_PDOWN_MMC_ID, - PM_VREG_PDOWN_RUIM_ID, - PM_VREG_PDOWN_MSMC0_ID, /* Supported in PM6610 only */ - PM_VREG_PDOWN_GP2_ID, /* Supported in PM7500 only */ - PM_VREG_PDOWN_GP5_ID, /* Supported in PM7500 only */ - PM_VREG_PDOWN_GP6_ID, /* Supported in PM7500 only */ - PM_VREG_PDOWN_RF_ID, - PM_VREG_PDOWN_RF_VCO_ID, - PM_VREG_PDOWN_MPLL_ID, - PM_VREG_PDOWN_S2_ID, - PM_VREG_PDOWN_S3_ID, - PM_VREG_PDOWN_RFUBM_ID, - - /* new for HAN */ - PM_VREG_PDOWN_RF1_ID, - PM_VREG_PDOWN_RF2_ID, - PM_VREG_PDOWN_RFA_ID, - PM_VREG_PDOWN_CDC2_ID, - PM_VREG_PDOWN_RFTX2_ID, - PM_VREG_PDOWN_USIM_ID, - PM_VREG_PDOWN_USB2P6_ID, - PM_VREG_PDOWN_USB3P3_ID, - PM_VREG_PDOWN_INVALID_ID, - - /* backward compatible enums only */ - PM_VREG_PDOWN_CAM_ID = PM_VREG_PDOWN_GP1_ID, - PM_VREG_PDOWN_MDDI_ID = PM_VREG_PDOWN_GP2_ID, - PM_VREG_PDOWN_RUIM2_ID = PM_VREG_PDOWN_GP3_ID, - PM_VREG_PDOWN_AUX_ID = PM_VREG_PDOWN_GP4_ID, - PM_VREG_PDOWN_AUX2_ID = PM_VREG_PDOWN_GP5_ID, - PM_VREG_PDOWN_BT_ID = PM_VREG_PDOWN_GP6_ID, - - PM_VREG_PDOWN_MSME_ID = PM_VREG_PDOWN_MSME1_ID, - PM_VREG_PDOWN_MSMC_ID = PM_VREG_PDOWN_MSMC1_ID, - PM_VREG_PDOWN_RFA1_ID = PM_VREG_PDOWN_RFRX2_ID, - PM_VREG_PDOWN_RFA2_ID = PM_VREG_PDOWN_RFTX2_ID, - PM_VREG_PDOWN_XO_ID = PM_VREG_PDOWN_TCXO_ID -}; - -/* gpio info for PCOM_RPC_GPIO_TLMM_CONFIG_EX */ - -#define GPIO_ENABLE 0 -#define GPIO_DISABLE 1 - -#define GPIO_INPUT 0 -#define GPIO_OUTPUT 1 - -#define GPIO_NO_PULL 0 -#define GPIO_PULL_DOWN 1 -#define GPIO_KEEPER 2 -#define GPIO_PULL_UP 3 - -#define GPIO_2MA 0 -#define GPIO_4MA 1 -#define GPIO_6MA 2 -#define GPIO_8MA 3 -#define GPIO_10MA 4 -#define GPIO_12MA 5 -#define GPIO_14MA 6 -#define GPIO_16MA 7 - -#define PCOM_GPIO_CFG(gpio, func, dir, pull, drvstr) \ - ((((gpio) & 0x3FF) << 4) | \ - ((func) & 0xf) | \ - (((dir) & 0x1) << 14) | \ - (((pull) & 0x3) << 15) | \ - (((drvstr) & 0xF) << 17)) - +void msm_proc_comm_reset_modem_now(void); int msm_proc_comm(unsigned cmd, unsigned *data1, unsigned *data2); #endif diff --git a/arch/arm/mach-msm/remote_spinlock.c b/arch/arm/mach-msm/remote_spinlock.c new file mode 100644 index 000000000000..7c3271bedd56 --- /dev/null +++ b/arch/arm/mach-msm/remote_spinlock.c @@ -0,0 +1,111 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include + +#include + +/* This is ugly but it has to be done. If linux/spinlock_types is included, + * then for a UP kernel, the spinlock will get stubbed out. Since this is a + * remote spin lock, stubbing out is not the right thing to do. + */ +#define __LINUX_SPINLOCK_TYPES_H +#include +#undef __LINUX_SPINLOCK_TYPES_H + +#include + +#include +#include "smd_private.h" + +#define SMEM_SPINLOCK_COUNT 8 +#define SMEM_SPINLOCK_ARRAY_SIZE (SMEM_SPINLOCK_COUNT * sizeof(uint32_t)) + +int _remote_spin_lock_init(remote_spin_lock_id_t id, _remote_spinlock_t *lock) +{ + _remote_spinlock_t spinlock_start; + + /* The raw_spinlock_t structure should be the same as + * raw_remote_spinlock_t to be able to reuse the __raw_spin_lock() + * and __raw_spin_unlock() functions. If this condition is not met, + * then please write new code to replace calls to __raw_spin_lock() + * and __raw_spin_unlock(). */ + BUILD_BUG_ON(sizeof(raw_remote_spinlock_t) != sizeof(raw_spinlock_t)); + + if (id >= SMEM_SPINLOCK_COUNT) + return -EINVAL; + + spinlock_start = smem_alloc(SMEM_SPINLOCK_ARRAY, + SMEM_SPINLOCK_ARRAY_SIZE); + if (spinlock_start == NULL) + return -ENXIO; + + *lock = spinlock_start + id; + + return 0; +} + +void _remote_spin_lock(_remote_spinlock_t *lock) +{ + __raw_spin_lock((raw_spinlock_t *) (*lock)); +} + +void _remote_spin_unlock(_remote_spinlock_t *lock) +{ + __raw_spin_unlock((raw_spinlock_t *) (*lock)); +} diff --git a/arch/arm/mach-msm/reset_modem.c b/arch/arm/mach-msm/reset_modem.c new file mode 100644 index 000000000000..5d5b0f9a0620 --- /dev/null +++ b/arch/arm/mach-msm/reset_modem.c @@ -0,0 +1,226 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +/* + * MSM architecture driver to reset the modem + */ +#include +#include +#include +#include + +#include "smd_private.h" +#include "proc_comm.h" + +#define DEBUG +/* #undef DEBUG */ +#ifdef DEBUG +#define D(x...) printk(x) +#else +#define D(x...) do {} while (0) +#endif + +static ssize_t reset_modem_read(struct file *fp, char __user *buf, + size_t count, loff_t *pos) +{ + return 0; +} + +static ssize_t reset_modem_write(struct file *fp, const char __user *buf, + size_t count, loff_t *pos) +{ + unsigned char cmd[64]; + int len; + int time; + int zero = 0; + int r; + + if (count < 1) + return 0; + + len = count > 63 ? 63 : count; + + if (copy_from_user(cmd, buf, len)) + return -EFAULT; + + cmd[len] = 0; + + /* lazy */ + if (cmd[len-1] == '\n') { + cmd[len-1] = 0; + len--; + } + + if (!strncmp(cmd, "wait", 4)) { + D(KERN_ERR "INFO:%s:%i:%s: " + "MODEM RESTART: WAIT\n", + __FILE__, + __LINE__, + __func__); + smsm_reset_modem(SMSM_MODEM_WAIT); + } else if (!strncmp(cmd, "continue", 8)) { + D(KERN_ERR "INFO:%s:%i:%s: " + "MODEM RESTART: CONTINUE\n", + __FILE__, + __LINE__, + __func__); + smsm_reset_modem_cont(); + } else if (!strncmp(cmd, "download", 8)) { + D(KERN_ERR "INFO:%s:%i:%s: " + "MODEM RESTART: DOWNLOAD\n", + __FILE__, + __LINE__, + __func__); + smsm_reset_modem(SMSM_SYSTEM_DOWNLOAD); + } else if (sscanf(cmd, "deferred reset %i", &time) == 1) { + D(KERN_ERR "INFO:%s:%i:%s: " + "MODEM RESTART: DEFERRED RESET %ims\n", + __FILE__, + __LINE__, + __func__, + time); + if (time == 0) { + r = 0; + msm_proc_comm_reset_modem_now(); + } else { + r = msm_proc_comm(PCOM_RESET_MODEM, &time, &zero); + } + if (r < 0) + return r; + } else if (!strncmp(cmd, "deferred reset", 14)) { + D(KERN_ERR "INFO:%s:%i:%s: " + "MODEM RESTART: DEFERRED RESET 0ms\n", + __FILE__, + __LINE__, + __func__); + r = 0; + msm_proc_comm_reset_modem_now(); + if (r < 0) + return r; + } else if (!strncmp(cmd, "reset chip now", 14)) { + uint param1 = 0x0; + uint param2 = 0x0; + + D(KERN_ERR "INFO:%s:%i:%s: " + "MODEM RESTART: CHIP RESET IMMEDIATE\n", + __FILE__, + __LINE__, + __func__); + + r = msm_proc_comm(PCOM_RESET_CHIP_IMM, ¶m1, ¶m2); + + if (r < 0) + return r; + } else if (!strncmp(cmd, "reset chip", 10)) { + + uint param1 = 0x0; + uint param2 = 0x0; + + D(KERN_ERR "INFO:%s:%i:%s: " + "MODEM RESTART: CHIP RESET \n", + __FILE__, + __LINE__, + __func__); + + r = msm_proc_comm(PCOM_RESET_CHIP, ¶m1, ¶m2); + + if (r < 0) + return r; + } else { /* if (!strncmp(cmd, "reset", 5)) */ + printk(KERN_ERR "INFO:%s:%i:%s: " + "MODEM RESTART: RESET\n", + __FILE__, + __LINE__, + __func__); + smsm_reset_modem(SMSM_RESET); + } + + return count; +} + +static int reset_modem_open(struct inode *ip, struct file *fp) +{ + return 0; +} + +static int reset_modem_release(struct inode *ip, struct file *fp) +{ + return 0; +} + +static const struct file_operations reset_modem_fops = { + .owner = THIS_MODULE, + .read = reset_modem_read, + .write = reset_modem_write, + .open = reset_modem_open, + .release = reset_modem_release, +}; + +static struct miscdevice reset_modem_dev = { + .minor = MISC_DYNAMIC_MINOR, + .name = "reset_modem", + .fops = &reset_modem_fops, +}; + +static int __init reset_modem_init(void) +{ + return misc_register(&reset_modem_dev); +} + +module_init(reset_modem_init); + +MODULE_DESCRIPTION("Reset Modem"); +MODULE_LICENSE("GPL v2"); diff --git a/arch/arm/mach-msm/rpc_hsusb.c b/arch/arm/mach-msm/rpc_hsusb.c new file mode 100644 index 000000000000..22dee1c3322b --- /dev/null +++ b/arch/arm/mach-msm/rpc_hsusb.c @@ -0,0 +1,574 @@ +/* linux/arch/arm/mach-msm/rpc_hsusb.c + * + * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * All source code in this file is licensed under the following license except + * where indicated. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License 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. + * You should have received a copy of the GNU General Public License + * along with this program; if not, you can find it at http://www.fsf.org + */ + +#include +#include +#include + +static struct msm_rpc_endpoint *usb_ep; +static struct msm_rpc_endpoint *chg_ep; + +struct msm_chg_rpc_ids { + unsigned long prog; + unsigned long vers_comp; + unsigned chg_usb_charger_connected_proc; + unsigned chg_usb_charger_disconnected_proc; + unsigned chg_usb_i_is_available_proc; + unsigned chg_usb_i_is_not_available_proc; +}; + +struct msm_hsusb_rpc_ids { + unsigned long prog; + unsigned long vers_comp; + unsigned long init_phy; + unsigned long vbus_pwr_up; + unsigned long vbus_pwr_down; + unsigned long update_product_id; + unsigned long update_serial_num; + unsigned long update_is_serial_num_null; + unsigned long reset_rework_installed; + unsigned long enable_pmic_ulpi_data0; + unsigned long disable_pmic_ulpi_data0; +}; + +static struct msm_hsusb_rpc_ids usb_rpc_ids; +static struct msm_chg_rpc_ids chg_rpc_ids; + +static int msm_hsusb_init_rpc_ids(unsigned long vers) +{ + if (vers == 0x00010001) { + usb_rpc_ids.prog = 0x30000064; + usb_rpc_ids.vers_comp = 0x00010001; + usb_rpc_ids.init_phy = 2; + usb_rpc_ids.vbus_pwr_up = 6; + usb_rpc_ids.vbus_pwr_down = 7; + usb_rpc_ids.update_product_id = 8; + usb_rpc_ids.update_serial_num = 9; + usb_rpc_ids.update_is_serial_num_null = 10; + usb_rpc_ids.reset_rework_installed = 17; + usb_rpc_ids.enable_pmic_ulpi_data0 = 18; + usb_rpc_ids.disable_pmic_ulpi_data0 = 19; + return 0; + } else if (vers == 0x00010002) { + usb_rpc_ids.prog = 0x30000064; + usb_rpc_ids.vers_comp = 0x00010002; + usb_rpc_ids.init_phy = 2; + usb_rpc_ids.vbus_pwr_up = 6; + usb_rpc_ids.vbus_pwr_down = 7; + usb_rpc_ids.update_product_id = 8; + usb_rpc_ids.update_serial_num = 9; + usb_rpc_ids.update_is_serial_num_null = 10; + usb_rpc_ids.reset_rework_installed = 17; + usb_rpc_ids.enable_pmic_ulpi_data0 = 18; + usb_rpc_ids.disable_pmic_ulpi_data0 = 19; + return 0; + } else { + printk(KERN_INFO "%s: no matches found for version\n", + __func__); + return -ENODATA; + } +} + +static int msm_chg_init_rpc_ids(unsigned long vers) +{ + if (vers == 0x00010001) { + chg_rpc_ids.prog = 0x3000001a; + chg_rpc_ids.vers_comp = 0x00010001; + chg_rpc_ids.chg_usb_charger_connected_proc = 7; + chg_rpc_ids.chg_usb_charger_disconnected_proc = 8; + chg_rpc_ids.chg_usb_i_is_available_proc = 9; + chg_rpc_ids.chg_usb_i_is_not_available_proc = 10; + return 0; + } else { + printk(KERN_INFO "%s: no matches found for version\n", + __func__); + return -ENODATA; + } +} +EXPORT_SYMBOL(msm_chg_init_rpc_ids); + +/* rpc connect for hsusb */ +int msm_hsusb_rpc_connect(void) +{ + + if (usb_ep && !IS_ERR(usb_ep)) { + printk(KERN_INFO "%s: usb_ep already connected\n", __func__); + return 0; + } + + /* Initialize rpc ids */ + if (msm_hsusb_init_rpc_ids(0x00010001)) { + printk(KERN_ERR "%s: rpc ids initialization failed\n" + , __func__); + return -ENODATA; + } + + usb_ep = msm_rpc_connect_compatible(usb_rpc_ids.prog, + usb_rpc_ids.vers_comp, 0); + + if (IS_ERR(usb_ep)) { + printk(KERN_ERR "%s: connect compatible failed vers = %lx\n", + __func__, usb_rpc_ids.vers_comp); + + /* Initialize rpc ids */ + if (msm_hsusb_init_rpc_ids(0x00010002)) { + printk(KERN_ERR "%s: rpc ids initialization failed\n", + __func__); + return -ENODATA; + } + usb_ep = msm_rpc_connect_compatible(usb_rpc_ids.prog, + usb_rpc_ids.vers_comp, 0); + } + + if (IS_ERR(usb_ep)) { + printk(KERN_ERR "%s: connect compatible failed vers = %lx\n", + __func__, usb_rpc_ids.vers_comp); + return -EAGAIN; + } else + printk(KERN_INFO "%s: rpc connect success vers = %lx\n", + __func__, usb_rpc_ids.vers_comp); + + return 0; +} +EXPORT_SYMBOL(msm_hsusb_rpc_connect); + +/* rpc connect for charging */ +int msm_chg_rpc_connect(void) +{ + + if (machine_is_msm7201a_surf() || machine_is_msm7x27_surf() || + machine_is_qsd8x50_surf()) + return -ENOTSUPP; + + if (chg_ep && !IS_ERR(chg_ep)) { + printk(KERN_INFO "%s: chg_ep already connected\n", __func__); + return 0; + } + + /* Initialize rpc ids */ + if (msm_chg_init_rpc_ids(0x00010001)) { + printk(KERN_ERR "%s: rpc ids initialization failed\n" + , __func__); + return -ENODATA; + } + + chg_ep = msm_rpc_connect_compatible(chg_rpc_ids.prog, + chg_rpc_ids.vers_comp, 0); + + if (IS_ERR(chg_ep)) { + printk(KERN_ERR "%s: connect compatible failed vers = %lx\n", + __func__, chg_rpc_ids.vers_comp); + return -EAGAIN; + } else + printk(KERN_INFO "%s: rpc connect success vers = %lx\n", + __func__, chg_rpc_ids.vers_comp); + + return 0; +} +EXPORT_SYMBOL(msm_chg_rpc_connect); + +/* rpc call for phy_reset */ +int msm_hsusb_phy_reset(void) +{ + int rc = 0; + struct hsusb_phy_start_req { + struct rpc_request_hdr hdr; + } req; + + if (!usb_ep || IS_ERR(usb_ep)) { + printk(KERN_ERR "%s: phy_reset rpc failed before call," + "rc = %ld\n", __func__, PTR_ERR(usb_ep)); + return -EAGAIN; + } + + rc = msm_rpc_call(usb_ep, usb_rpc_ids.init_phy, + &req, sizeof(req), 5 * HZ); + + if (rc < 0) { + printk(KERN_ERR "%s: phy_reset rpc failed! rc = %d\n", + __func__, rc); + } else + printk(KERN_INFO "msm_hsusb_phy_reset\n"); + + return rc; +} +EXPORT_SYMBOL(msm_hsusb_phy_reset); + +/* rpc call for vbus powerup */ +int msm_hsusb_vbus_powerup(void) +{ + int rc = 0; + struct hsusb_phy_start_req { + struct rpc_request_hdr hdr; + } req; + + if (!usb_ep || IS_ERR(usb_ep)) { + printk(KERN_ERR "%s: vbus_powerup rpc failed before call," + "rc = %ld\n", __func__, PTR_ERR(usb_ep)); + return -EAGAIN; + } + + rc = msm_rpc_call(usb_ep, usb_rpc_ids.vbus_pwr_up, + &req, sizeof(req), 5 * HZ); + + if (rc < 0) { + printk(KERN_ERR "%s: vbus_powerup failed! rc = %d\n", + __func__, rc); + } else + printk(KERN_INFO "msm_hsusb_vbus_powerup\n"); + + return rc; +} +EXPORT_SYMBOL(msm_hsusb_vbus_powerup); + +/* rpc call for vbus shutdown */ +int msm_hsusb_vbus_shutdown(void) +{ + int rc = 0; + struct hsusb_phy_start_req { + struct rpc_request_hdr hdr; + } req; + + if (!usb_ep || IS_ERR(usb_ep)) { + printk(KERN_ERR "%s: vbus_shutdown rpc failed before call," + "rc = %ld\n", __func__, PTR_ERR(usb_ep)); + return -EAGAIN; + } + + rc = msm_rpc_call(usb_ep, usb_rpc_ids.vbus_pwr_down, + &req, sizeof(req), 5 * HZ); + + if (rc < 0) { + printk(KERN_ERR "%s: vbus_shutdown failed! rc = %d\n", + __func__, rc); + } else + printk(KERN_INFO "msm_hsusb_vbus_shutdown\n"); + + return rc; +} +EXPORT_SYMBOL(msm_hsusb_vbus_shutdown); + +int msm_hsusb_send_productID(uint32_t product_id) +{ + int rc = 0; + struct hsusb_phy_start_req { + struct rpc_request_hdr hdr; + uint32_t product_id; + } req; + + if (!usb_ep || IS_ERR(usb_ep)) { + printk(KERN_ERR "%s: rpc connect failed: rc = %ld\n", + __func__, PTR_ERR(usb_ep)); + return -EAGAIN; + } + + req.product_id = cpu_to_be32(product_id); + rc = msm_rpc_call(usb_ep, usb_rpc_ids.update_product_id, + &req, sizeof(req), + 5 * HZ); + if (rc < 0) + printk(KERN_ERR "%s: rpc call failed! error: %d\n", + __func__, rc); + else + printk(KERN_ERR "%s: rpc call success\n" , + __func__); + return rc; +} +EXPORT_SYMBOL(msm_hsusb_send_productID); + +int msm_hsusb_send_serial_number(char *serial_number) +{ + int rc = 0, serial_len; + struct hsusb_phy_start_req { + struct rpc_request_hdr hdr; + uint32_t length; + char serial_num[20]; + } req; + + if (!usb_ep || IS_ERR(usb_ep)) { + printk(KERN_ERR "%s: rpc connect failed: rc = %ld\n", + __func__, PTR_ERR(usb_ep)); + return -EAGAIN; + } + + serial_len = strlen(serial_number)+1; + strncpy(req.serial_num, serial_number, 20); + req.length = cpu_to_be32(serial_len); + rc = msm_rpc_call(usb_ep, usb_rpc_ids.update_serial_num, + &req, sizeof(req), + 5 * HZ); + if (rc < 0) + printk(KERN_ERR "%s: rpc call failed! error: %d\n", + __func__, rc); + else + printk(KERN_ERR "%s: rpc call success\n" , + __func__); + return rc; +} +EXPORT_SYMBOL(msm_hsusb_send_serial_number); + +int msm_hsusb_is_serial_num_null(uint32_t val) +{ + int rc = 0; + struct hsusb_phy_start_req { + struct rpc_request_hdr hdr; + uint32_t value; + } req; + + if (!usb_ep || IS_ERR(usb_ep)) { + printk(KERN_ERR "%s: rpc connect failed: rc = %ld\n", + __func__, PTR_ERR(usb_ep)); + return -EAGAIN; + } + if (!usb_rpc_ids.update_is_serial_num_null) { + printk(KERN_ERR "%s: proc id not supported \n", __func__); + return -ENODATA; + } + + req.value = cpu_to_be32(val); + rc = msm_rpc_call(usb_ep, usb_rpc_ids.update_is_serial_num_null, + &req, sizeof(req), + 5 * HZ); + if (rc < 0) + printk(KERN_ERR "%s: rpc call failed! error: %d\n" , + __func__, rc); + else + printk(KERN_ERR "%s: rpc call success\n" , + __func__); + + return rc; +} +EXPORT_SYMBOL(msm_hsusb_is_serial_num_null); + +int msm_chg_usb_charger_connected(uint32_t device) +{ + int rc = 0; + struct hsusb_start_req { + struct rpc_request_hdr hdr; + uint32_t otg_dev; + } req; + + if (!chg_ep || IS_ERR(chg_ep)) + return -EAGAIN; + req.otg_dev = cpu_to_be32(device); + rc = msm_rpc_call(chg_ep, chg_rpc_ids.chg_usb_charger_connected_proc, + &req, sizeof(req), 5 * HZ); + + if (rc < 0) { + printk(KERN_ERR "%s: charger_connected failed! rc = %d\n", + __func__, rc); + } else + printk(KERN_INFO "msm_chg_usb_charger_connected\n"); + + return rc; +} +EXPORT_SYMBOL(msm_chg_usb_charger_connected); + +int msm_chg_usb_i_is_available(uint32_t sample) +{ + int rc = 0; + struct hsusb_start_req { + struct rpc_request_hdr hdr; + uint32_t i_ma; + } req; + + if (!chg_ep || IS_ERR(chg_ep)) + return -EAGAIN; + req.i_ma = cpu_to_be32(sample); + rc = msm_rpc_call(chg_ep, chg_rpc_ids.chg_usb_i_is_available_proc, + &req, sizeof(req), 5 * HZ); + + if (rc < 0) { + printk(KERN_ERR "%s: charger_i_available failed! rc = %d\n", + __func__, rc); + } else + printk(KERN_INFO "msm_chg_usb_i_is_available\n"); + + return rc; +} +EXPORT_SYMBOL(msm_chg_usb_i_is_available); + +int msm_chg_usb_i_is_not_available(void) +{ + int rc = 0; + struct hsusb_start_req { + struct rpc_request_hdr hdr; + } req; + + if (!chg_ep || IS_ERR(chg_ep)) + return -EAGAIN; + rc = msm_rpc_call(chg_ep, chg_rpc_ids.chg_usb_i_is_not_available_proc, + &req, sizeof(req), 5 * HZ); + + if (rc < 0) { + printk(KERN_ERR "%s: charger_i_not_available failed! rc =" + "%d \n", __func__, rc); + } else + printk(KERN_INFO "msm_chg_usb_i_is_not_available\n"); + + return rc; +} +EXPORT_SYMBOL(msm_chg_usb_i_is_not_available); + +int msm_chg_usb_charger_disconnected(void) +{ + int rc = 0; + struct hsusb_start_req { + struct rpc_request_hdr hdr; + } req; + + if (!chg_ep || IS_ERR(chg_ep)) + return -EAGAIN; + rc = msm_rpc_call(chg_ep, chg_rpc_ids.chg_usb_charger_disconnected_proc, + &req, sizeof(req), 5 * HZ); + + if (rc < 0) { + printk(KERN_ERR "%s: charger_disconnected failed! rc = %d\n", + __func__, rc); + } else + printk(KERN_INFO "msm_chg_usb_charger_disconnected\n"); + + return rc; +} +EXPORT_SYMBOL(msm_chg_usb_charger_disconnected); + +/* rpc call to close connection */ +int msm_hsusb_rpc_close(void) +{ + int rc = 0; + + if (IS_ERR(usb_ep)) { + printk(KERN_ERR "%s: rpc_close failed before call, rc = %ld\n", + __func__, PTR_ERR(usb_ep)); + return -EAGAIN; + } + + rc = msm_rpc_close(usb_ep); + usb_ep = NULL; + + if (rc < 0) { + printk(KERN_ERR "%s: close rpc failed! rc = %d\n", + __func__, rc); + return -EAGAIN; + } else + printk(KERN_INFO "rpc close success\n"); + + return rc; +} +EXPORT_SYMBOL(msm_hsusb_rpc_close); + +/* rpc call to close charging connection */ +int msm_chg_rpc_close(void) +{ + int rc = 0; + + if (IS_ERR(chg_ep)) { + printk(KERN_ERR "%s: rpc_close failed before call, rc = %ld\n", + __func__, PTR_ERR(chg_ep)); + return -EAGAIN; + } + + rc = msm_rpc_close(chg_ep); + chg_ep = NULL; + + if (rc < 0) { + printk(KERN_ERR "%s: close rpc failed! rc = %d\n", + __func__, rc); + return -EAGAIN; + } else + printk(KERN_INFO "rpc close success\n"); + + return rc; +} +EXPORT_SYMBOL(msm_chg_rpc_close); + +int msm_hsusb_reset_rework_installed(void) +{ + int rc = 0; + struct hsusb_start_req { + struct rpc_request_hdr hdr; + } req; + struct hsusb_rpc_rep { + struct rpc_reply_hdr hdr; + uint32_t rework; + } rep; + + memset(&rep, 0, sizeof(rep)); + + if (!usb_ep || IS_ERR(usb_ep)) { + pr_err("%s: hsusb rpc connection not initialized, rc = %ld\n", + __func__, PTR_ERR(usb_ep)); + return -EAGAIN; + } + + rc = msm_rpc_call_reply(usb_ep, usb_rpc_ids.reset_rework_installed, + &req, sizeof(req), + &rep, sizeof(rep), 5 * HZ); + + if (rc < 0) { + pr_err("%s: rpc call failed! error: (%d)" + "proc id: (%lx)\n", + __func__, rc, + usb_rpc_ids.reset_rework_installed); + return rc; + } + + pr_info("%s: rework: (%d)\n", __func__, rep.rework); + return be32_to_cpu(rep.rework); +} +EXPORT_SYMBOL(msm_hsusb_reset_rework_installed); + +static int msm_hsusb_pmic_ulpidata0_config(int enable) +{ + int rc = 0; + struct hsusb_start_req { + struct rpc_request_hdr hdr; + } req; + + if (!usb_ep || IS_ERR(usb_ep)) { + pr_err("%s: hsusb rpc connection not initialized, rc = %ld\n", + __func__, PTR_ERR(usb_ep)); + return -EAGAIN; + } + + if (enable) + rc = msm_rpc_call(usb_ep, usb_rpc_ids.enable_pmic_ulpi_data0, + &req, sizeof(req), 5 * HZ); + else + rc = msm_rpc_call(usb_ep, usb_rpc_ids.disable_pmic_ulpi_data0, + &req, sizeof(req), 5 * HZ); + + if (rc < 0) + pr_err("%s: rpc call failed! error: %d\n", + __func__, rc); + return rc; +} + +int msm_hsusb_enable_pmic_ulpidata0(void) +{ + return msm_hsusb_pmic_ulpidata0_config(1); +} +EXPORT_SYMBOL(msm_hsusb_enable_pmic_ulpidata0); + +int msm_hsusb_disable_pmic_ulpidata0(void) +{ + return msm_hsusb_pmic_ulpidata0_config(0); +} +EXPORT_SYMBOL(msm_hsusb_disable_pmic_ulpidata0); diff --git a/arch/arm/mach-msm/rpc_server_dog_keepalive.c b/arch/arm/mach-msm/rpc_server_dog_keepalive.c index a04a380e1ff0..5e0f46da379d 100644 --- a/arch/arm/mach-msm/rpc_server_dog_keepalive.c +++ b/arch/arm/mach-msm/rpc_server_dog_keepalive.c @@ -1,6 +1,7 @@ /* arch/arm/mach-msm/rpc_server_dog_keepalive.c * * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2009, Code Aurora Forum. All rights reserved. * Author: Iliyan Malchev * * This software is licensed under the terms of the GNU General Public @@ -21,8 +22,6 @@ /* dog_keepalive server definitions */ #define DOG_KEEPALIVE_PROG 0x30000015 -#define RPC_DOG_KEEPALIVE_NULL 0 - #if CONFIG_MSM_AMSS_VERSION==6210 #define DOG_KEEPALIVE_VERS 0 #define RPC_DOG_KEEPALIVE_BEACON 1 @@ -32,6 +31,11 @@ #else #error "Unsupported AMSS version" #endif +#define DOG_KEEPALIVE_VERS_COMP 0x00010001 +#define RPC_DOG_KEEPALIVE_NULL 0 + + +/* TODO: Remove server registration with _VERS when modem is upated with _COMP*/ static int handle_rpc_call(struct msm_rpc_server *server, struct rpc_request_hdr *req, unsigned len) @@ -40,22 +44,33 @@ static int handle_rpc_call(struct msm_rpc_server *server, case RPC_DOG_KEEPALIVE_NULL: return 0; case RPC_DOG_KEEPALIVE_BEACON: - printk(KERN_INFO "DOG KEEPALIVE PING\n"); return 0; default: return -ENODEV; } } -static struct msm_rpc_server rpc_server = { - .prog = DOG_KEEPALIVE_PROG, - .vers = DOG_KEEPALIVE_VERS, - .rpc_call = handle_rpc_call, +static struct msm_rpc_server rpc_server[] = { + { + .prog = DOG_KEEPALIVE_PROG, + .vers = DOG_KEEPALIVE_VERS, + .rpc_call = handle_rpc_call, + }, + { + .prog = DOG_KEEPALIVE_PROG, + .vers = DOG_KEEPALIVE_VERS_COMP, + .rpc_call = handle_rpc_call, + }, }; static int __init rpc_server_init(void) { - return msm_rpc_create_server(&rpc_server); + /* Dual server registration to support backwards compatibility vers */ + int ret; + ret = msm_rpc_create_server(&rpc_server[1]); + if (ret < 0) + return ret; + return msm_rpc_create_server(&rpc_server[0]); } diff --git a/arch/arm/mach-msm/rpc_server_handset.c b/arch/arm/mach-msm/rpc_server_handset.c new file mode 100644 index 000000000000..4b97c6a4f7e7 --- /dev/null +++ b/arch/arm/mach-msm/rpc_server_handset.c @@ -0,0 +1,188 @@ +/* arch/arm/mach-msm/rpc_server_handset.c + * + * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * You should have received a copy of the GNU General Public License + * along with this program; if not, you can find it at http://www.fsf.org. + */ + +#include +#include + +#include +#include +#include + +#include "keypad-surf-ffa.h" + +#define HS_SERVER_PROG 0x30000062 +#define HS_SERVER_VERS 0x00010001 + +#define RPC_KEYPAD_NULL_PROC 0 +#define RPC_KEYPAD_PASS_KEY_CODE_PROC 2 +#define RPC_KEYPAD_SET_PWR_KEY_STATE_PROC 3 + +#define HS_PWR_K 0x6F /* Power key */ +#define HS_END_K 0x51 /* End key or Power key */ +#define HS_STEREO_HEADSET_K 0x82 +#define HS_HEADSET_SWITCH_K 0x84 +#define HS_REL_K 0xFF /* key release */ + +#define KEY(hs_key, input_key) ((hs_key << 24) | input_key) + +static const uint32_t hs_key_map[] = { + KEY(HS_PWR_K, KEY_POWER), + KEY(HS_END_K, KEY_END), + KEY(HS_STEREO_HEADSET_K, SW_HEADPHONE_INSERT), + KEY(HS_HEADSET_SWITCH_K, KEY_MEDIA), + 0 +}; + +static struct input_dev *kpdev; +static struct input_dev *hsdev; + +static int hs_find_key(uint32_t hscode) +{ + int i, key; + + key = KEY(hscode, 0); + + for (i = 0; hs_key_map[i] != 0; i++) { + if ((hs_key_map[i] & 0xff000000) == key) + return hs_key_map[i] & 0x00ffffff; + } + return -1; +} + +static void +report_headset_switch(struct input_dev *dev, int key, int value) +{ + struct msm_handset *hs = input_get_drvdata(dev); + + input_report_switch(dev, key, value); + switch_set_state(&hs->sdev, value); + input_sync(dev); +} + +/* + * tuple format: (key_code, key_param) + * + * old-architecture: + * key-press = (key_code, 0) + * key-release = (0xff, key_code) + * + * new-architecutre: + * key-press = (key_code, 0) + * key-release = (key_code, 0xff) + */ +static void report_hs_key(uint32_t key_code, uint32_t key_parm) +{ + int key, temp_key_code; + + if (key_code == HS_REL_K) + key = hs_find_key(key_parm); + else + key = hs_find_key(key_code); + + temp_key_code = key_code; + + if (key_parm == HS_REL_K) + key_code = key_parm; + + switch (key) { + case KEY_POWER: + case KEY_END: + if (!kpdev) { + printk(KERN_ERR "%s: No input device for reporting " + "pwr/end key press\n", __func__); + return; + } + input_report_key(kpdev, key, (key_code != HS_REL_K)); + input_sync(kpdev); + break; + case SW_HEADPHONE_INSERT: + if (!hsdev) { + printk(KERN_ERR "%s: No input device for reporting " + "handset events\n", __func__); + return; + } + report_headset_switch(hsdev, key, (key_code != HS_REL_K)); + break; + case KEY_MEDIA: + if (!hsdev) { + printk(KERN_ERR "%s: No input device for reporting " + "handset events\n", __func__); + return; + } + input_report_key(hsdev, key, (key_code != HS_REL_K)); + input_sync(hsdev); + break; + case -1: + printk(KERN_ERR "%s: No mapping for remote handset event %d\n", + __func__, temp_key_code); + break; + default: + printk(KERN_ERR "%s: Unhandled handset key %d\n", __func__, + key); + } +} + +static int handle_hs_rpc_call(struct msm_rpc_server *server, + struct rpc_request_hdr *req, unsigned len) +{ + struct rpc_keypad_pass_key_code_args { + uint32_t key_code; + uint32_t key_parm; + }; + + kpdev = msm_keypad_get_input_dev(); + hsdev = msm_get_handset_input_dev(); + + switch (req->procedure) { + case RPC_KEYPAD_NULL_PROC: + return 0; + + case RPC_KEYPAD_PASS_KEY_CODE_PROC: { + struct rpc_keypad_pass_key_code_args *args; + + args = (struct rpc_keypad_pass_key_code_args *)(req + 1); + args->key_code = be32_to_cpu(args->key_code); + args->key_parm = be32_to_cpu(args->key_parm); + + report_hs_key(args->key_code, args->key_parm); + + return 0; + } + + case RPC_KEYPAD_SET_PWR_KEY_STATE_PROC: + /* This RPC function must be available for the ARM9 + * to function properly. This function is redundant + * when RPC_KEYPAD_PASS_KEY_CODE_PROC is handled. So + * input_report_key is not needed. + */ + return 0; + default: + return -ENODEV; + } +} + +static struct msm_rpc_server hs_rpc_server = { + .prog = HS_SERVER_PROG, + .vers = HS_SERVER_VERS, + .rpc_call = handle_hs_rpc_call, +}; + +static int __init hs_rpc_server_init(void) +{ + return msm_rpc_create_server(&hs_rpc_server); +} +module_init(hs_rpc_server_init); diff --git a/arch/arm/mach-msm/rpc_server_time_remote.c b/arch/arm/mach-msm/rpc_server_time_remote.c index a833f83dfedb..5e9719a085cf 100644 --- a/arch/arm/mach-msm/rpc_server_time_remote.c +++ b/arch/arm/mach-msm/rpc_server_time_remote.c @@ -1,6 +1,7 @@ /* arch/arm/mach-msm/rpc_server_time_remote.c * * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2009, Code Aurora Forum. All rights reserved. * Author: Iliyan Malchev * * This software is licensed under the terms of the GNU General Public @@ -17,13 +18,11 @@ #include #include #include +#include "rpc_server_time_remote.h" /* time_remote_mtoa server definitions. */ #define TIME_REMOTE_MTOA_PROG 0x3000005d -#define RPC_TIME_REMOTE_MTOA_NULL 0 -#define RPC_TIME_TOD_SET_APPS_BASES 2 - #if CONFIG_MSM_AMSS_VERSION==6210 #define TIME_REMOTE_MTOA_VERS 0 #elif (CONFIG_MSM_AMSS_VERSION==6220) || (CONFIG_MSM_AMSS_VERSION==6225) @@ -31,6 +30,9 @@ #else #error "Unknown AMSS version" #endif +#define TIME_REMOTE_MTOA_VERS_COMP 0x00010001 +#define RPC_TIME_REMOTE_MTOA_NULL 0 +#define RPC_TIME_TOD_SET_APPS_BASES 2 struct rpc_time_tod_set_apps_bases_args { uint32_t tick; @@ -53,6 +55,7 @@ static int handle_rpc_call(struct msm_rpc_server *server, "\ttick = %d\n" "\tstamp = %lld\n", args->tick, args->stamp); + rtc_hctosys(); return 0; } default: @@ -60,15 +63,27 @@ static int handle_rpc_call(struct msm_rpc_server *server, } } -static struct msm_rpc_server rpc_server = { - .prog = TIME_REMOTE_MTOA_PROG, - .vers = TIME_REMOTE_MTOA_VERS, - .rpc_call = handle_rpc_call, +static struct msm_rpc_server rpc_server[] = { + { + .prog = TIME_REMOTE_MTOA_PROG, + .vers = TIME_REMOTE_MTOA_VERS, + .rpc_call = handle_rpc_call, + }, + { + .prog = TIME_REMOTE_MTOA_PROG, + .vers = TIME_REMOTE_MTOA_VERS_COMP, + .rpc_call = handle_rpc_call, + }, }; static int __init rpc_server_init(void) { - return msm_rpc_create_server(&rpc_server); + /* Dual server registration to support backwards compatibility vers */ + int ret; + ret = msm_rpc_create_server(&rpc_server[1]); + if (ret < 0) + return ret; + return msm_rpc_create_server(&rpc_server[0]); } diff --git a/arch/arm/mach-msm/rpc_server_time_remote.h b/arch/arm/mach-msm/rpc_server_time_remote.h new file mode 100644 index 000000000000..056666f50013 --- /dev/null +++ b/arch/arm/mach-msm/rpc_server_time_remote.h @@ -0,0 +1,21 @@ +/* arch/arm/mach-msm/rpc_server_time_remote.h + * + * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#ifndef __ARCH_ARM_MACH_MSM_RPC_SERVER_TIME_REMOTE_H +#define __ARCH_ARM_MACH_MSM_RPC_SERVER_TIME_REMOTE_H + +int rtc_hctosys(void); + +#endif diff --git a/arch/arm/mach-msm/sirc.c b/arch/arm/mach-msm/sirc.c new file mode 100644 index 000000000000..5a64aa44ddbe --- /dev/null +++ b/arch/arm/mach-msm/sirc.c @@ -0,0 +1,239 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#include + +static void sirc_irq_mask(unsigned int irq); +static void sirc_irq_unmask(unsigned int irq); +static void sirc_irq_ack(unsigned int irq); +static int sirc_irq_set_wake(unsigned int irq, unsigned int on); +static int sirc_irq_set_type(unsigned int irq, unsigned int flow_type); +static void sirc_irq_handler(unsigned int irq, struct irq_desc *desc); + +static unsigned int int_enable; +static unsigned int wake_enable; + +static struct sirc_regs_t sirc_regs = { + .int_enable = SPSS_SIRC_INT_ENABLE, + .int_enable_clear = SPSS_SIRC_INT_ENABLE_CLEAR, + .int_enable_set = SPSS_SIRC_INT_ENABLE_SET, + .int_type = SPSS_SIRC_INT_TYPE, + .int_polarity = SPSS_SIRC_INT_POLARITY, + .int_clear = SPSS_SIRC_INT_CLEAR, +}; + +static struct sirc_cascade_regs sirc_reg_table[] = { + { + .int_status = SPSS_SIRC_IRQ_STATUS, + .cascade_irq = INT_SIRC_0, + } +}; + +static unsigned int save_type; +static unsigned int save_polarity; + +/* Mask off the given interrupt. Keep the int_enable mask in sync with + the enable reg, so it can be restored after power collapse. */ +static void sirc_irq_mask(unsigned int irq) +{ + unsigned int mask; + + + mask = 1 << (irq - FIRST_SIRC_IRQ); + writel(mask, sirc_regs.int_enable_clear); + int_enable &= ~mask; + return; +} + +/* Unmask the given interrupt. Keep the int_enable mask in sync with + the enable reg, so it can be restored after power collapse. */ +static void sirc_irq_unmask(unsigned int irq) +{ + unsigned int mask; + + mask = 1 << (irq - FIRST_SIRC_IRQ); + writel(mask, sirc_regs.int_enable_set); + int_enable |= mask; + return; +} + +static void sirc_irq_ack(unsigned int irq) +{ + unsigned int mask; + + mask = 1 << (irq - FIRST_SIRC_IRQ); + writel(mask, sirc_regs.int_clear); + return; +} + +static int sirc_irq_set_wake(unsigned int irq, unsigned int on) +{ + unsigned int mask; + + /* Used to set the interrupt enable mask during power collapse. */ + mask = 1 << (irq - FIRST_SIRC_IRQ); + if (on) + wake_enable |= mask; + else + wake_enable &= ~mask; + + return 0; +} + +static int sirc_irq_set_type(unsigned int irq, unsigned int flow_type) +{ + unsigned int mask; + unsigned int val; + + mask = 1 << (irq - FIRST_SIRC_IRQ); + val = readl(sirc_regs.int_polarity); + + if (flow_type & (IRQF_TRIGGER_LOW | IRQF_TRIGGER_FALLING)) + val |= mask; + else + val &= ~mask; + + writel(val, sirc_regs.int_polarity); + + val = readl(sirc_regs.int_type); + if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) { + val |= mask; + irq_desc[irq].handle_irq = handle_edge_irq; + } else { + val &= ~mask; + irq_desc[irq].handle_irq = handle_level_irq; + } + + writel(val, sirc_regs.int_type); + + return 0; +} + +/* Finds the pending interrupt on the passed cascade irq and redrives it */ +static void sirc_irq_handler(unsigned int irq, struct irq_desc *desc) +{ + unsigned int reg = 0; + unsigned int sirq; + unsigned int status; + + while ((reg < ARRAY_SIZE(sirc_reg_table)) && + (sirc_reg_table[reg].cascade_irq != irq)) + reg++; + + status = readl(sirc_reg_table[reg].int_status); + status &= SIRC_MASK; + if (status == 0) + return; + + for (sirq = 0; + (sirq < NR_SIRC_IRQS) && ((status & (1U << sirq)) == 0); + sirq++) + ; + generic_handle_irq(sirq+FIRST_SIRC_IRQ); + + desc->chip->ack(irq); +} + +void msm_sirc_enter_sleep(void) +{ + save_type = readl(sirc_regs.int_type); + save_polarity = readl(sirc_regs.int_polarity); + writel(wake_enable, sirc_regs.int_enable); + return; +} + +void msm_sirc_exit_sleep(void) +{ + writel(save_type, sirc_regs.int_type); + writel(save_polarity, sirc_regs.int_polarity); + writel(int_enable, sirc_regs.int_enable); + return; +} + +static struct irq_chip sirc_irq_chip = { + .name = "sirc", + .ack = sirc_irq_ack, + .mask = sirc_irq_mask, + .unmask = sirc_irq_unmask, + .set_wake = sirc_irq_set_wake, + .set_type = sirc_irq_set_type, +}; + +void __init msm_init_sirc(void) +{ + int i; + + int_enable = 0; + wake_enable = 0; + + for (i = FIRST_SIRC_IRQ; i < LAST_SIRC_IRQ; i++) { + set_irq_chip(i, &sirc_irq_chip); + set_irq_handler(i, handle_edge_irq); + set_irq_flags(i, IRQF_VALID); + } + + for (i = 0; i < ARRAY_SIZE(sirc_reg_table); i++) { + set_irq_chained_handler(sirc_reg_table[i].cascade_irq, + sirc_irq_handler); + set_irq_wake(sirc_reg_table[i].cascade_irq, 1); + } + return; +} + diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c index 64d12323995e..609a7f19893c 100644 --- a/arch/arm/mach-msm/smd.c +++ b/arch/arm/mach-msm/smd.c @@ -1,6 +1,7 @@ /* arch/arm/mach-msm/smd.c * * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. * Author: Brian Swetland * * This software is licensed under the terms of the GNU General Public @@ -26,90 +27,144 @@ #include #include #include -#include - +#include +#include #include #include #include +#include #include "smd_private.h" #include "proc_comm.h" - -void (*msm_hw_reset_hook)(void); +#include "modem_notifier.h" #define MODULE_NAME "msm_smd" +#define SMEM_VERSION 0x000B +#define SMD_VERSION 0x00020000 enum { MSM_SMD_DEBUG = 1U << 0, MSM_SMSM_DEBUG = 1U << 0, }; -static int msm_smd_debug_mask; +enum { + SMEM_APPS_Q6_SMSM = 3, + SMEM_Q6_APPS_SMSM = 5, + SMSM_NUM_INTR_MUX = 8, +}; + +/* Internal definitions which are not exported in some targets */ +enum { + SMSM_Q6_I = 2, +}; -module_param_named(debug_mask, msm_smd_debug_mask, - int, S_IRUGO | S_IWUSR | S_IWGRP); +enum { + SMSM_APPS_DEM_I = 3, +}; + +enum { + SMD_APPS_QDSP_I = 1, + SMD_MODEM_QDSP_I = 2 +}; + +static int msm_smd_debug_mask; +module_param_named(debug_mask, msm_smd_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP); void *smem_find(unsigned id, unsigned size); -static void smd_diag(void); +void smd_diag(void); static unsigned last_heap_free = 0xffffffff; +#if 0 +#define D(x...) printk(x) +#else +#define D(x...) do {} while (0) +#endif + #define MSM_A2M_INT(n) (MSM_CSR_BASE + 0x400 + (n) * 4) -static inline void notify_other_smsm(void) -{ - writel(1, MSM_A2M_INT(5)); +static void notify_other_smsm(uint32_t smsm_entry, + uint32_t old_val, uint32_t new_val) +{ + uint32_t *smsm_intr_mask; + uint32_t *smsm_intr_mux; + + smsm_intr_mask = smem_alloc(SMEM_SMSM_CPU_INTR_MASK, + SMSM_NUM_ENTRIES * SMSM_NUM_HOSTS * + sizeof(uint32_t)); + + /* older protocol don't use smsm_intr_mask, + but still communicates with modem */ + if (!smsm_intr_mask || + (smsm_intr_mask[smsm_entry * SMSM_NUM_HOSTS + SMSM_MODEM] & + (old_val ^ new_val))) + writel(1, MSM_A2M_INT(5)); + + if (smsm_intr_mask && + (smsm_intr_mask[smsm_entry * SMSM_NUM_HOSTS + SMSM_Q6_I] & + (old_val ^ new_val))) { + smsm_intr_mux = smem_alloc(SMEM_SMD_SMSM_INTR_MUX, + SMSM_NUM_INTR_MUX * + sizeof(uint32_t)); + if (smsm_intr_mux) + smsm_intr_mux[SMEM_APPS_Q6_SMSM]++; + + writel(1, MSM_A2M_INT(8)); + } } -static inline void notify_other_smd(void) +static inline void notify_other_smd(uint32_t ch_type) { - writel(1, MSM_A2M_INT(0)); + if (ch_type == SMD_APPS_MODEM) + writel(1, MSM_A2M_INT(0)); + else if (ch_type == SMD_APPS_QDSP_I) + writel(1, MSM_A2M_INT(8)); } -static void smd_diag(void) +void smd_diag(void) { char *x; + int size; x = smem_find(ID_DIAG_ERR_MSG, SZ_DIAG_ERR_MSG); if (x != 0) { x[SZ_DIAG_ERR_MSG - 1] = 0; - pr_info("smem: DIAG '%s'\n", x); + printk("smem: DIAG '%s'\n", x); } -} -/* call when SMSM_RESET flag is set in the A9's smsm_state */ -static void handle_modem_crash(void) -{ - pr_err("ARM9 has CRASHED\n"); - smd_diag(); - - /* hard reboot if possible */ - if (msm_hw_reset_hook) - msm_hw_reset_hook(); - - /* in this case the modem or watchdog should reboot us */ - for (;;) - ; + x = smem_get_entry(SMEM_ERR_CRASH_LOG, &size); + if (x != 0) { + x[size - 1] = 0; + printk(KERN_ERR "smem: CRASH LOG\n'%s'\n", x); + } } extern int (*msm_check_for_modem_crash)(void); static int check_for_modem_crash(void) { - struct smsm_shared *smsm; + uint32_t *smsm; - smsm = smem_find(ID_SHARED_STATE, 2 * sizeof(struct smsm_shared)); + smsm = smem_find(ID_SHARED_STATE, SMSM_NUM_ENTRIES * sizeof(uint32_t)); /* if the modem's not ready yet, we have to hope for the best */ if (!smsm) return 0; - if (smsm[1].state & SMSM_RESET) { - handle_modem_crash(); - return -1; + if (smsm[SMSM_MODEM_STATE] & SMSM_RESET) { + pr_err("proc_comm: ARM9 has crashed\n"); + smd_diag(); } else { return 0; } + + /* hard reboot if possible FIXME + if (msm_reset_hook) + msm_reset_hook(0); + */ + + for (;;) + ; } #define SMD_SS_CLOSED 0x00000000 @@ -141,13 +196,22 @@ static DEFINE_MUTEX(smd_creation_mutex); static int smd_initialized; +/* 'type' field of smd_alloc_elm structure + * has the following breakup + * bits 0-7 -> channel type + * bits 8-11 -> xfer type + * bits 12-31 -> reserved + */ struct smd_alloc_elm { char name[20]; uint32_t cid; - uint32_t ctype; + uint32_t type; uint32_t ref_count; }; +#define SMD_CHANNEL_TYPE(x) ((x) & 0x000000FF) +#define SMD_XFER_TYPE(x) (((x) & 0x00000F00) >> 8) + struct smd_half_channel { unsigned state; unsigned char fDSR; @@ -160,17 +224,14 @@ struct smd_half_channel { unsigned char fUNUSED; unsigned tail; unsigned head; - unsigned char data[SMD_BUF_SIZE]; -}; - -struct smd_shared { - struct smd_half_channel ch0; - struct smd_half_channel ch1; }; struct smd_channel { volatile struct smd_half_channel *send; volatile struct smd_half_channel *recv; + unsigned char *send_buf; + unsigned char *recv_buf; + unsigned buf_size; struct list_head ch_list; unsigned current_packet; @@ -182,12 +243,14 @@ struct smd_channel { int (*write)(smd_channel_t *ch, const void *data, int len); int (*read_avail)(smd_channel_t *ch); int (*write_avail)(smd_channel_t *ch); + int (*read_from_cb)(smd_channel_t *ch, void *data, int len); void (*update_state)(smd_channel_t *ch); unsigned last_state; - char name[32]; + char name[20]; struct platform_device pdev; + unsigned type; }; static LIST_HEAD(smd_ch_closed_list); @@ -196,7 +259,8 @@ static LIST_HEAD(smd_ch_list); static unsigned char smd_ch_allocated[64]; static struct work_struct probe_work; -static void smd_alloc_channel(const char *name, uint32_t cid, uint32_t type); +static void smd_alloc_channel(struct smd_alloc_elm *alloc_elm); +static void *_smem_find(unsigned id, unsigned *size); static void smd_channel_probe_worker(struct work_struct *work) { @@ -208,13 +272,17 @@ static void smd_channel_probe_worker(struct work_struct *work) for (n = 0; n < 64; n++) { if (smd_ch_allocated[n]) continue; + + /* channel should be allocated only if APPS + processor is involved */ + if (SMD_CHANNEL_TYPE(shared[n].type) == SMD_MODEM_QDSP_I) + continue; if (!shared[n].ref_count) continue; if (!shared[n].name[0]) continue; - smd_alloc_channel(shared[n].name, - shared[n].cid, - shared[n].ctype); + + smd_alloc_channel(&shared[n]); smd_ch_allocated[n] = 1; } } @@ -222,36 +290,28 @@ static void smd_channel_probe_worker(struct work_struct *work) static char *chstate(unsigned n) { switch (n) { - case SMD_SS_CLOSED: - return "CLOSED"; - case SMD_SS_OPENING: - return "OPENING"; - case SMD_SS_OPENED: - return "OPENED"; - case SMD_SS_FLUSHING: - return "FLUSHING"; - case SMD_SS_CLOSING: - return "CLOSING"; - case SMD_SS_RESET: - return "RESET"; - case SMD_SS_RESET_OPENING: - return "ROPENING"; - default: - return "UNKNOWN"; + case SMD_SS_CLOSED: return "CLOSED"; + case SMD_SS_OPENING: return "OPENING"; + case SMD_SS_OPENED: return "OPENED"; + case SMD_SS_FLUSHING: return "FLUSHING"; + case SMD_SS_CLOSING: return "CLOSING"; + case SMD_SS_RESET: return "RESET"; + case SMD_SS_RESET_OPENING: return "ROPENING"; + default: return "UNKNOWN"; } } /* how many bytes are available for reading */ static int smd_stream_read_avail(struct smd_channel *ch) { - return (ch->recv->head - ch->recv->tail) & (SMD_BUF_SIZE - 1); + return (ch->recv->head - ch->recv->tail) & (ch->buf_size - 1); } /* how many bytes we are free to write */ static int smd_stream_write_avail(struct smd_channel *ch) { - return (SMD_BUF_SIZE - 1) - - ((ch->send->head - ch->send->tail) & (SMD_BUF_SIZE - 1)); + return (ch->buf_size - 1) - + ((ch->send->head - ch->send->tail) & (ch->buf_size - 1)); } static int smd_packet_read_avail(struct smd_channel *ch) @@ -274,8 +334,9 @@ static int smd_packet_write_avail(struct smd_channel *ch) static int ch_is_open(struct smd_channel *ch) { - return (ch->recv->state == SMD_SS_OPENED) && - (ch->send->state == SMD_SS_OPENED); + return (ch->recv->state == SMD_SS_OPENED || + ch->recv->state == SMD_SS_FLUSHING) + && (ch->send->state == SMD_SS_OPENED); } /* provide a pointer and length to readable data in the fifo */ @@ -283,20 +344,20 @@ static unsigned ch_read_buffer(struct smd_channel *ch, void **ptr) { unsigned head = ch->recv->head; unsigned tail = ch->recv->tail; - *ptr = (void *) (ch->recv->data + tail); + *ptr = (void *) (ch->recv_buf + tail); if (tail <= head) return head - tail; else - return SMD_BUF_SIZE - tail; + return ch->buf_size - tail; } /* advance the fifo read pointer after data from ch_read_buffer is consumed */ static void ch_read_done(struct smd_channel *ch, unsigned count) { BUG_ON(count > smd_stream_read_avail(ch)); - ch->recv->tail = (ch->recv->tail + count) & (SMD_BUF_SIZE - 1); - ch->recv->fTAIL = 1; + ch->recv->tail = (ch->recv->tail + count) & (ch->buf_size - 1); + ch->send->fTAIL = 1; } /* basic read interface to ch_read_{buffer,done} used @@ -357,42 +418,40 @@ static unsigned ch_write_buffer(struct smd_channel *ch, void **ptr) { unsigned head = ch->send->head; unsigned tail = ch->send->tail; - *ptr = (void *) (ch->send->data + head); + *ptr = (void *) (ch->send_buf + head); if (head < tail) { return tail - head - 1; } else { if (tail == 0) - return SMD_BUF_SIZE - head - 1; + return ch->buf_size - head - 1; else - return SMD_BUF_SIZE - head; + return ch->buf_size - head; } } -/* advace the fifo write pointer after freespace - * from ch_write_buffer is filled - */ +/* advace the fifo write pointer after freespace from ch_write_buffer is filled */ static void ch_write_done(struct smd_channel *ch, unsigned count) { BUG_ON(count > smd_stream_write_avail(ch)); - ch->send->head = (ch->send->head + count) & (SMD_BUF_SIZE - 1); + ch->send->head = (ch->send->head + count) & (ch->buf_size - 1); ch->send->fHEAD = 1; } -static void hc_set_state(volatile struct smd_half_channel *hc, unsigned n) +static void ch_set_state(struct smd_channel *ch, unsigned n) { if (n == SMD_SS_OPENED) { - hc->fDSR = 1; - hc->fCTS = 1; - hc->fCD = 1; + ch->send->fDSR = 1; + ch->send->fCTS = 1; + ch->send->fCD = 1; } else { - hc->fDSR = 0; - hc->fCTS = 0; - hc->fCD = 0; + ch->send->fDSR = 0; + ch->send->fCTS = 0; + ch->send->fCD = 0; } - hc->state = n; - hc->fSTATE = 1; - notify_other_smd(); + ch->send->state = n; + ch->send->fSTATE = 1; + notify_other_smd(ch->type); } static void do_smd_probe(void) @@ -409,22 +468,34 @@ static void smd_state_change(struct smd_channel *ch, { ch->last_state = next; - pr_info("SMD: ch %d %s -> %s\n", ch->n, - chstate(last), chstate(next)); + printk(KERN_INFO "SMD: ch %d %s -> %s\n", ch->n, + chstate(last), chstate(next)); switch (next) { case SMD_SS_OPENING: - ch->recv->tail = 0; + if (ch->send->state == SMD_SS_CLOSING || + ch->send->state == SMD_SS_CLOSED) { + ch->recv->tail = 0; + ch->send->head = 0; + ch_set_state(ch, SMD_SS_OPENING); + } + break; case SMD_SS_OPENED: - if (ch->send->state != SMD_SS_OPENED) - hc_set_state(ch->send, SMD_SS_OPENED); - ch->notify(ch->priv, SMD_EVENT_OPEN); + if (ch->send->state == SMD_SS_OPENING) { + ch_set_state(ch, SMD_SS_OPENED); + ch->notify(ch->priv, SMD_EVENT_OPEN); + } break; case SMD_SS_FLUSHING: case SMD_SS_RESET: /* we should force them to close? */ - default: - ch->notify(ch->priv, SMD_EVENT_CLOSE); + break; + case SMD_SS_CLOSED: + if (ch->send->state == SMD_SS_OPENED) { + ch_set_state(ch, SMD_SS_CLOSING); + ch->notify(ch->priv, SMD_EVENT_CLOSE); + } + break; } } @@ -432,7 +503,8 @@ static irqreturn_t smd_irq_handler(int irq, void *data) { unsigned long flags; struct smd_channel *ch; - int do_notify = 0; + int do_notify_modem = 0; + int do_notify_qdsp = 0; unsigned ch_flags; unsigned tmp; @@ -443,17 +515,26 @@ static irqreturn_t smd_irq_handler(int irq, void *data) if (ch->recv->fHEAD) { ch->recv->fHEAD = 0; ch_flags |= 1; - do_notify |= 1; + if (ch->type == SMD_APPS_MODEM) + do_notify_modem |= 1; + else if (ch->type == SMD_APPS_QDSP_I) + do_notify_qdsp |= 1; } if (ch->recv->fTAIL) { ch->recv->fTAIL = 0; ch_flags |= 2; - do_notify |= 1; + if (ch->type == SMD_APPS_MODEM) + do_notify_modem |= 1; + else if (ch->type == SMD_APPS_QDSP_I) + do_notify_qdsp |= 1; } if (ch->recv->fSTATE) { ch->recv->fSTATE = 0; ch_flags |= 4; - do_notify |= 1; + if (ch->type == SMD_APPS_MODEM) + do_notify_modem |= 1; + else if (ch->type == SMD_APPS_QDSP_I) + do_notify_qdsp |= 1; } } tmp = ch->recv->state; @@ -464,8 +545,12 @@ static irqreturn_t smd_irq_handler(int irq, void *data) ch->notify(ch->priv, SMD_EVENT_DATA); } } - if (do_notify) - notify_other_smd(); + if (do_notify_modem) + notify_other_smd(SMD_APPS_MODEM); + + if (do_notify_qdsp) + notify_other_smd(SMD_APPS_QDSP_I); + spin_unlock_irqrestore(&smd_lock, flags); do_smd_probe(); return IRQ_HANDLED; @@ -490,35 +575,41 @@ void smd_sleep_exit(void) if (ch_is_open(ch)) { if (ch->recv->fHEAD) { if (msm_smd_debug_mask & MSM_SMD_DEBUG) - pr_info("smd_sleep_exit ch %d fHEAD " + printk(KERN_DEBUG + "smd_sleep_exit ch %d fHEAD " "%x %x %x\n", - ch->n, ch->recv->fHEAD, + ch->n, + ch->recv->fHEAD, ch->recv->head, ch->recv->tail); need_int = 1; break; } if (ch->recv->fTAIL) { if (msm_smd_debug_mask & MSM_SMD_DEBUG) - pr_info("smd_sleep_exit ch %d fTAIL " + printk(KERN_DEBUG + "smd_sleep_exit ch %d fTAIL " "%x %x %x\n", - ch->n, ch->recv->fTAIL, + ch->n, + ch->recv->fTAIL, ch->send->head, ch->send->tail); need_int = 1; break; } if (ch->recv->fSTATE) { if (msm_smd_debug_mask & MSM_SMD_DEBUG) - pr_info("smd_sleep_exit ch %d fSTATE %x" - "\n", ch->n, ch->recv->fSTATE); + printk("smd_sleep_exit ch %d fSTATE %x" + "\n", ch->n, + ch->recv->fSTATE); need_int = 1; break; } tmp = ch->recv->state; if (tmp != ch->last_state) { if (msm_smd_debug_mask & MSM_SMD_DEBUG) - pr_info("smd_sleep_exit ch %d " + printk("smd_sleep_exit ch %d " "state %x != %x\n", - ch->n, tmp, ch->last_state); + ch->n, tmp, + ch->last_state); need_int = 1; break; } @@ -528,35 +619,23 @@ void smd_sleep_exit(void) do_smd_probe(); if (need_int) { if (msm_smd_debug_mask & MSM_SMD_DEBUG) - pr_info("smd_sleep_exit need interrupt\n"); + printk("smd_sleep_exit need interrupt\n"); tasklet_schedule(&smd_fake_irq_tasklet); } } - -void smd_kick(smd_channel_t *ch) +static int smd_is_packet(struct smd_alloc_elm *alloc_elm) { - unsigned long flags; - unsigned tmp; + if (SMD_XFER_TYPE(alloc_elm->type) == 1) + return 0; + else if (SMD_XFER_TYPE(alloc_elm->type) == 2) + return 1; - spin_lock_irqsave(&smd_lock, flags); - ch->update_state(ch); - tmp = ch->recv->state; - if (tmp != ch->last_state) { - ch->last_state = tmp; - if (tmp == SMD_SS_OPENED) - ch->notify(ch->priv, SMD_EVENT_OPEN); - else - ch->notify(ch->priv, SMD_EVENT_CLOSE); - } - ch->notify(ch->priv, SMD_EVENT_DATA); - notify_other_smd(); - spin_unlock_irqrestore(&smd_lock, flags); -} + /* for cases where xfer type is 0 */ + if (!strncmp(alloc_elm->name, "DAL", 3)) + return 0; -static int smd_is_packet(int chn) -{ - if ((chn > 4) || (chn == 1)) + if (alloc_elm->cid > 4 || alloc_elm->cid == 1) return 1; else return 0; @@ -569,6 +648,7 @@ static int smd_stream_write(smd_channel_t *ch, const void *_data, int len) unsigned xfer; int orig_len = len; + D("smd_stream_write() %d -> ch%d\n", len, ch->n); if (len < 0) return -EINVAL; @@ -585,15 +665,18 @@ static int smd_stream_write(smd_channel_t *ch, const void *_data, int len) break; } - notify_other_smd(); + if (orig_len - len) + notify_other_smd(ch->type); return orig_len - len; } static int smd_packet_write(smd_channel_t *ch, const void *_data, int len) { + int ret; unsigned hdr[5]; + D("smd_packet_write() %d -> ch%d\n", len, ch->n); if (len < 0) return -EINVAL; @@ -603,8 +686,21 @@ static int smd_packet_write(smd_channel_t *ch, const void *_data, int len) hdr[0] = len; hdr[1] = hdr[2] = hdr[3] = hdr[4] = 0; - smd_stream_write(ch, hdr, sizeof(hdr)); - smd_stream_write(ch, _data, len); + + ret = smd_stream_write(ch, hdr, sizeof(hdr)); + if (ret < 0 || ret != sizeof(hdr)) { + D("%s failed to write pkt header: " + "%d returned\n", __func__, ret); + return -1; + } + + + ret = smd_stream_write(ch, _data, len); + if (ret < 0 || ret != len) { + D("%s failed to write pkt data: " + "%d returned\n", __func__, ret); + return ret; + } return len; } @@ -618,7 +714,7 @@ static int smd_stream_read(smd_channel_t *ch, void *data, int len) r = ch_read(ch, data, len); if (r > 0) - notify_other_smd(); + notify_other_smd(ch->type); return r; } @@ -636,7 +732,7 @@ static int smd_packet_read(smd_channel_t *ch, void *data, int len) r = ch_read(ch, data, len); if (r > 0) - notify_other_smd(); + notify_other_smd(ch->type); spin_lock_irqsave(&smd_lock, flags); ch->current_packet -= r; @@ -646,49 +742,130 @@ static int smd_packet_read(smd_channel_t *ch, void *data, int len) return r; } -static void smd_alloc_channel(const char *name, uint32_t cid, uint32_t type) +static int smd_packet_read_from_cb(smd_channel_t *ch, void *data, int len) +{ + int r; + + if (len < 0) + return -EINVAL; + + if (len > ch->current_packet) + len = ch->current_packet; + + r = ch_read(ch, data, len); + if (r > 0) + notify_other_smd(ch->type); + + ch->current_packet -= r; + update_packet_state(ch); + + return r; +} + +static struct smd_channel *_smd_alloc_channel_v1(uint32_t cid) { struct smd_channel *ch; - struct smd_shared *shared; + void *shared; - shared = smem_alloc(ID_SMD_CHANNELS + cid, sizeof(*shared)); + shared = smem_alloc(ID_SMD_CHANNELS + cid, + 2 * (sizeof(struct smd_half_channel) + + SMD_BUF_SIZE)); if (!shared) { - pr_err("smd_alloc_channel() cid %d does not exist\n", cid); - return; + pr_err("smd_alloc_channel: cid %d does not exist\n", cid); + return NULL; } ch = kzalloc(sizeof(struct smd_channel), GFP_KERNEL); - if (ch == 0) { + if (ch) { + ch->send = shared; + ch->send_buf = shared + sizeof(struct smd_half_channel); + ch->recv = (struct smd_half_channel *) + (ch->send_buf + SMD_BUF_SIZE); + ch->recv_buf = (unsigned char *)ch->recv + + sizeof(struct smd_half_channel); + ch->buf_size = SMD_BUF_SIZE; + ch->n = cid; + } else + pr_err("smd_alloc_channel: out of memory\n"); + + return ch; +} + +static struct smd_channel *_smd_alloc_channel_v2(uint32_t cid) +{ + struct smd_channel *ch; + void *shared, *shared_fifo; + unsigned size; + + shared = smem_alloc(ID_SMD_CHANNELS + cid, + 2 * sizeof(struct smd_half_channel)); + if (!shared) { + pr_err("smd_alloc_channel: cid %d does not exist\n", cid); + return NULL; + } + + shared_fifo = _smem_find(SMEM_SMD_FIFO_BASE_ID + cid, &size); + if (!shared_fifo) { + pr_err("smd_alloc_channel: cid %d fifo do not exist\n", cid); + return NULL; + } + printk(KERN_INFO "smd_alloc_channel: cid %d fifo found; size = %d\n", + cid, (size / 2)); + + ch = kzalloc(sizeof(struct smd_channel), GFP_KERNEL); + if (ch) { + ch->send = shared; + ch->recv = shared + sizeof(struct smd_half_channel); + ch->send_buf = shared_fifo; + ch->recv_buf = shared_fifo + (size / 2); + ch->buf_size = size / 2; + ch->n = cid; + } else pr_err("smd_alloc_channel() out of memory\n"); + + return ch; +} + +static void smd_alloc_channel(struct smd_alloc_elm *alloc_elm) +{ + struct smd_channel *ch; + uint32_t *smd_ver; + + smd_ver = smem_alloc(SMEM_VERSION_SMD, 32 * sizeof(uint32_t)); + + if (smd_ver && ((smd_ver[VERSION_MODEM] >> 16) >= 1)) + ch = _smd_alloc_channel_v2(alloc_elm->cid); + else + ch = _smd_alloc_channel_v1(alloc_elm->cid); + + if (ch == 0) return; - } - ch->send = &shared->ch0; - ch->recv = &shared->ch1; - ch->n = cid; + ch->type = SMD_CHANNEL_TYPE(alloc_elm->type); + memcpy(ch->name, alloc_elm->name, 20); + ch->name[19] = 0; - if (smd_is_packet(cid)) { + if (smd_is_packet(alloc_elm)) { ch->read = smd_packet_read; ch->write = smd_packet_write; ch->read_avail = smd_packet_read_avail; ch->write_avail = smd_packet_write_avail; ch->update_state = update_packet_state; + ch->read_from_cb = smd_packet_read_from_cb; } else { ch->read = smd_stream_read; ch->write = smd_stream_write; ch->read_avail = smd_stream_read_avail; ch->write_avail = smd_stream_write_avail; ch->update_state = update_stream_state; + ch->read_from_cb = smd_stream_read; } - memcpy(ch->name, "SMD_", 4); - memcpy(ch->name + 4, name, 20); - ch->name[23] = 0; ch->pdev.name = ch->name; - ch->pdev.id = -1; + ch->pdev.id = ch->type; - pr_info("smd_alloc_channel() '%s' cid=%d, shared=%p\n", - ch->name, ch->n, shared); + pr_info("smd_alloc_channel() '%s' cid=%d\n", + ch->name, ch->n); mutex_lock(&smd_creation_mutex); list_add(&ch->ch_list, &smd_ch_closed_list); @@ -701,13 +878,14 @@ static void do_nothing_notify(void *priv, unsigned flags) { } -struct smd_channel *smd_get_channel(const char *name) +struct smd_channel *smd_get_channel(const char *name, uint32_t type) { struct smd_channel *ch; mutex_lock(&smd_creation_mutex); list_for_each_entry(ch, &smd_ch_closed_list, ch_list) { - if (!strcmp(name, ch->name)) { + if (!strcmp(name, ch->name) && + (type == ch->type)) { list_del(&ch->ch_list); mutex_unlock(&smd_creation_mutex); return ch; @@ -718,18 +896,21 @@ struct smd_channel *smd_get_channel(const char *name) return NULL; } -int smd_open(const char *name, smd_channel_t **_ch, - void *priv, void (*notify)(void *, unsigned)) +int smd_named_open_on_edge(const char *name, uint32_t edge, + smd_channel_t **_ch, + void *priv, void (*notify)(void *, unsigned)) { struct smd_channel *ch; unsigned long flags; if (smd_initialized == 0) { - pr_info("smd_open() before smd_init()\n"); + printk(KERN_INFO "smd_open() before smd_init()\n"); return -ENODEV; } - ch = smd_get_channel(name); + D("smd_open('%s', %p, %p)\n", name, priv, notify); + + ch = smd_get_channel(name, edge); if (!ch) return -ENODEV; @@ -743,34 +924,34 @@ int smd_open(const char *name, smd_channel_t **_ch, *_ch = ch; + D("smd_open: opening '%s'\n", ch->name); + spin_lock_irqsave(&smd_lock, flags); list_add(&ch->ch_list, &smd_ch_list); + D("%s: opening ch %d\n", __func__, ch->n); + + smd_state_change(ch, ch->last_state, SMD_SS_OPENING); - /* If the remote side is CLOSING, we need to get it to - * move to OPENING (which we'll do by moving from CLOSED to - * OPENING) and then get it to move from OPENING to - * OPENED (by doing the same state change ourselves). - * - * Otherwise, it should be OPENING and we can move directly - * to OPENED so that it will follow. - */ - if (ch->recv->state == SMD_SS_CLOSING) { - ch->send->head = 0; - hc_set_state(ch->send, SMD_SS_OPENING); - } else { - hc_set_state(ch->send, SMD_SS_OPENED); - } spin_unlock_irqrestore(&smd_lock, flags); - smd_kick(ch); return 0; } +EXPORT_SYMBOL(smd_named_open_on_edge); + + +int smd_open(const char *name, smd_channel_t **_ch, + void *priv, void (*notify)(void *, unsigned)) +{ + return smd_named_open_on_edge(name, SMD_APPS_MODEM, _ch, priv, + notify); +} +EXPORT_SYMBOL(smd_open); int smd_close(smd_channel_t *ch) { unsigned long flags; - pr_info("smd_close(%p)\n", ch); + printk(KERN_INFO "smd_close(%p)\n", ch); if (ch == 0) return -1; @@ -778,7 +959,7 @@ int smd_close(smd_channel_t *ch) spin_lock_irqsave(&smd_lock, flags); ch->notify = do_nothing_notify; list_del(&ch->ch_list); - hc_set_state(ch->send, SMD_SS_CLOSED); + ch_set_state(ch, SMD_SS_CLOSED); spin_unlock_irqrestore(&smd_lock, flags); mutex_lock(&smd_creation_mutex); @@ -787,26 +968,37 @@ int smd_close(smd_channel_t *ch) return 0; } +EXPORT_SYMBOL(smd_close); int smd_read(smd_channel_t *ch, void *data, int len) { return ch->read(ch, data, len); } +EXPORT_SYMBOL(smd_read); + +int smd_read_from_cb(smd_channel_t *ch, void *data, int len) +{ + return ch->read_from_cb(ch, data, len); +} +EXPORT_SYMBOL(smd_read_from_cb); int smd_write(smd_channel_t *ch, const void *data, int len) { return ch->write(ch, data, len); } +EXPORT_SYMBOL(smd_write); int smd_read_avail(smd_channel_t *ch) { return ch->read_avail(ch); } +EXPORT_SYMBOL(smd_read_avail); int smd_write_avail(smd_channel_t *ch) { return ch->write_avail(ch); } +EXPORT_SYMBOL(smd_write_avail); int smd_wait_until_readable(smd_channel_t *ch, int bytes) { @@ -823,14 +1015,54 @@ int smd_cur_packet_size(smd_channel_t *ch) return ch->current_packet; } +int smd_tiocmget(smd_channel_t *ch) +{ + return (ch->recv->fDSR ? TIOCM_DSR : 0) | + (ch->recv->fCTS ? TIOCM_CTS : 0) | + (ch->recv->fCD ? TIOCM_CD : 0) | + (ch->recv->fRI ? TIOCM_RI : 0) | + (ch->send->fCTS ? TIOCM_RTS : 0) | + (ch->send->fDSR ? TIOCM_DTR : 0); +} + +int smd_tiocmset(smd_channel_t *ch, unsigned int set, unsigned int clear) +{ + unsigned long flags; + + spin_lock_irqsave(&smd_lock, flags); + if (set & TIOCM_DTR) + ch->send->fDSR = 1; + + if (set & TIOCM_RTS) + ch->send->fCTS = 1; -/* ------------------------------------------------------------------------- */ + if (clear & TIOCM_DTR) + ch->send->fDSR = 0; + + if (clear & TIOCM_RTS) + ch->send->fCTS = 0; + + ch->send->fSTATE = 1; + barrier(); + notify_other_smd(ch->type); + spin_unlock_irqrestore(&smd_lock, flags); + + return 0; +} + + +/* -------------------------------------------------------------------------- */ void *smem_alloc(unsigned id, unsigned size) { return smem_find(id, size); } +void *smem_get_entry(unsigned id, unsigned *size) +{ + return _smem_find(id, size); +} + static void *_smem_find(unsigned id, unsigned *size) { struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE; @@ -866,144 +1098,207 @@ void *smem_find(unsigned id, unsigned size_in) return ptr; } +static int smem_init(void) +{ + struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE; + uint32_t *smsm; + + smsm = smem_alloc(ID_SHARED_STATE, + SMSM_NUM_ENTRIES * sizeof(uint32_t)); + + if (smsm) { + smsm[SMSM_APPS_STATE] = 0; + if ((shared->version[VERSION_MODEM] >> 16) >= 0xB) + smsm[SMSM_APPS_DEM_I] = 0; + } + + smsm = smem_alloc(SMEM_SMSM_CPU_INTR_MASK, + SMSM_NUM_ENTRIES * SMSM_NUM_HOSTS * sizeof(uint32_t)); + + if (smsm) { + smsm[SMSM_APPS_STATE * SMSM_NUM_HOSTS + SMSM_MODEM] = + 0xffffffff; + smsm[SMSM_APPS_DEM_I * SMSM_NUM_HOSTS + SMSM_MODEM] = + 0xffffffff; + smsm[SMSM_APPS_STATE * SMSM_NUM_HOSTS + SMSM_Q6_I] = 0xffffffff; + smsm[SMSM_APPS_DEM_I * SMSM_NUM_HOSTS + SMSM_Q6_I] = 0xffffffff; + } + + return 0; +} + +void smsm_reset_modem(unsigned mode) +{ + if (mode == SMSM_SYSTEM_DOWNLOAD) { + mode = SMSM_RESET | SMSM_SYSTEM_DOWNLOAD; + } else if (mode == SMSM_MODEM_WAIT) { + mode = SMSM_RESET | SMSM_MODEM_WAIT; + } else { /* reset_mode is SMSM_RESET or default */ + mode = SMSM_RESET; + } + + smsm_change_state(SMSM_APPS_STATE, mode, mode); +} +EXPORT_SYMBOL(smsm_reset_modem); + +void smsm_reset_modem_cont(void) +{ + unsigned long flags; + uint32_t *smsm; + + spin_lock_irqsave(&smem_lock, flags); + smsm = smem_alloc(ID_SHARED_STATE, + SMSM_NUM_ENTRIES * sizeof(uint32_t)); + smsm[SMSM_APPS_STATE] &= ~SMSM_MODEM_WAIT; + spin_unlock_irqrestore(&smem_lock, flags); +} +EXPORT_SYMBOL(smsm_reset_modem_cont); + static irqreturn_t smsm_irq_handler(int irq, void *data) { unsigned long flags; - struct smsm_shared *smsm; + uint32_t *smsm; + static uint32_t prev_smem_q6_apps_smsm; + + if (irq == INT_ADSP_A11) { + smsm = smem_alloc(SMEM_SMD_SMSM_INTR_MUX, + SMSM_NUM_INTR_MUX * sizeof(uint32_t)); + if (!smsm || + (smsm[SMEM_Q6_APPS_SMSM] == prev_smem_q6_apps_smsm)) + return IRQ_HANDLED; + + prev_smem_q6_apps_smsm = smsm[SMEM_Q6_APPS_SMSM]; + } spin_lock_irqsave(&smem_lock, flags); smsm = smem_alloc(ID_SHARED_STATE, - 2 * sizeof(struct smsm_shared)); + SMSM_NUM_ENTRIES * sizeof(uint32_t)); if (smsm == 0) { - pr_info("\n"); + printk(KERN_INFO "\n"); } else { - unsigned apps = smsm[0].state; - unsigned modm = smsm[1].state; + unsigned old_apps, apps; + unsigned modm = smsm[SMSM_MODEM_STATE]; + + old_apps = apps = smsm[SMSM_APPS_STATE]; if (msm_smd_debug_mask & MSM_SMSM_DEBUG) - pr_info("\n", apps, modm); - if (modm & SMSM_RESET) { - handle_modem_crash(); + printk(KERN_INFO "\n", apps, modm); + if (apps & SMSM_RESET) { + /* If we get an interrupt and the apps SMSM_RESET + bit is already set, the modem is acking the + app's reset ack. */ + apps &= ~SMSM_RESET; + + /* Issue a fake irq to handle any + * smd state changes during reset + */ + smd_fake_irq_handler(0); + + /* queue modem restart notify chain */ + modem_queue_start_reset_notify(); + + } else if (modm & SMSM_RESET) { + apps |= SMSM_RESET; } else { apps |= SMSM_INIT; if (modm & SMSM_SMDINIT) apps |= SMSM_SMDINIT; if (modm & SMSM_RPCINIT) apps |= SMSM_RPCINIT; + if ((apps & (SMSM_INIT | SMSM_SMDINIT | SMSM_RPCINIT)) == + (SMSM_INIT | SMSM_SMDINIT | SMSM_RPCINIT)) + apps |= SMSM_RUN; } - if (smsm[0].state != apps) { + if (smsm[SMSM_APPS_STATE] != apps) { if (msm_smd_debug_mask & MSM_SMSM_DEBUG) - pr_info("\n", apps); - smsm[0].state = apps; + printk(KERN_INFO "\n", apps); + smsm[SMSM_APPS_STATE] = apps; do_smd_probe(); - notify_other_smsm(); + notify_other_smsm(SMSM_APPS_STATE, old_apps, apps); } } spin_unlock_irqrestore(&smem_lock, flags); return IRQ_HANDLED; } -int smsm_change_state(uint32_t clear_mask, uint32_t set_mask) +int smsm_change_state(uint32_t smsm_entry, + uint32_t clear_mask, uint32_t set_mask) { unsigned long flags; - struct smsm_shared *smsm; + uint32_t *smsm; + uint32_t old_state; + + if (smsm_entry >= SMSM_NUM_ENTRIES) { + printk(KERN_ERR "smsm_change_state: Invalid entry %d", + smsm_entry); + return -EINVAL; + } spin_lock_irqsave(&smem_lock, flags); smsm = smem_alloc(ID_SHARED_STATE, - 2 * sizeof(struct smsm_shared)); + SMSM_NUM_ENTRIES * sizeof(uint32_t)); if (smsm) { - if (smsm[1].state & SMSM_RESET) - handle_modem_crash(); - smsm[0].state = (smsm[0].state & ~clear_mask) | set_mask; + old_state = smsm[smsm_entry]; + smsm[smsm_entry] = (smsm[smsm_entry] & ~clear_mask) | set_mask; if (msm_smd_debug_mask & MSM_SMSM_DEBUG) - pr_info("smsm_change_state %x\n", - smsm[0].state); - notify_other_smsm(); + printk(KERN_INFO "smsm_change_state %x\n", + smsm[smsm_entry]); + notify_other_smsm(SMSM_APPS_STATE, old_state, smsm[smsm_entry]); } spin_unlock_irqrestore(&smem_lock, flags); if (smsm == NULL) { - pr_err("smsm_change_state \n"); + printk(KERN_ERR "smsm_change_state \n"); return -EIO; } return 0; } -uint32_t smsm_get_state(void) +uint32_t smsm_get_state(uint32_t smsm_entry) { unsigned long flags; - struct smsm_shared *smsm; + uint32_t *smsm; uint32_t rv; + if (smsm_entry >= SMSM_NUM_ENTRIES) { + printk(KERN_ERR "smsm_change_state: Invalid entry %d", + smsm_entry); + return -EINVAL; + } + spin_lock_irqsave(&smem_lock, flags); smsm = smem_alloc(ID_SHARED_STATE, - 2 * sizeof(struct smsm_shared)); + SMSM_NUM_ENTRIES * sizeof(uint32_t)); if (smsm) - rv = smsm[1].state; + rv = smsm[smsm_entry]; else rv = 0; - if (rv & SMSM_RESET) - handle_modem_crash(); - spin_unlock_irqrestore(&smem_lock, flags); if (smsm == NULL) - pr_err("smsm_get_state \n"); + printk(KERN_ERR "smsm_get_state \n"); return rv; -} - -int smsm_set_sleep_duration(uint32_t delay) -{ - uint32_t *ptr; - - ptr = smem_alloc(SMEM_SMSM_SLEEP_DELAY, sizeof(*ptr)); - if (ptr == NULL) { - pr_err("smsm_set_sleep_duration \n"); - return -EIO; - } - if (msm_smd_debug_mask & MSM_SMSM_DEBUG) - pr_info("smsm_set_sleep_duration %d -> %d\n", - *ptr, delay); - *ptr = delay; - return 0; -} -int smsm_set_interrupt_info(struct smsm_interrupt_info *info) -{ - struct smsm_interrupt_info *ptr; - - ptr = smem_alloc(SMEM_SMSM_INT_INFO, sizeof(*ptr)); - if (ptr == NULL) { - pr_err("smsm_set_sleep_duration \n"); - return -EIO; - } - if (msm_smd_debug_mask & MSM_SMSM_DEBUG) - pr_info("smsm_set_interrupt_info %x %x -> %x %x\n", - ptr->aArm_en_mask, ptr->aArm_interrupts_pending, - info->aArm_en_mask, info->aArm_interrupts_pending); - *ptr = *info; - return 0; } -#define MAX_NUM_SLEEP_CLIENTS 64 -#define MAX_SLEEP_NAME_LEN 8 - -#define NUM_GPIO_INT_REGISTERS 6 -#define GPIO_SMEM_NUM_GROUPS 2 -#define GPIO_SMEM_MAX_PC_INTERRUPTS 8 +#define MAX_NUM_SLEEP_CLIENTS 64 +#define MAX_SLEEP_NAME_LEN 8 +#define NUM_GPIO_INT_REGISTERS 6 +#define GPIO_SMEM_NUM_GROUPS 2 +#define GPIO_SMEM_MAX_PC_INTERRUPTS 8 struct tramp_gpio_save { - unsigned int enable; - unsigned int detect; - unsigned int polarity; + unsigned int enable; + unsigned int detect; + unsigned int polarity; }; struct tramp_gpio_smem { @@ -1014,49 +1309,55 @@ struct tramp_gpio_smem { uint32_t polarity[NUM_GPIO_INT_REGISTERS]; }; - -void smsm_print_sleep_info(void) +/* + * Print debug information on shared memory sleep variables + */ +void smsm_print_sleep_info(uint32_t sleep_delay, uint32_t sleep_limit, + uint32_t irq_mask, uint32_t wakeup_reason, uint32_t pending_irqs) { unsigned long flags; uint32_t *ptr; struct tramp_gpio_smem *gpio; - struct smsm_interrupt_info *int_info; - spin_lock_irqsave(&smem_lock, flags); - ptr = smem_alloc(SMEM_SMSM_SLEEP_DELAY, sizeof(*ptr)); - if (ptr) - pr_info("SMEM_SMSM_SLEEP_DELAY: %x\n", *ptr); - - ptr = smem_alloc(SMEM_SMSM_LIMIT_SLEEP, sizeof(*ptr)); - if (ptr) - pr_info("SMEM_SMSM_LIMIT_SLEEP: %x\n", *ptr); + printk(KERN_ERR "SMEM_SMSM_SLEEP_DELAY: %x\n", sleep_delay); + printk(KERN_ERR "SMEM_SMSM_LIMIT_SLEEP: %x\n", sleep_limit); ptr = smem_alloc(SMEM_SLEEP_POWER_COLLAPSE_DISABLED, sizeof(*ptr)); if (ptr) - pr_info("SMEM_SLEEP_POWER_COLLAPSE_DISABLED: %x\n", *ptr); + printk(KERN_ERR "SMEM_SLEEP_POWER_COLLAPSE_DISABLED: %x\n", *ptr); + else + printk(KERN_ERR "SMEM_SLEEP_POWER_COLLAPSE_DISABLED: missing\n"); - int_info = smem_alloc(SMEM_SMSM_INT_INFO, sizeof(*int_info)); - if (int_info) - pr_info("SMEM_SMSM_INT_INFO %x %x %x\n", - int_info->aArm_en_mask, - int_info->aArm_interrupts_pending, - int_info->aArm_wakeup_reason); + printk(KERN_ERR "SMEM_SMSM_INT_INFO %x %x %x\n", + irq_mask, pending_irqs, wakeup_reason); gpio = smem_alloc(SMEM_GPIO_INT, sizeof(*gpio)); if (gpio) { int i; - for (i = 0; i < NUM_GPIO_INT_REGISTERS; i++) - pr_info("SMEM_GPIO_INT: %d: e %x d %x p %x\n", - i, gpio->enabled[i], gpio->detection[i], - gpio->polarity[i]); - - for (i = 0; i < GPIO_SMEM_NUM_GROUPS; i++) - pr_info("SMEM_GPIO_INT: %d: f %d: %d %d...\n", - i, gpio->num_fired[i], gpio->fired[i][0], - gpio->fired[i][1]); - } + for (i = 0; i < NUM_GPIO_INT_REGISTERS; i++) { + printk(KERN_ERR "SMEM_GPIO_INT: %d: e %x d %x p %x\n", + i, gpio->enabled[i], gpio->detection[i], + gpio->polarity[i]); + } + for (i = 0; i < GPIO_SMEM_NUM_GROUPS; i++) { + printk(KERN_ERR "SMEM_GPIO_INT: %d: f %d: %d %d...\n", + i, gpio->num_fired[i], gpio->fired[i][0], + gpio->fired[i][1]); + } + } else + printk(KERN_ERR "SMEM_GPIO_INT: missing\n"); + +#if 0 + ptr = smem_alloc(SMEM_SLEEP_STATIC, + 2 * MAX_NUM_SLEEP_CLIENTS * (MAX_SLEEP_NAME_LEN + 1)); + if (ptr) + printk(KERN_ERR "SMEM_SLEEP_STATIC: %x %x %x %x\n", + ptr[0], ptr[1], ptr[2], ptr[3]); + else + printk(KERN_ERR "SMEM_SLEEP_STATIC: missing\n"); +#endif spin_unlock_irqrestore(&smem_lock, flags); } @@ -1064,7 +1365,7 @@ void smsm_print_sleep_info(void) int smd_core_init(void) { int r; - pr_info("smd_core_init()\n"); + printk(KERN_INFO "smd_core_init()\n"); r = request_irq(INT_A9_M2A_0, smd_irq_handler, IRQF_TRIGGER_RISING, "smd_dev", 0); @@ -1072,7 +1373,8 @@ int smd_core_init(void) return r; r = enable_irq_wake(INT_A9_M2A_0); if (r < 0) - pr_err("smd_core_init: enable_irq_wake failed for A9_M2A_0\n"); + printk(KERN_ERR "smd_core_init: " + "enable_irq_wake failed for INT_A9_M2A_0\n"); r = request_irq(INT_A9_M2A_5, smsm_irq_handler, IRQF_TRIGGER_RISING, "smsm_dev", 0); @@ -1080,9 +1382,30 @@ int smd_core_init(void) free_irq(INT_A9_M2A_0, 0); return r; } + r = enable_irq_wake(INT_A9_M2A_5); if (r < 0) - pr_err("smd_core_init: enable_irq_wake failed for A9_M2A_5\n"); + printk(KERN_ERR "smd_core_init: " + "enable_irq_wake failed for INT_A9_M2A_5\n"); + + r = request_irq(INT_ADSP_A11, smd_irq_handler, + IRQF_TRIGGER_RISING | IRQF_SHARED, "smd_dev", + smd_irq_handler); + if (r < 0) + printk(KERN_ERR "smd_core_init: " + "request_irq failed for INT_ADSP_A11\n"); + + r = request_irq(INT_ADSP_A11, smsm_irq_handler, + IRQF_TRIGGER_RISING | IRQF_SHARED, "smsm_dev", + smsm_irq_handler); + if (r < 0) + printk(KERN_ERR "smd_core_init: " + "request_irq failed for INT_ADSP_A11\n"); + + r = enable_irq_wake(INT_ADSP_A11); + if (r < 0) + printk(KERN_ERR "smd_core_init: " + "enable_irq_wake failed for INT_ADSP_A11\n"); /* we may have missed a signal while booting -- fake * an interrupt to make sure we process any existing @@ -1090,13 +1413,144 @@ int smd_core_init(void) */ smsm_irq_handler(0, 0); - pr_info("smd_core_init() done\n"); + printk(KERN_INFO "smd_core_init() done\n"); return 0; } #if defined(CONFIG_DEBUG_FS) +static int debug_f3(char *buf, int max) +{ + char *x; + int size; + int i = 0, j = 0; + unsigned cols = 0; + char str[4*sizeof(unsigned)+1] = {0}; + + i += scnprintf(buf + i, max - i, + "Printing to log\n"); + + x = smem_get_entry(SMEM_ERR_F3_TRACE_LOG, &size); + if (x != 0) { + printk(KERN_ERR "smem: F3 TRACE LOG\n"); + while (size > 0) { + if (size >= sizeof(unsigned)) { + printk(KERN_ERR "%08x", *((unsigned *) x)); + for (j = 0; j < sizeof(unsigned); ++j) + if (isprint(*(x+j))) + str[cols*sizeof(unsigned) + j] + = *(x+j); + else + str[cols*sizeof(unsigned) + j] + = '-'; + x += sizeof(unsigned); + size -= sizeof(unsigned); + } else { + while (size-- > 0) + printk(KERN_ERR "%02x", + (unsigned) *x++); + break; + } + if (cols == 3) { + cols = 0; + str[4*sizeof(unsigned)] = 0; + printk(KERN_ERR " %s\n", str); + str[0] = 0; + } else { + cols++; + printk(KERN_ERR " "); + } + } + printk(KERN_ERR "\n"); + } + + return max; +} + +static int debug_diag(char *buf, int max) +{ + int i = 0; + + i += scnprintf(buf + i, max - i, + "Printing to log\n"); + smd_diag(); + + return i; +} + +static int debug_modem_err_f3(char *buf, int max) +{ + char *x; + int size; + int i = 0, j = 0; + unsigned cols = 0; + char str[4*sizeof(unsigned)+1] = {0}; + + x = smem_get_entry(SMEM_ERR_F3_TRACE_LOG, &size); + if (x != 0) { + printk(KERN_ERR "smem: F3 TRACE LOG\n"); + while (size > 0 && max - i) { + if (size >= sizeof(unsigned)) { + i += scnprintf(buf + i, max - i, "%08x", + *((unsigned *) x)); + for (j = 0; j < sizeof(unsigned); ++j) + if (isprint(*(x+j))) + str[cols*sizeof(unsigned) + j] + = *(x+j); + else + str[cols*sizeof(unsigned) + j] + = '-'; + x += sizeof(unsigned); + size -= sizeof(unsigned); + } else { + while (size-- > 0 && max - i) + i += scnprintf(buf + i, max - i, + "%02x", + (unsigned) *x++); + break; + } + if (cols == 3) { + cols = 0; + str[4*sizeof(unsigned)] = 0; + i += scnprintf(buf + i, max - i, " %s\n", + str); + str[0] = 0; + } else { + cols++; + i += scnprintf(buf + i, max - i, " "); + } + } + i += scnprintf(buf + i, max - i, "\n"); + } + + return i; +} + +static int debug_modem_err(char *buf, int max) +{ + char *x; + int size; + int i = 0; + + x = smem_find(ID_DIAG_ERR_MSG, SZ_DIAG_ERR_MSG); + if (x != 0) { + x[SZ_DIAG_ERR_MSG - 1] = 0; + i += scnprintf(buf + i, max - i, + "smem: DIAG '%s'\n", x); + } + + x = smem_get_entry(SMEM_ERR_CRASH_LOG, &size); + if (x != 0) { + x[size - 1] = 0; + i += scnprintf(buf + i, max - i, + "smem: CRASH LOG\n'%s'\n", x); + } + i += scnprintf(buf + i, max - i, "\n"); + + return i; +} + static int dump_ch(char *buf, int max, int n, struct smd_half_channel *s, struct smd_half_channel *r) @@ -1125,26 +1579,13 @@ static int dump_ch(char *buf, int max, int n, ); } -static int debug_read_stat(char *buf, int max) +static int debug_read_diag_msg(char *buf, int max) { - struct smsm_shared *smsm; char *msg; int i = 0; - smsm = smem_find(ID_SHARED_STATE, - 2 * sizeof(struct smsm_shared)); - msg = smem_find(ID_DIAG_ERR_MSG, SZ_DIAG_ERR_MSG); - if (smsm) { - if (smsm[1].state & SMSM_RESET) - i += scnprintf(buf + i, max - i, - "smsm: ARM9 HAS CRASHED\n"); - i += scnprintf(buf + i, max - i, "smsm: a9: %08x a11: %08x\n", - smsm[0].state, smsm[1].state); - } else { - i += scnprintf(buf + i, max - i, "smsm: cannot find\n"); - } if (msg) { msg[SZ_DIAG_ERR_MSG - 1] = 0; i += scnprintf(buf + i, max - i, "diag: '%s'\n", msg); @@ -1165,53 +1606,87 @@ static int debug_read_mem(char *buf, int max) shared->heap_info.free_offset, shared->heap_info.heap_remaining); - for (n = 0; n < SMEM_NUM_ITEMS; n++) { + for (n = 0; n < SMD_HEAP_SIZE; n++) { if (toc[n].allocated == 0) continue; i += scnprintf(buf + i, max - i, - "%04d: offsed %08x size %08x\n", + "%04d: offset %08x size %08x\n", n, toc[n].offset, toc[n].size); } return i; } -static int debug_read_ch(char *buf, int max) +static int debug_read_ch_v1(char *buf, int max) +{ + void *shared; + int n, i = 0; + + for (n = 0; n < SMD_CHANNELS; n++) { + shared = smem_find(ID_SMD_CHANNELS + n, + 2 * (sizeof(struct smd_half_channel) + + SMD_BUF_SIZE)); + + if (shared == 0) + continue; + i += dump_ch(buf + i, max - i, n, shared, + (shared + sizeof(struct smd_half_channel) + + SMD_BUF_SIZE)); + } + + return i; +} + +static int debug_read_ch_v2(char *buf, int max) { - struct smd_shared *shared; + void *shared; int n, i = 0; for (n = 0; n < SMD_CHANNELS; n++) { shared = smem_find(ID_SMD_CHANNELS + n, - sizeof(struct smd_shared)); + 2 * sizeof(struct smd_half_channel)); + if (shared == 0) continue; - i += dump_ch(buf + i, max - i, n, &shared->ch0, &shared->ch1); + i += dump_ch(buf + i, max - i, n, shared, + (shared + sizeof(struct smd_half_channel))); } return i; } -static int debug_read_version(char *buf, int max) +static int debug_read_smem_version(char *buf, int max) { struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE; - unsigned version = shared->version[VERSION_MODEM]; - return sprintf(buf, "%d.%d\n", version >> 16, version & 0xffff); + uint32_t n, version, i = 0; + + for (n = 0; n < 32; n++) { + version = shared->version[n]; + i += scnprintf(buf + i, max - i, + "entry %d: smem = %d proc_comm = %d\n", n, + version >> 16, + version & 0xffff); + } + + return i; } -static int debug_read_build_id(char *buf, int max) +static int debug_read_smd_version(char *buf, int max) { - unsigned size; - void *data; + uint32_t *smd_ver; + uint32_t n, version, i = 0; - data = _smem_find(SMEM_HW_SW_BUILD_ID, &size); - if (!data) - return 0; + smd_ver = smem_alloc(SMEM_VERSION_SMD, 32 * sizeof(uint32_t)); - if (size >= max) - size = max; - memcpy(buf, data, size); + if (smd_ver) + for (n = 0; n < 32; n++) { + version = smd_ver[n]; + i += scnprintf(buf + i, max - i, + "entry %d: %d.%d\n", n, + version >> 16, + version & 0xffff); + } - return size; + return i; } static int debug_read_alloc_tbl(char *buf, int max) @@ -1219,25 +1694,74 @@ static int debug_read_alloc_tbl(char *buf, int max) struct smd_alloc_elm *shared; int n, i = 0; - shared = smem_find(ID_CH_ALLOC_TBL, sizeof(*shared) * 64); + shared = smem_find(ID_CH_ALLOC_TBL, sizeof(struct smd_alloc_elm[64])); for (n = 0; n < 64; n++) { - if (shared[n].ref_count == 0) - continue; i += scnprintf(buf + i, max - i, - "%03d: %20s cid=%02d ctype=%d ref_count=%d\n", - n, shared[n].name, shared[n].cid, - shared[n].ctype, shared[n].ref_count); + "name=%s cid=%d ch type=%d " + "xfer type=%d ref_count=%d\n", + shared[n].name, + shared[n].cid, + SMD_CHANNEL_TYPE(shared[n].type), + SMD_XFER_TYPE(shared[n].type), + shared[n].ref_count); } return i; } -static int debug_boom(char *buf, int max) +static int debug_read_smsm_state(char *buf, int max) { - unsigned ms = 5000; - msm_proc_comm(PCOM_RESET_MODEM, &ms, 0); - return 0; + uint32_t *smsm; + int n, i = 0; + + smsm = smem_find(ID_SHARED_STATE, + SMSM_NUM_ENTRIES * sizeof(uint32_t)); + + if (smsm) + for (n = 0; n < SMSM_NUM_ENTRIES; n++) + i += scnprintf(buf + i, max - i, "entry %d: 0x%08x\n", + n, smsm[n]); + + return i; + +} + +static int debug_read_intr_mask(char *buf, int max) +{ + uint32_t *smsm; + int m, n, i = 0; + + smsm = smem_alloc(SMEM_SMSM_CPU_INTR_MASK, + SMSM_NUM_ENTRIES * SMSM_NUM_HOSTS * sizeof(uint32_t)); + + if (smsm) + for (m = 0; m < SMSM_NUM_ENTRIES; m++) { + i += scnprintf(buf + i, max - i, "entry %d:", m); + for (n = 0; n < SMSM_NUM_HOSTS; n++) + i += scnprintf(buf + i, max - i, + " host %d: 0x%08x", + n, smsm[m * SMSM_NUM_HOSTS + n]); + i += scnprintf(buf + i, max - i, "\n"); + } + + return i; +} + +static int debug_read_intr_mux(char *buf, int max) +{ + uint32_t *smsm; + int n, i = 0; + + smsm = smem_alloc(SMEM_SMD_SMSM_INTR_MUX, + SMSM_NUM_INTR_MUX * sizeof(uint32_t)); + + if (smsm) + for (n = 0; n < SMSM_NUM_INTR_MUX; n++) + i += scnprintf(buf + i, max - i, "entry %d: %d\n", + n, smsm[n]); + + return i; } #define DEBUG_BUFMAX 4096 @@ -1272,31 +1796,60 @@ static void debug_create(const char *name, mode_t mode, static void smd_debugfs_init(void) { struct dentry *dent; + uint32_t *smd_ver; dent = debugfs_create_dir("smd", 0); if (IS_ERR(dent)) return; - debug_create("ch", 0444, dent, debug_read_ch); - debug_create("stat", 0444, dent, debug_read_stat); + smd_ver = smem_alloc(SMEM_VERSION_SMD, 32 * sizeof(uint32_t)); + + if (smd_ver && ((smd_ver[VERSION_MODEM] >> 16) >= 1)) + debug_create("ch", 0444, dent, debug_read_ch_v2); + else + debug_create("ch", 0444, dent, debug_read_ch_v1); + + debug_create("diag", 0444, dent, debug_read_diag_msg); debug_create("mem", 0444, dent, debug_read_mem); - debug_create("version", 0444, dent, debug_read_version); + debug_create("version", 0444, dent, debug_read_smd_version); debug_create("tbl", 0444, dent, debug_read_alloc_tbl); - debug_create("build", 0444, dent, debug_read_build_id); - debug_create("boom", 0444, dent, debug_boom); + debug_create("modem_err", 0444, dent, debug_modem_err); + debug_create("modem_err_f3", 0444, dent, debug_modem_err_f3); + debug_create("print_diag", 0444, dent, debug_diag); + debug_create("print_f3", 0444, dent, debug_f3); +} + +static void smsm_debugfs_init(void) +{ + struct dentry *dent; + + dent = debugfs_create_dir("smsm", 0); + if (IS_ERR(dent)) + return; + + debug_create("state", 0444, dent, debug_read_smsm_state); + debug_create("intr_mask", 0444, dent, debug_read_intr_mask); + debug_create("intr_mux", 0444, dent, debug_read_intr_mux); + debug_create("version", 0444, dent, debug_read_smem_version); } #else static void smd_debugfs_init(void) {} +static void smsm_debugfs_init(void) {} #endif static int __init msm_smd_probe(struct platform_device *pdev) { - pr_info("smd_init()\n"); + printk(KERN_INFO "smd_init()\n"); INIT_WORK(&probe_work, smd_channel_probe_worker); + if (smem_init()) { + printk(KERN_ERR "smem_init() failed\n"); + return -1; + } + if (smd_core_init()) { - pr_err("smd_core_init() failed\n"); + printk(KERN_ERR "smd_core_init() failed\n"); return -1; } @@ -1304,9 +1857,11 @@ static int __init msm_smd_probe(struct platform_device *pdev) msm_check_for_modem_crash = check_for_modem_crash; - smd_debugfs_init(); smd_initialized = 1; + smd_debugfs_init(); + smsm_debugfs_init(); + return 0; } diff --git a/arch/arm/mach-msm/smd_ctl2.c b/arch/arm/mach-msm/smd_ctl2.c new file mode 100644 index 000000000000..109a02f93d55 --- /dev/null +++ b/arch/arm/mach-msm/smd_ctl2.c @@ -0,0 +1,689 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +/* + * SMD Control Driver -- Provides a binary SMD non-muxed control port + * interface. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "modem_notifier.h" + +#define NUM_SMD_CTL_PORTS 3 +#define DEVICE_NAME "smdcntl" +#define MAX_BUF_SIZE 1024 + +struct smd_ctl_dev { + struct cdev cdev; + char name[9]; + struct device *devicep; + + struct smd_channel *ctl_ch; + struct mutex ctl_ch_lock; + struct mutex rx_lock; + struct mutex is_open_lock; + struct workqueue_struct *ctl_wq; + struct work_struct ctl_work; + wait_queue_head_t ctl_wait_queue; + wait_queue_head_t ctl_opened_wait_queue; + + int i; + + unsigned char tx_buf[MAX_BUF_SIZE]; + unsigned char rx_buf[MAX_BUF_SIZE]; + int bytes_read; + int is_open; + + struct notifier_block nb; + int has_reset; + struct mutex has_reset_lock; + +} *smd_ctl_devp[NUM_SMD_CTL_PORTS]; + +struct class *smd_ctl_classp; +static dev_t smd_ctl_number; + +#define DEBUG +#undef DEBUG + +#ifdef DEBUG +#define D_DUMP_BUFFER(prestr, cnt, buf) \ +do { \ + int i; \ + printk(KERN_ERR "%s", prestr); \ + for (i = 0; i < cnt; i++) \ + printk(KERN_ERR "%.2x", buf[i]); \ + printk(KERN_ERR "\n"); \ +} while (0) +#else +#define D_DUMP_BUFFER(prestr, cnt, buf) do {} while (0) +#endif + +#ifdef DEBUG +#define D(x...) printk(x) +#else +#define D(x...) do {} while (0) +#endif + +static void clean_and_signal(struct smd_ctl_dev *smd_ctl_devp) +{ + flush_workqueue(smd_ctl_devp->ctl_wq); + + mutex_lock(&smd_ctl_devp->has_reset_lock); + smd_ctl_devp->has_reset = 1; + mutex_unlock(&smd_ctl_devp->has_reset_lock); + + mutex_lock(&smd_ctl_devp->rx_lock); + smd_ctl_devp->bytes_read = 0; + mutex_unlock(&smd_ctl_devp->rx_lock); + + mutex_lock(&smd_ctl_devp->is_open_lock); + smd_ctl_devp->is_open = 0; + mutex_unlock(&smd_ctl_devp->is_open_lock); + + wake_up_interruptible(&smd_ctl_devp->ctl_wait_queue); + wake_up_interruptible(&smd_ctl_devp->ctl_opened_wait_queue); +} + +static int modem_notifier(struct notifier_block *this, + unsigned long code, + void *_cmd) +{ + struct smd_ctl_dev *smd_ctl_devp = + container_of(this, + struct smd_ctl_dev, + nb); + + if (!smd_ctl_devp) + return NOTIFY_DONE; + + switch (code) { + case MODEM_NOTIFIER_START_RESET: + printk(KERN_ERR "Notify: start reset ch:%i\n", + smd_ctl_devp->i); + clean_and_signal(smd_ctl_devp); + break; + case MODEM_NOTIFIER_END_RESET: + printk(KERN_ERR "Notify: end reset\n"); + break; + default: + printk(KERN_ERR "Notify: general\n"); + break; + } + return NOTIFY_DONE; +} + +int smd_ctl_ioctl(struct inode *inode, + struct file *file, + unsigned int cmd, + unsigned long arg) +{ + int ret; + struct smd_ctl_dev *smd_ctl_devp; + + smd_ctl_devp = file->private_data; + + switch (cmd) { + case TIOCMGET: + ret = smd_tiocmget(smd_ctl_devp->ctl_ch); + break; + case TIOCMSET: + ret = smd_tiocmset(smd_ctl_devp->ctl_ch, arg, ~arg); + break; + default: + ret = -1; + } + + return ret; +} + +ssize_t smd_ctl_read(struct file *file, + char __user *buf, + size_t count, + loff_t *ppos) +{ + unsigned char read_buf[MAX_BUF_SIZE]; + int r; + int bytes_read; + struct smd_ctl_dev *smd_ctl_devp; + + D(KERN_ERR "%s: read %i bytes\n", + __func__, count); + + if (count > MAX_BUF_SIZE) { + printk(KERN_ERR "ERROR:%s:%i:%s: " + "count = %i > MAX_BUF_SIZE = %i\n", + __FILE__, + __LINE__, + __func__, + count, + MAX_BUF_SIZE); + return -EINVAL; + } + + smd_ctl_devp = file->private_data; + + if (!smd_ctl_devp->ctl_ch) + return -EINVAL; + + r = wait_event_interruptible(smd_ctl_devp->ctl_wait_queue, + smd_ctl_devp->bytes_read | + smd_ctl_devp->has_reset); + + if (smd_ctl_devp->has_reset) + return -ENETRESET; + + if (r < 0) { + /* qualify error message */ + if (r != -ERESTARTSYS) { + /* we get this anytime a signal comes in */ + printk(KERN_ERR "ERROR:%s:%i:%s: " + "wait_event_interruptible ret %i\n", + __FILE__, + __LINE__, + __func__, + r + ); + } + return r; + } + + /* Here we have a whole packet waiting for us */ + + mutex_lock(&smd_ctl_devp->rx_lock); + bytes_read = smd_ctl_devp->bytes_read; + smd_ctl_devp->bytes_read = 0; + mutex_unlock(&smd_ctl_devp->rx_lock); + + D(KERN_ERR "%s: after wait_event_interruptible bytes_read = %i\n", + __func__, bytes_read); + + if (bytes_read > count) { + printk(KERN_ERR "packet size %i > buffer size %i, " + "dropping packet!", bytes_read, count); + smd_read(smd_ctl_devp->ctl_ch, 0, bytes_read); + return -EINVAL; + } + + /* smd_read and copy_to_user need to be merged to only do 1 copy */ + if (smd_read(smd_ctl_devp->ctl_ch, read_buf, bytes_read) + != bytes_read) { + if (smd_ctl_devp->has_reset) + return -ENETRESET; + + printk(KERN_ERR "user read: not enough data?!\n"); + return -EINVAL; + } + D_DUMP_BUFFER("read: ", bytes_read, read_buf); + r = copy_to_user(buf, read_buf, bytes_read); + + if (r > 0) { + printk(KERN_ERR "ERROR:%s:%i:%s: " + "copy_to_user could not copy %i bytes.\n", + __FILE__, + __LINE__, + __func__, + r); + return r; + } + + D(KERN_ERR "%s: just read %i bytes\n", + __func__, bytes_read); + + /* Not all packet events get explictly handled, this doesn't + matter if a constant stream of packets is streaming in, but + eventually a packet will be received and we'll have missed + the event. Queuing one more work item will catch this if + its happened, but do nothing if it hasn't. + */ + queue_work(smd_ctl_devp->ctl_wq, &smd_ctl_devp->ctl_work); + + D(KERN_ERR "%s: just queued more work\n", __func__); + + return bytes_read; +} + +ssize_t smd_ctl_write(struct file *file, + const char __user *buf, + size_t count, + loff_t *ppos) +{ + int r; + struct smd_ctl_dev *smd_ctl_devp; + + if (count > MAX_BUF_SIZE) + return -EINVAL; + + D(KERN_ERR "%s: writting %i bytes\n", + __func__, count); + + smd_ctl_devp = file->private_data; + + if (!smd_ctl_devp->ctl_ch) + return -EINVAL; + + r = wait_event_interruptible(smd_ctl_devp->ctl_opened_wait_queue, + smd_ctl_devp->is_open | + smd_ctl_devp->has_reset); + + if (smd_ctl_devp->has_reset) + return -ENETRESET; + + if (r < 0) { + /* qualify error message */ + if (r != -ERESTARTSYS) { + /* we get this anytime a signal comes in */ + printk(KERN_ERR "ERROR:%s:%i:%s: " + "wait_event_interruptible ret %i\n", + __FILE__, + __LINE__, + __func__, + r + ); + } + return r; + } + + D_DUMP_BUFFER("write: ", count, buf); + + r = copy_from_user(smd_ctl_devp->tx_buf, buf, count); + if (r > 0) { + printk(KERN_ERR "ERROR:%s:%i:%s: " + "copy_from_user could not copy %i bytes.\n", + __FILE__, + __LINE__, + __func__, + r); + return r; + } + + D(KERN_ERR "%s: after copy_from_user. count = %i\n", + __func__, count); + + r = smd_write(smd_ctl_devp->ctl_ch, smd_ctl_devp->tx_buf, count); + if (r != count) { + if (smd_ctl_devp->has_reset) + return -ENETRESET; + + printk(KERN_ERR "ERROR:%s:%i:%s: " + "smd_write(ch,buf,count = %i) ret %i.\n", + __FILE__, + __LINE__, + __func__, + count, + r); + return r; + } + + D(KERN_ERR "%s: just wrote %i bytes\n", + __func__, count); + + return count; +} + +static void ctl_work_func(struct work_struct *work) +{ + /* unsigned char buf[MAX_BUF_SIZE]; */ + int sz; + struct smd_ctl_dev *smd_ctl_devp = container_of(work, + struct smd_ctl_dev, + ctl_work); + + if (!smd_ctl_devp->ctl_ch) + return; + + for (;;) { + sz = smd_cur_packet_size(smd_ctl_devp->ctl_ch); + if (sz == 0) { + D(KERN_ERR "%s: packet size is 0\n", __func__); + break; + } + if (sz > smd_read_avail(smd_ctl_devp->ctl_ch)) { + D(KERN_ERR "%s: packet size is %i - " + "the whole packet isn't here\n", + __func__, sz); + break; + } + if (sz > MAX_BUF_SIZE) { + smd_read(smd_ctl_devp->ctl_ch, 0, sz); + D(KERN_ERR "%s: packet size is %i - " + "greater than max %i, dropping\n", + __func__, sz, MAX_BUF_SIZE); + continue; + } + + /* here we have a packet of size sz ready */ + + mutex_lock(&smd_ctl_devp->rx_lock); + smd_ctl_devp->bytes_read = sz; + mutex_unlock(&smd_ctl_devp->rx_lock); + wake_up_interruptible(&smd_ctl_devp->ctl_wait_queue); + D(KERN_ERR "%s: after wake_up\n", __func__); + break; + } +} + +static void ctl_notify(void *priv, unsigned event) +{ + struct smd_ctl_dev *smd_ctl_devp = priv; + + if (smd_ctl_devp->ctl_ch == 0) + return; + + switch (event) { + case SMD_EVENT_DATA: { + int sz; + D(KERN_ERR "%s: data\n", + __func__); + sz = smd_cur_packet_size(smd_ctl_devp->ctl_ch); + D(KERN_ERR "%s: data sz = %i\n", + __func__, sz); + D(KERN_ERR "%s: smd_read_avail = %i\n", + __func__, smd_read_avail(smd_ctl_devp->ctl_ch)); + if ((sz > 0) && (sz <= smd_read_avail(smd_ctl_devp->ctl_ch))) { + queue_work(smd_ctl_devp->ctl_wq, + &smd_ctl_devp->ctl_work); + D(KERN_ERR "%s: data just queued\n", + __func__); + } + D(KERN_ERR "%s: data after queueing\n", + __func__); + break; + } + case SMD_EVENT_OPEN: + D(KERN_ERR "%s: smd opened\n", + __func__); + smd_ctl_devp->is_open = 1; + wake_up_interruptible(&smd_ctl_devp->ctl_opened_wait_queue); + break; + case SMD_EVENT_CLOSE: + smd_ctl_devp->is_open = 0; + printk(KERN_ERR "%s: smd closed\n", + __func__); + break; + } +} + +static char *smd_ctl_name[] = { + "DATA5_CNTL", + "DATA6_CNTL", + "DATA7_CNTL", +}; + +int smd_ctl_open(struct inode *inode, struct file *file) +{ + int r = 0; + struct smd_ctl_dev *smd_ctl_devp; + + smd_ctl_devp = container_of(inode->i_cdev, struct smd_ctl_dev, cdev); + + if (!smd_ctl_devp) + return -EINVAL; + + file->private_data = smd_ctl_devp; + + mutex_lock(&smd_ctl_devp->ctl_ch_lock); + if (smd_ctl_devp->ctl_ch == 0) + r = smd_open(smd_ctl_name[smd_ctl_devp->i], + &smd_ctl_devp->ctl_ch, + smd_ctl_devp, + ctl_notify); + mutex_unlock(&smd_ctl_devp->ctl_ch_lock); + + return r; +} + +int smd_ctl_release(struct inode *inode, struct file *file) +{ + int r = 0; + struct smd_ctl_dev *smd_ctl_devp = file->private_data; + + if (!smd_ctl_devp) + return -EINVAL; + + clean_and_signal(smd_ctl_devp); + + mutex_lock(&smd_ctl_devp->ctl_ch_lock); + if (smd_ctl_devp->ctl_ch != 0) { + r = smd_close(smd_ctl_devp->ctl_ch); + smd_ctl_devp->ctl_ch = 0; + } + mutex_unlock(&smd_ctl_devp->ctl_ch_lock); + + mutex_lock(&smd_ctl_devp->has_reset_lock); + smd_ctl_devp->has_reset = 0; + mutex_unlock(&smd_ctl_devp->has_reset_lock); + + return r; +} + +static const struct file_operations smd_ctl_fops = { + .owner = THIS_MODULE, + .open = smd_ctl_open, + .release = smd_ctl_release, + .read = smd_ctl_read, + .write = smd_ctl_write, + .ioctl = smd_ctl_ioctl, +}; + +static int __init smd_ctl_init(void) +{ + int i; + int r; + unsigned char buf[32]; + + r = alloc_chrdev_region(&smd_ctl_number, + 0, + NUM_SMD_CTL_PORTS, + DEVICE_NAME); + if (IS_ERR_VALUE(r)) { + printk(KERN_ERR "ERROR:%s:%i:%s: " + "alloc_chrdev_region() ret %i.\n", + __FILE__, + __LINE__, + __func__, + r); + goto error0; + } + + smd_ctl_classp = class_create(THIS_MODULE, DEVICE_NAME); + if (IS_ERR(smd_ctl_classp)) { + printk(KERN_ERR "ERROR:%s:%i:%s: " + "class_create() ENOMEM\n", + __FILE__, + __LINE__, + __func__); + r = -ENOMEM; + goto error1; + } + + for (i = 0; i < NUM_SMD_CTL_PORTS; ++i) { + smd_ctl_devp[i] = kzalloc(sizeof(struct smd_ctl_dev), + GFP_KERNEL); + if (IS_ERR(smd_ctl_devp[i])) { + printk(KERN_ERR "ERROR:%s:%i:%s kmalloc() ENOMEM\n", + __FILE__, + __LINE__, + __func__); + r = -ENOMEM; + goto error2; + } + + smd_ctl_devp[i]->i = i; + + scnprintf(buf, 32, "ctl%i", i); + smd_ctl_devp[i]->ctl_wq = create_singlethread_workqueue(buf); + if (&smd_ctl_devp[i]->ctl_wq == 0) { + printk(KERN_ERR + "%s:%i:%s: " + "create_singlethread_workqueue() ret 0\n", + __FILE__, + __LINE__, + __func__); + r = -ENOMEM; + goto error2; + } + + init_waitqueue_head(&smd_ctl_devp[i]->ctl_wait_queue); + smd_ctl_devp[i]->is_open = 0; + init_waitqueue_head(&smd_ctl_devp[i]->ctl_opened_wait_queue); + INIT_WORK(&smd_ctl_devp[i]->ctl_work, + ctl_work_func); + + mutex_init(&smd_ctl_devp[i]->ctl_ch_lock); + mutex_init(&smd_ctl_devp[i]->rx_lock); + mutex_init(&smd_ctl_devp[i]->is_open_lock); + + cdev_init(&smd_ctl_devp[i]->cdev, &smd_ctl_fops); + smd_ctl_devp[i]->cdev.owner = THIS_MODULE; + + r = cdev_add(&smd_ctl_devp[i]->cdev, + (smd_ctl_number + i), + 1); + + if (IS_ERR_VALUE(r)) { + printk(KERN_ERR "%s:%i:%s: cdev_add() ret %i\n", + __FILE__, + __LINE__, + __func__, + r); + destroy_workqueue(smd_ctl_devp[i]->ctl_wq); + kfree(smd_ctl_devp[i]); + goto error2; + } + + smd_ctl_devp[i]->devicep = + device_create(smd_ctl_classp, + NULL, + (smd_ctl_number + i), + NULL, + DEVICE_NAME "%d", + i); + + if (IS_ERR(smd_ctl_devp[i]->devicep)) { + printk(KERN_ERR "%s:%i:%s: " + "device_create() ENOMEM\n", + __FILE__, + __LINE__, + __func__); + r = -ENOMEM; + cdev_del(&smd_ctl_devp[i]->cdev); + destroy_workqueue(smd_ctl_devp[i]->ctl_wq); + kfree(smd_ctl_devp[i]); + goto error2; + } + + smd_ctl_devp[i]->nb.notifier_call = modem_notifier; + modem_register_notifier(&smd_ctl_devp[i]->nb); + mutex_init(&smd_ctl_devp[i]->has_reset_lock); + + } + + printk(KERN_INFO "SMD Control Port Driver Initialized.\n"); + return 0; + + error2: + if (i > 0) { + while (--i >= 0) { + cdev_del(&smd_ctl_devp[i]->cdev); + destroy_workqueue(smd_ctl_devp[i]->ctl_wq); + kfree(smd_ctl_devp[i]); + device_destroy(smd_ctl_classp, + MKDEV(MAJOR(smd_ctl_number), i)); + } + } + + class_destroy(smd_ctl_classp); + error1: + unregister_chrdev_region(MAJOR(smd_ctl_number), NUM_SMD_CTL_PORTS); + error0: + return r; +} + +static void __exit smd_ctl_cleanup(void) +{ + int i; + + for (i = 0; i < NUM_SMD_CTL_PORTS; ++i) { + modem_unregister_notifier(&smd_ctl_devp[i]->nb); + cdev_del(&smd_ctl_devp[i]->cdev); + kfree(smd_ctl_devp[i]); + device_destroy(smd_ctl_classp, + MKDEV(MAJOR(smd_ctl_number), i)); + } + + class_destroy(smd_ctl_classp); + + unregister_chrdev_region(MAJOR(smd_ctl_number), NUM_SMD_CTL_PORTS); +} + +module_init(smd_ctl_init); +module_exit(smd_ctl_cleanup); + +MODULE_DESCRIPTION("MSM Shared Memory Control Port"); +MODULE_LICENSE("GPL v2"); diff --git a/arch/arm/mach-msm/smd_loopback.c b/arch/arm/mach-msm/smd_loopback.c new file mode 100644 index 000000000000..49312a89424e --- /dev/null +++ b/arch/arm/mach-msm/smd_loopback.c @@ -0,0 +1,306 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +/* + * SMD Loopback Driver -- Provides a loopback SMD port interface. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "smd_private.h" + +#define MAX_BUF_SIZE 512 + +static DEFINE_MUTEX(loopback_ch_lock); +static DEFINE_MUTEX(loopback_rx_buf_lock); +static DEFINE_MUTEX(loopback_tx_buf_lock); +static DEFINE_SPINLOCK(loopback_read_lock); + +static DECLARE_WAIT_QUEUE_HEAD(loopback_wait_queue); + +struct loopback_device_t { + struct miscdevice misc; + + struct smd_channel *ch; + + unsigned char tx_buf[MAX_BUF_SIZE]; + unsigned char rx_buf[MAX_BUF_SIZE]; + unsigned int read_avail; +}; + +struct loopback_device_t *loopback_devp; + +static void loopback_notify(void *priv, unsigned event) +{ + unsigned long flags; + + switch (event) { + case SMD_EVENT_DATA: { + int sz; + sz = smd_cur_packet_size(loopback_devp->ch); + if ((sz > 0) && (sz <= smd_read_avail(loopback_devp->ch))) { + /* queue_work(loopback_wq, &loopback_work); */ + spin_lock_irqsave(&loopback_read_lock, flags); + if (loopback_devp->read_avail == 0) { + loopback_devp->read_avail = sz; + wake_up_interruptible(&loopback_wait_queue); + } + spin_unlock_irqrestore(&loopback_read_lock, flags); + } + break; + } + case SMD_EVENT_OPEN: + printk(KERN_INFO "loopback: smd opened\n"); + break; + case SMD_EVENT_CLOSE: + printk(KERN_INFO "loopback: smd closed\n"); + break; + } +} + +static ssize_t loopback_read(struct file *fp, char __user *buf, + size_t count, loff_t *pos) +{ + int r = 0; + int bytes_read = 0; + unsigned long flags; + int sz; + + for (;;) { + mutex_lock(&loopback_rx_buf_lock); + + spin_lock_irqsave(&loopback_read_lock, flags); + loopback_devp->read_avail = 0; + spin_unlock_irqrestore(&loopback_read_lock, flags); + + sz = smd_cur_packet_size(loopback_devp->ch); + + if ((sz != 0) && (sz <= smd_read_avail(loopback_devp->ch))) { + if (sz > MAX_BUF_SIZE) { + smd_read(loopback_devp->ch, 0, sz); + mutex_unlock(&loopback_rx_buf_lock); + continue; + } + + if (sz != smd_read(loopback_devp->ch, + loopback_devp->rx_buf, sz)) { + mutex_unlock(&loopback_rx_buf_lock); + continue; + } + + bytes_read = sz; + break; + } + + mutex_unlock(&loopback_rx_buf_lock); + r = wait_event_interruptible(loopback_wait_queue, + loopback_devp->read_avail); + if (r < 0) { + /* qualify error message */ + if (r != -ERESTARTSYS) { + /* we get this anytime a signal comes in */ + printk(KERN_ERR "ERROR:%s:%i:%s: " + "wait_event_interruptible ret %i\n", + __FILE__, + __LINE__, + __func__, + r + ); + } + return r; + } + } + + r = copy_to_user(buf, loopback_devp->rx_buf, bytes_read); + mutex_unlock(&loopback_rx_buf_lock); + + if (r > 0) { + printk(KERN_ERR "ERROR:%s:%i:%s: " + "copy_to_user could not copy %i bytes.\n", + __FILE__, + __LINE__, + __func__, + r); + } + + return bytes_read; +} + +static ssize_t loopback_write(struct file *file, + const char __user *buf, + size_t count, + loff_t *ppos) +{ + int r, n; + + if (count > MAX_BUF_SIZE) + count = MAX_BUF_SIZE; + + r = copy_from_user(loopback_devp->tx_buf, buf, count); + if (r > 0) { + printk(KERN_ERR "ERROR:%s:%i:%s: " + "copy_from_user could not copy %i bytes.\n", + __FILE__, + __LINE__, + __func__, + r); + return 0; + } + + mutex_lock(&loopback_tx_buf_lock); + n = smd_write_avail(loopback_devp->ch); + while (n < count) { + mutex_unlock(&loopback_tx_buf_lock); + msleep(250); + mutex_lock(&loopback_tx_buf_lock); + n = smd_write_avail(loopback_devp->ch); + } + + r = smd_write(loopback_devp->ch, loopback_devp->tx_buf, count); + mutex_unlock(&loopback_tx_buf_lock); + + if (r != count) { + printk(KERN_ERR "ERROR:%s:%i:%s: " + "smd_write(ch,buf,count = %i) ret %i.\n", + __FILE__, + __LINE__, + __func__, + count, + r); + return r; + } + + return count; +} + +static int loopback_open(struct inode *ip, struct file *fp) +{ + int r = 0; + + mutex_lock(&loopback_ch_lock); + if (loopback_devp->ch == 0) { + smsm_change_state(SMSM_APPS_STATE, 0, SMSM_SMD_LOOPBACK); + msleep(100); + r = smd_open("LOOPBACK", &loopback_devp->ch, + 0, loopback_notify); + } + + mutex_unlock(&loopback_ch_lock); + return r; +} + +static int loopback_release(struct inode *ip, struct file *fp) +{ + int r = 0; + + mutex_lock(&loopback_ch_lock); + if (loopback_devp->ch != 0) { + r = smd_close(loopback_devp->ch); + loopback_devp->ch = 0; + } + mutex_unlock(&loopback_ch_lock); + + return r; +} + +static const struct file_operations loopback_fops = { + .owner = THIS_MODULE, + .read = loopback_read, + .write = loopback_write, + .open = loopback_open, + .release = loopback_release, +}; + +static struct loopback_device_t loopback_device = { + .misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = "loopback", + .fops = &loopback_fops, + } +}; + +static void __exit loopback_exit(void) +{ + misc_deregister(&loopback_device.misc); +} + +static int __init loopback_init(void) +{ + int ret; + + loopback_devp = &loopback_device; + + ret = misc_register(&loopback_device.misc); + return ret; +} + +module_init(loopback_init); +module_exit(loopback_exit); + +MODULE_DESCRIPTION("MSM Shared Memory loopback Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/arch/arm/mach-msm/smd_nmea.c b/arch/arm/mach-msm/smd_nmea.c new file mode 100644 index 000000000000..35e1cbdca1e6 --- /dev/null +++ b/arch/arm/mach-msm/smd_nmea.c @@ -0,0 +1,249 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +/* + * SMD NMEA Driver -- Provides GPS NMEA device to SMD port interface. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define MAX_BUF_SIZE 200 + +static DEFINE_MUTEX(nmea_ch_lock); +static DEFINE_MUTEX(nmea_rx_buf_lock); + +static DECLARE_WAIT_QUEUE_HEAD(nmea_wait_queue); + +struct nmea_device_t { + struct miscdevice misc; + + struct smd_channel *ch; + + unsigned char rx_buf[MAX_BUF_SIZE]; + unsigned int bytes_read; +}; + +struct nmea_device_t *nmea_devp; + +static void nmea_work_func(struct work_struct *ws) +{ + int sz; + + for (;;) { + sz = smd_cur_packet_size(nmea_devp->ch); + if (sz == 0) + break; + if (sz > smd_read_avail(nmea_devp->ch)) + break; + if (sz > MAX_BUF_SIZE) { + smd_read(nmea_devp->ch, 0, sz); + continue; + } + + mutex_lock(&nmea_rx_buf_lock); + if (smd_read(nmea_devp->ch, nmea_devp->rx_buf, sz) != sz) { + mutex_unlock(&nmea_rx_buf_lock); + printk(KERN_ERR "nmea: not enough data?!\n"); + continue; + } + nmea_devp->bytes_read = sz; + mutex_unlock(&nmea_rx_buf_lock); + wake_up_interruptible(&nmea_wait_queue); + } +} + +struct workqueue_struct *nmea_wq; +static DECLARE_WORK(nmea_work, nmea_work_func); + +static void nmea_notify(void *priv, unsigned event) +{ + switch (event) { + case SMD_EVENT_DATA: { + int sz; + sz = smd_cur_packet_size(nmea_devp->ch); + if ((sz > 0) && (sz <= smd_read_avail(nmea_devp->ch))) + queue_work(nmea_wq, &nmea_work); + break; + } + case SMD_EVENT_OPEN: + printk(KERN_INFO "nmea: smd opened\n"); + break; + case SMD_EVENT_CLOSE: + printk(KERN_INFO "nmea: smd closed\n"); + break; + } +} + +static ssize_t nmea_read(struct file *fp, char __user *buf, + size_t count, loff_t *pos) +{ + int r; + int bytes_read; + + r = wait_event_interruptible(nmea_wait_queue, + nmea_devp->bytes_read); + if (r < 0) { + /* qualify error message */ + if (r != -ERESTARTSYS) { + /* we get this anytime a signal comes in */ + printk(KERN_ERR "ERROR:%s:%i:%s: " + "wait_event_interruptible ret %i\n", + __FILE__, + __LINE__, + __func__, + r + ); + } + return r; + } + + mutex_lock(&nmea_rx_buf_lock); + bytes_read = nmea_devp->bytes_read; + nmea_devp->bytes_read = 0; + r = copy_to_user(buf, nmea_devp->rx_buf, bytes_read); + mutex_unlock(&nmea_rx_buf_lock); + + if (r > 0) { + printk(KERN_ERR "ERROR:%s:%i:%s: " + "copy_to_user could not copy %i bytes.\n", + __FILE__, + __LINE__, + __func__, + r); + return r; + } + + return bytes_read; +} + +static int nmea_open(struct inode *ip, struct file *fp) +{ + int r = 0; + + mutex_lock(&nmea_ch_lock); + if (nmea_devp->ch == 0) + r = smd_open("GPSNMEA", &nmea_devp->ch, nmea_devp, nmea_notify); + mutex_unlock(&nmea_ch_lock); + + return r; +} + +static int nmea_release(struct inode *ip, struct file *fp) +{ + int r = 0; + + mutex_lock(&nmea_ch_lock); + if (nmea_devp->ch != 0) { + r = smd_close(nmea_devp->ch); + nmea_devp->ch = 0; + } + mutex_unlock(&nmea_ch_lock); + + return r; +} + +static const struct file_operations nmea_fops = { + .owner = THIS_MODULE, + .read = nmea_read, + .open = nmea_open, + .release = nmea_release, +}; + +static struct nmea_device_t nmea_device = { + .misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = "nmea", + .fops = &nmea_fops, + } +}; + +static void __exit nmea_exit(void) +{ + destroy_workqueue(nmea_wq); + misc_deregister(&nmea_device.misc); +} + +static int __init nmea_init(void) +{ + int ret; + + nmea_device.bytes_read = 0; + nmea_devp = &nmea_device; + + nmea_wq = create_singlethread_workqueue("nmea"); + if (nmea_wq == 0) + return -ENOMEM; + + ret = misc_register(&nmea_device.misc); + return ret; +} + +module_init(nmea_init); +module_exit(nmea_exit); + +MODULE_DESCRIPTION("MSM Shared Memory NMEA Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/arch/arm/mach-msm/smd_private.h b/arch/arm/mach-msm/smd_private.h index c0eb3de1be54..88c96cf67335 100644 --- a/arch/arm/mach-msm/smd_private.h +++ b/arch/arm/mach-msm/smd_private.h @@ -1,7 +1,7 @@ /* arch/arm/mach-msm/smd_private.h * * Copyright (C) 2007 Google, Inc. - * Copyright (c) 2007 QUALCOMM Incorporated + * Copyright (c) 2007-2009, Code Aurora Forum. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -49,25 +49,61 @@ struct smem_proc_comm #define VERSION_APPS 8 #define VERSION_MODEM 9 +#define SMD_HEAP_SIZE 512 + struct smem_shared { struct smem_proc_comm proc_comm[4]; unsigned version[32]; struct smem_heap_info heap_info; - struct smem_heap_entry heap_toc[128]; + struct smem_heap_entry heap_toc[SMD_HEAP_SIZE]; }; -struct smsm_shared -{ - unsigned host; - unsigned state; -}; - -struct smsm_interrupt_info -{ +#if defined(CONFIG_MSM_SMD_PKG4) +struct smsm_interrupt_info { uint32_t aArm_en_mask; uint32_t aArm_interrupts_pending; uint32_t aArm_wakeup_reason; + uint32_t aArm_rpc_prog; + uint32_t aArm_rpc_proc; + char aArm_smd_port_name[20]; + uint32_t aArm_gpio_info; +}; +#elif defined(CONFIG_MSM_SMD_PKG3) +struct smsm_interrupt_info { + uint32_t aArm_en_mask; + uint32_t aArm_interrupts_pending; + uint32_t aArm_wakeup_reason; +}; +#else +#error No SMD Package Specified; aborting +#endif + +#if defined(CONFIG_MSM_N_WAY_SMSM) +enum { + SMSM_APPS_STATE, + SMSM_MODEM_STATE, + SMSM_Q6_STATE, + SMSM_APPS_DEM, + SMSM_MODEM_DEM, + SMSM_Q6_DEM, + SMSM_POWER_MASTER_DEM, + SMSM_TIME_MASTER_DEM, + SMSM_NUM_ENTRIES, +}; +#else +enum { + SMSM_APPS_STATE = 1, + SMSM_MODEM_STATE = 3, + SMSM_NUM_ENTRIES, +}; +#endif + +enum { + SMSM_APPS, + SMSM_MODEM, + SMSM_Q6, + SMSM_NUM_HOSTS, }; #define SZ_DIAG_ERR_MSG 0xC8 @@ -76,21 +112,35 @@ struct smsm_interrupt_info #define ID_SHARED_STATE SMEM_SMSM_SHARED_STATE #define ID_CH_ALLOC_TBL SMEM_CHANNEL_ALLOC_TBL -#define SMSM_INIT 0x000001 -#define SMSM_SMDINIT 0x000008 -#define SMSM_RPCINIT 0x000020 -#define SMSM_RESET 0x000040 -#define SMSM_RSA 0x0080 -#define SMSM_RUN 0x000100 -#define SMSM_PWRC 0x0200 -#define SMSM_TIMEWAIT 0x0400 -#define SMSM_TIMEINIT 0x0800 -#define SMSM_PWRC_EARLY_EXIT 0x1000 -#define SMSM_WFPI 0x2000 -#define SMSM_SLEEP 0x4000 -#define SMSM_SLEEPEXIT 0x8000 -#define SMSM_OEMSBL_RELEASE 0x10000 -#define SMSM_PWRC_SUSPEND 0x200000 +#define SMSM_INIT 0x00000001 +#define SMSM_OSENTERED 0x00000002 +#define SMSM_SMDWAIT 0x00000004 +#define SMSM_SMDINIT 0x00000008 +#define SMSM_RPCWAIT 0x00000010 +#define SMSM_RPCINIT 0x00000020 +#define SMSM_RESET 0x00000040 +#define SMSM_RSA 0x00000080 +#define SMSM_RUN 0x00000100 +#define SMSM_PWRC 0x00000200 +#define SMSM_TIMEWAIT 0x00000400 +#define SMSM_TIMEINIT 0x00000800 +#define SMSM_PWRC_EARLY_EXIT 0x00001000 +#define SMSM_WFPI 0x00002000 +#define SMSM_SLEEP 0x00004000 +#define SMSM_SLEEPEXIT 0x00008000 +#define SMSM_OEMSBL_RELEASE 0x00010000 +#define SMSM_APPS_REBOOT 0x00020000 +#define SMSM_SYSTEM_POWER_DOWN 0x00040000 +#define SMSM_SYSTEM_REBOOT 0x00080000 +#define SMSM_SYSTEM_DOWNLOAD 0x00100000 +#define SMSM_PWRC_SUSPEND 0x00200000 +#define SMSM_APPS_SHUTDOWN 0x00400000 +#define SMSM_SMD_LOOPBACK 0x00800000 +#define SMSM_RUN_QUIET 0x01000000 +#define SMSM_MODEM_WAIT 0x02000000 +#define SMSM_MODEM_BREAK 0x04000000 +#define SMSM_MODEM_CONTINUE 0x08000000 +#define SMSM_UNKNOWN 0x80000000 #define SMSM_WKUP_REASON_RPC 0x00000001 #define SMSM_WKUP_REASON_INT 0x00000002 @@ -100,16 +150,20 @@ struct smsm_interrupt_info #define SMSM_WKUP_REASON_RESET 0x00000020 void *smem_alloc(unsigned id, unsigned size); -int smsm_change_state(uint32_t clear_mask, uint32_t set_mask); -uint32_t smsm_get_state(void); -int smsm_set_sleep_duration(uint32_t delay); -int smsm_set_interrupt_info(struct smsm_interrupt_info *info); -void smsm_print_sleep_info(void); - -#define SMEM_NUM_SMD_CHANNELS 64 - -typedef enum -{ +void *smem_get_entry(unsigned id, unsigned *size); +int smsm_change_state(uint32_t smsm_entry, + uint32_t clear_mask, uint32_t set_mask); +uint32_t smsm_get_state(uint32_t smsm_entry); +void smsm_print_sleep_info(uint32_t sleep_delay, uint32_t sleep_limit, + uint32_t irq_mask, uint32_t wakeup_reason, uint32_t pending_irqs); +void smsm_reset_modem(unsigned mode); +void smsm_reset_modem_cont(void); +void smd_sleep_exit(void); + +#define SMEM_NUM_SMD_STREAM_CHANNELS 64 +#define SMEM_NUM_SMD_BLOCK_CHANNELS 64 + +enum { /* fixed items */ SMEM_PROC_COMM = 0, SMEM_HEAP_INFO, @@ -128,7 +182,7 @@ typedef enum SMEM_WM_UUID, SMEM_CHANNEL_ALLOC_TBL, SMEM_SMD_BASE_ID, - SMEM_SMEM_LOG_IDX = SMEM_SMD_BASE_ID + SMEM_NUM_SMD_CHANNELS, + SMEM_SMEM_LOG_IDX = SMEM_SMD_BASE_ID + SMEM_NUM_SMD_STREAM_CHANNELS, SMEM_SMEM_LOG_EVENTS, SMEM_SMEM_STATIC_LOG_IDX, SMEM_SMEM_STATIC_LOG_EVENTS, @@ -158,6 +212,7 @@ typedef enum SMEM_BATT_INFO, SMEM_APPS_BOOT_MODE, SMEM_VERSION_FIRST, + SMEM_VERSION_SMD = SMEM_VERSION_FIRST, SMEM_VERSION_LAST = SMEM_VERSION_FIRST + 24, SMEM_OSS_RRCASN1_BUF1, SMEM_OSS_RRCASN1_BUF2, @@ -165,7 +220,31 @@ typedef enum SMEM_ID_VENDOR1, SMEM_ID_VENDOR2, SMEM_HW_SW_BUILD_ID, + SMEM_SMD_BLOCK_PORT_BASE_ID, + SMEM_SMD_BLOCK_PORT_PROC0_HEAP = SMEM_SMD_BLOCK_PORT_BASE_ID + + SMEM_NUM_SMD_BLOCK_CHANNELS, + SMEM_SMD_BLOCK_PORT_PROC1_HEAP = SMEM_SMD_BLOCK_PORT_PROC0_HEAP + + SMEM_NUM_SMD_BLOCK_CHANNELS, + SMEM_I2C_MUTEX = SMEM_SMD_BLOCK_PORT_PROC1_HEAP + + SMEM_NUM_SMD_BLOCK_CHANNELS, + SMEM_SCLK_CONVERSION, + SMEM_SMD_SMSM_INTR_MUX, + SMEM_SMSM_CPU_INTR_MASK, + SMEM_APPS_DEM_SLAVE_DATA, + SMEM_QDSP6_DEM_SLAVE_DATA, + SMEM_CLKREGIM_BSP, + SMEM_CLKREGIM_SOURCES, + SMEM_SMD_FIFO_BASE_ID, + SMEM_USABLE_RAM_PARTITION_TABLE = SMEM_SMD_FIFO_BASE_ID + + SMEM_NUM_SMD_STREAM_CHANNELS, + SMEM_POWER_ON_STATUS_INFO, + SMEM_DAL_AREA, + SMEM_SMEM_LOG_POWER_IDX, + SMEM_SMEM_LOG_POWER_WRAP, + SMEM_SMEM_LOG_POWER_EVENTS, + SMEM_ERR_CRASH_LOG, + SMEM_ERR_F3_TRACE_LOG, SMEM_NUM_ITEMS, -} smem_mem_type; +}; #endif diff --git a/arch/arm/mach-msm/smd_rpcrouter.c b/arch/arm/mach-msm/smd_rpcrouter.c index f30325c008b5..a0766e353d28 100644 --- a/arch/arm/mach-msm/smd_rpcrouter.c +++ b/arch/arm/mach-msm/smd_rpcrouter.c @@ -1,7 +1,7 @@ /* arch/arm/mach-msm/smd_rpcrouter.c * * Copyright (C) 2007 Google, Inc. - * Copyright (c) 2007 QUALCOMM Incorporated + * Copyright (c) 2007-2009, Code Aurora Forum. All rights reserved. * Author: San Mehat * * This software is licensed under the terms of the GNU General Public @@ -15,7 +15,6 @@ * */ -/* TODO: fragmentation for large writes */ /* TODO: handle cases where smd_write() will tempfail due to full fifo */ /* TODO: thread priority? schedule a work to bump it? */ /* TODO: maybe make server_list_lock a mutex */ @@ -37,38 +36,94 @@ #include #include #include +#include +#include + +#include #include +#include #include "smd_rpcrouter.h" - -#define TRACE_R2R_MSG 0 -#define TRACE_R2R_RAW 0 -#define TRACE_RPC_MSG 0 - -#define MSM_RPCROUTER_DEBUG 0 -#define MSM_RPCROUTER_DEBUG_PKT 0 -#define MSM_RPCROUTER_R2R_DEBUG 0 -#define DUMP_ALL_RECEIVED_HEADERS 0 - -#define DIAG(x...) printk("[RR] ERROR " x) - -#if MSM_RPCROUTER_DEBUG -#define D(x...) printk(x) -#else -#define D(x...) do {} while (0) -#endif - -#if TRACE_R2R_MSG -#define RR(x...) printk("[RR] "x) +#include "modem_notifier.h" + +enum { + SMEM_LOG = 1U << 0, + RTR_DBG = 1U << 1, + R2R_MSG = 1U << 2, + R2R_RAW = 1U << 3, + RPC_MSG = 1U << 4, + NTFY_MSG = 1U << 5, + RAW_PMR = 1U << 6, + RAW_PMW = 1U << 7, + R2R_RAW_HDR = 1U << 8, +}; +static int smd_rpcrouter_debug_mask; +module_param_named(debug_mask, smd_rpcrouter_debug_mask, + int, S_IRUGO | S_IWUSR | S_IWGRP); + +#define DIAG(x...) printk(KERN_ERR "[RR] ERROR " x) + +#if defined(CONFIG_MSM_ONCRPCROUTER_DEBUG) +#define D(x...) do { \ +if (smd_rpcrouter_debug_mask & RTR_DBG) \ + printk(KERN_ERR x); \ +} while (0) + +#define RR(x...) do { \ +if (smd_rpcrouter_debug_mask & R2R_MSG) \ + printk(KERN_ERR "[RR] "x); \ +} while (0) + +#define RAW(x...) do { \ +if (smd_rpcrouter_debug_mask & R2R_RAW) \ + printk(KERN_ERR "[RAW] "x); \ +} while (0) + +#define RAW_HDR(x...) do { \ +if (smd_rpcrouter_debug_mask & R2R_RAW_HDR) \ + printk(KERN_ERR "[HDR] "x); \ +} while (0) + +#define RAW_PMR(x...) do { \ +if (smd_rpcrouter_debug_mask & RAW_PMR) \ + printk(KERN_ERR "[PMR] "x); \ +} while (0) + +#define RAW_PMR_NOMASK(x...) do { \ + printk(KERN_ERR "[PMR] "x); \ +} while (0) + +#define RAW_PMW(x...) do { \ +if (smd_rpcrouter_debug_mask & RAW_PMW) \ + printk(KERN_ERR "[PMW] "x); \ +} while (0) + +#define RAW_PMW_NOMASK(x...) do { \ + printk(KERN_ERR "[PMW] "x); \ +} while (0) + +#define IO(x...) do { \ +if (smd_rpcrouter_debug_mask & RPC_MSG) \ + printk(KERN_ERR "[RPC] "x); \ +} while (0) + +#define NTFY(x...) do { \ +if (smd_rpcrouter_debug_mask & NTFY_MSG) \ + printk(KERN_ERR "[NOTIFY] "x); \ +} while (0) #else -#define RR(x...) do {} while (0) +#define D(x...) do { } while (0) +#define RR(x...) do { } while (0) +#define RAW(x...) do { } while (0) +#define RAW_HDR(x...) do { } while (0) +#define RAW_PMR(x...) do { } while (0) +#define RAW_PMR_NO_MASK(x...) do { } while (0) +#define RAW_PMW(x...) do { } while (0) +#define RAW_PMW_NO_MASK(x...) do { } while (0) +#define IO(x...) do { } while (0) +#define NTFY(x...) do { } while (0) #endif -#if TRACE_RPC_MSG -#define IO(x...) printk("[RPC] "x) -#else -#define IO(x...) do {} while (0) -#endif static LIST_HEAD(local_endpoints); static LIST_HEAD(remote_endpoints); @@ -88,7 +143,6 @@ static DEFINE_SPINLOCK(smd_lock); static struct workqueue_struct *rpcrouter_workqueue; static atomic_t next_xid = ATOMIC_INIT(1); -static uint8_t next_pacmarkid; static void do_read_data(struct work_struct *work); static void do_create_pdevs(struct work_struct *work); @@ -103,6 +157,20 @@ static DECLARE_WORK(work_create_rpcrouter_pdev, do_create_rpcrouter_pdev); #define RR_STATE_BODY 2 #define RR_STATE_ERROR 3 +/* After restart notification, local ep keep + * state for server restart and for ep notify. + * Server restart cleared by R-R new svr msg. + * NTFY cleared by calling msm_rpc_clear_netreset +*/ + +#define RESTART_NORMAL 0 +#define RESTART_PEND_SVR 1 +#define RESTART_PEND_NTFY 2 +#define RESTART_PEND_NTFY_SVR 3 + +/* State for remote ep following restart */ +#define RESTART_QUOTA_ABORT 1 + struct rr_context { struct rr_packet *pkt; uint8_t *ptr; @@ -154,6 +222,90 @@ static int rpcrouter_send_control_msg(union rr_control_msg *msg) return 0; } +static void modem_reset_start_cleanup(void) +{ + struct msm_rpc_endpoint *ept; + struct rr_remote_endpoint *r_ept; + struct rr_packet *pkt, *tmp_pkt; + struct rr_fragment *frag, *next; + struct msm_rpc_reply *reply, *reply_tmp; + unsigned long flags; + + spin_lock_irqsave(&local_endpoints_lock, flags); + /* remove all partial packets received */ + list_for_each_entry(ept, &local_endpoints, list) { + RR("modem_reset_start_clenup PID %x, remotepid:%d \n", + ept->dst_pid, RPCROUTER_PID_REMOTE); + /* remove replies */ + spin_lock(&ept->reply_q_lock); + list_for_each_entry_safe(reply, reply_tmp, + &ept->reply_pend_q, list) { + list_del(&reply->list); + kfree(reply); + } + list_for_each_entry_safe(reply, reply_tmp, + &ept->reply_avail_q, list) { + list_del(&reply->list); + kfree(reply); + } + spin_unlock(&ept->reply_q_lock); + if (ept->dst_pid == RPCROUTER_PID_REMOTE) { + spin_lock(&ept->incomplete_lock); + list_for_each_entry_safe(pkt, tmp_pkt, + &ept->incomplete, list) { + list_del(&pkt->list); + frag = pkt->first; + while (frag != NULL) { + next = frag->next; + kfree(frag); + frag = next; + } + kfree(pkt); + } + spin_unlock(&ept->incomplete_lock); + /* remove all completed packets waiting to be read*/ + spin_lock(&ept->read_q_lock); + list_for_each_entry_safe(pkt, tmp_pkt, &ept->read_q, + list) { + list_del(&pkt->list); + frag = pkt->first; + while (frag != NULL) { + next = frag->next; + kfree(frag); + frag = next; + } + kfree(pkt); + } + spin_unlock(&ept->read_q_lock); + /* Set restart state for local ep */ + RR("EPT:0x%p, State %d RESTART_PEND_NTFY_SVR " + "PROG:0x%08x VERS:0x%08x \n", + ept, ept->restart_state, be32_to_cpu(ept->dst_prog), + be32_to_cpu(ept->dst_vers)); + spin_lock(&ept->restart_lock); + ept->restart_state = RESTART_PEND_NTFY_SVR; + spin_unlock(&ept->restart_lock); + wake_up(&ept->wait_q); + } + } + + spin_unlock_irqrestore(&local_endpoints_lock, flags); + + /* Unblock endpoints waiting for quota ack*/ + spin_lock_irqsave(&remote_endpoints_lock, flags); + list_for_each_entry(r_ept, &remote_endpoints, list) { + spin_lock(&r_ept->quota_lock); + r_ept->quota_restart_state = RESTART_QUOTA_ABORT; + RR("Set STATE_PENDING PID:0x%08x CID:0x%08x \n", r_ept->pid, + r_ept->cid); + spin_unlock(&r_ept->quota_lock); + wake_up(&r_ept->quota_wait); + } + spin_unlock_irqrestore(&remote_endpoints_lock, flags); + +} + + static struct rr_server *rpcrouter_create_server(uint32_t pid, uint32_t cid, uint32_t prog, @@ -202,8 +354,7 @@ static void rpcrouter_destroy_server(struct rr_server *server) kfree(server); } -static struct rr_server *rpcrouter_lookup_server(uint32_t prog, - uint32_t ver) +static struct rr_server *rpcrouter_lookup_server(uint32_t prog, uint32_t ver) { struct rr_server *server; unsigned long flags; @@ -236,7 +387,6 @@ static struct rr_server *rpcrouter_lookup_server_by_dev(dev_t dev) return NULL; } - struct msm_rpc_endpoint *msm_rpcrouter_create_local_endpoint(dev_t dev) { struct msm_rpc_endpoint *ept; @@ -246,10 +396,6 @@ struct msm_rpc_endpoint *msm_rpcrouter_create_local_endpoint(dev_t dev) if (!ept) return NULL; memset(ept, 0, sizeof(struct msm_rpc_endpoint)); - - /* mark no reply outstanding */ - ept->reply_pid = 0xffffffff; - ept->cid = (uint32_t) ept; ept->pid = RPCROUTER_PID_LOCAL; ept->dev = dev; @@ -277,7 +423,14 @@ struct msm_rpc_endpoint *msm_rpcrouter_create_local_endpoint(dev_t dev) init_waitqueue_head(&ept->wait_q); INIT_LIST_HEAD(&ept->read_q); spin_lock_init(&ept->read_q_lock); + INIT_LIST_HEAD(&ept->reply_avail_q); + INIT_LIST_HEAD(&ept->reply_pend_q); + spin_lock_init(&ept->reply_q_lock); + spin_lock_init(&ept->restart_lock); + init_waitqueue_head(&ept->restart_wait); + ept->restart_state = RESTART_NORMAL; INIT_LIST_HEAD(&ept->incomplete); + spin_lock_init(&ept->incomplete_lock); spin_lock_irqsave(&local_endpoints_lock, flags); list_add_tail(&ept->list, &local_endpoints); @@ -289,6 +442,8 @@ int msm_rpcrouter_destroy_local_endpoint(struct msm_rpc_endpoint *ept) { int rc; union rr_control_msg msg; + struct msm_rpc_reply *reply, *reply_tmp; + unsigned long flags; msg.cmd = RPCROUTER_CTRL_CMD_REMOVE_CLIENT; msg.cli.pid = ept->pid; @@ -299,6 +454,18 @@ int msm_rpcrouter_destroy_local_endpoint(struct msm_rpc_endpoint *ept) if (rc < 0) return rc; + /* Free replies */ + spin_lock_irqsave(&ept->reply_q_lock, flags); + list_for_each_entry_safe(reply, reply_tmp, &ept->reply_pend_q, list) { + list_del(&reply->list); + kfree(reply); + } + list_for_each_entry_safe(reply, reply_tmp, &ept->reply_avail_q, list) { + list_del(&reply->list); + kfree(reply); + } + spin_unlock_irqrestore(&ept->reply_q_lock, flags); + list_del(&ept->list); kfree(ept); return 0; @@ -321,6 +488,7 @@ static int rpcrouter_create_remote_endpoint(uint32_t cid) spin_lock_irqsave(&remote_endpoints_lock, flags); list_add_tail(&new_c->list, &remote_endpoints); + new_c->quota_restart_state = RESTART_NORMAL; spin_unlock_irqrestore(&remote_endpoints_lock, flags); return 0; } @@ -357,6 +525,41 @@ static struct rr_remote_endpoint *rpcrouter_lookup_remote_endpoint(uint32_t cid) return NULL; } +static void handle_server_restart(struct rr_server *server, uint32_t cid, + uint32_t prog, uint32_t vers) +{ + struct rr_remote_endpoint *r_ept; + struct msm_rpc_endpoint *ept; + unsigned long flags; + r_ept = rpcrouter_lookup_remote_endpoint(cid); + if (r_ept && (r_ept->quota_restart_state != + RESTART_NORMAL)) { + spin_lock_irqsave(&r_ept->quota_lock, flags); + r_ept->tx_quota_cntr = 0; + r_ept->quota_restart_state = + RESTART_NORMAL; + spin_unlock_irqrestore(&r_ept->quota_lock, flags); + printk(KERN_INFO "rpcrouter: Remote EP %0x Reset\n", + (unsigned int)r_ept); + wake_up(&r_ept->quota_wait); + } + spin_lock_irqsave(&local_endpoints_lock, flags); + list_for_each_entry(ept, &local_endpoints, list) { + if ((be32_to_cpu(ept->dst_prog) == prog) && + (be32_to_cpu(ept->dst_vers) == vers) && + (ept->restart_state & RESTART_PEND_SVR)) { + spin_lock(&ept->restart_lock); + ept->restart_state &= ~RESTART_PEND_SVR; + spin_unlock(&ept->restart_lock); + D("rpcrouter: Local EPT Reset %08x:%08x \n", + prog, vers); + wake_up(&ept->restart_wait); + wake_up(&ept->wait_q); + } + } + spin_unlock_irqrestore(&local_endpoints_lock, flags); +} + static int process_control_msg(union rr_control_msg *msg, int len) { union rr_control_msg ctl; @@ -364,6 +567,7 @@ static int process_control_msg(union rr_control_msg *msg, int len) struct rr_remote_endpoint *r_ept; int rc = 0; unsigned long flags; + static int first = 1; if (len != sizeof(*msg)) { printk(KERN_ERR "rpcrouter: r2r msg size %d != %d\n", @@ -388,12 +592,14 @@ static int process_control_msg(union rr_control_msg *msg, int len) /* TODO: long time to hold a spinlock... */ spin_lock_irqsave(&server_list_lock, flags); list_for_each_entry(server, &server_list, list) { + if (server->pid != RPCROUTER_PID_LOCAL) + continue; ctl.srv.pid = server->pid; ctl.srv.cid = server->cid; ctl.srv.prog = server->prog; ctl.srv.vers = server->vers; - RR("x NEW_SERVER id=%d:%08x prog=%08x:%d\n", + RR("x NEW_SERVER id=%d:%08x prog=%08x:%08x\n", server->pid, server->cid, server->prog, server->vers); @@ -401,7 +607,11 @@ static int process_control_msg(union rr_control_msg *msg, int len) } spin_unlock_irqrestore(&server_list_lock, flags); - queue_work(rpcrouter_workqueue, &work_create_rpcrouter_pdev); + if (first) { + first = 0; + queue_work(rpcrouter_workqueue, + &work_create_rpcrouter_pdev); + } break; case RPCROUTER_CTRL_CMD_RESUME_TX: @@ -420,7 +630,14 @@ static int process_control_msg(union rr_control_msg *msg, int len) break; case RPCROUTER_CTRL_CMD_NEW_SERVER: - RR("o NEW_SERVER id=%d:%08x prog=%08x:%d\n", + if (msg->srv.vers == 0) { + printk(KERN_ERR + "rpcrouter:Server create rejected, version = 0" + "program (%08x)\n", msg->srv.prog); + break; + } + + RR("o NEW_SERVER id=%d:%08x prog=%08x:%08x\n", msg->srv.pid, msg->srv.cid, msg->srv.prog, msg->srv.vers); server = rpcrouter_lookup_server(msg->srv.prog, msg->srv.vers); @@ -449,7 +666,9 @@ static int process_control_msg(union rr_control_msg *msg, int len) } else { if ((server->pid == msg->srv.pid) && (server->cid == msg->srv.cid)) { - printk(KERN_ERR "rpcrouter: Duplicate svr\n"); + handle_server_restart(server, msg->srv.cid, + msg->srv.prog, + msg->srv.vers); } else { server->pid = msg->srv.pid; server->cid = msg->srv.cid; @@ -566,6 +785,32 @@ static int rr_read(void *data, int len) return 0; } +#if defined(CONFIG_MSM_ONCRPCROUTER_DEBUG) +static char *type_to_str(int i) +{ + switch (i) { + case RPCROUTER_CTRL_CMD_DATA: + return "data "; + case RPCROUTER_CTRL_CMD_HELLO: + return "hello "; + case RPCROUTER_CTRL_CMD_BYE: + return "bye "; + case RPCROUTER_CTRL_CMD_NEW_SERVER: + return "new_srvr"; + case RPCROUTER_CTRL_CMD_REMOVE_SERVER: + return "rmv_srvr"; + case RPCROUTER_CTRL_CMD_REMOVE_CLIENT: + return "rmv_clnt"; + case RPCROUTER_CTRL_CMD_RESUME_TX: + return "resum_tx"; + case RPCROUTER_CTRL_CMD_EXIT: + return "cmd_exit"; + default: + return "invalid"; + } +} +#endif + static uint32_t r2r_buf[RPCROUTER_MSGSIZE_MAX]; static void do_read_data(struct work_struct *work) @@ -574,17 +819,21 @@ static void do_read_data(struct work_struct *work) struct rr_packet *pkt; struct rr_fragment *frag; struct msm_rpc_endpoint *ept; + struct rpc_request_hdr *rq; uint32_t pm, mid; unsigned long flags; if (rr_read(&hdr, sizeof(hdr))) goto fail_io; -#if TRACE_R2R_RAW RR("- ver=%d type=%d src=%d:%08x crx=%d siz=%d dst=%d:%08x\n", hdr.version, hdr.type, hdr.src_pid, hdr.src_cid, hdr.confirm_rx, hdr.size, hdr.dst_pid, hdr.dst_cid); -#endif + RAW_HDR("[r rr_h] " + "ver=%i,type=%s,src_pid=%08x,src_cid=%08x," + "confirm_rx=%i,size=%3i,dst_pid=%08x,dst_cid=%08x\n", + hdr.version, type_to_str(hdr.type), hdr.src_pid, hdr.src_cid, + hdr.confirm_rx, hdr.size, hdr.dst_pid, hdr.dst_cid); if (hdr.version != RPCROUTER_VERSION) { DIAG("version %d != %d\n", hdr.version, RPCROUTER_VERSION); @@ -617,17 +866,53 @@ static void do_read_data(struct work_struct *work) if (rr_read(frag->data, hdr.size)) goto fail_io; +#if defined(CONFIG_MSM_ONCRPCROUTER_DEBUG) + if ((smd_rpcrouter_debug_mask & RAW_PMR) && + ((pm >> 30 & 0x1) || (pm >> 31 & 0x1))) { + uint32_t xid = 0; + if (pm >> 30 & 0x1) { + rq = (struct rpc_request_hdr *) frag->data; + xid = ntohl(rq->xid); + } + if ((pm >> 31 & 0x1) || (pm >> 30 & 0x1)) + RAW_PMR_NOMASK("xid:0x%03x first=%i,last=%i,mid=%3i," + "len=%3i,dst_cid=%08x\n", + xid, + pm >> 30 & 0x1, + pm >> 31 & 0x1, + pm >> 16 & 0xF, + pm & 0xFF, hdr.dst_cid); + } + + if (smd_rpcrouter_debug_mask & SMEM_LOG) { + rq = (struct rpc_request_hdr *) frag->data; + if (rq->xid == 0) + smem_log_event(SMEM_LOG_PROC_ID_APPS | + RPC_ROUTER_LOG_EVENT_MID_READ, + PACMARK_MID(pm), + hdr.dst_cid, + hdr.src_cid); + else + smem_log_event(SMEM_LOG_PROC_ID_APPS | + RPC_ROUTER_LOG_EVENT_MSG_READ, + ntohl(rq->xid), + hdr.dst_cid, + hdr.src_cid); + } +#endif + ept = rpcrouter_lookup_local_endpoint(hdr.dst_cid); if (!ept) { DIAG("no local ept for cid %08x\n", hdr.dst_cid); kfree(frag); goto done; } - + /* See if there is already a partial packet that matches our mid * and if so, append this fragment to that packet. */ - mid = PACMARK_MID(pm); + mid = PACMARK_MID(pm); + spin_lock_irqsave(&ept->incomplete_lock, flags); list_for_each_entry(pkt, &ept->incomplete, list) { if (pkt->mid == mid) { pkt->last->next = frag; @@ -635,12 +920,15 @@ static void do_read_data(struct work_struct *work) pkt->length += frag->length; if (PACMARK_LAST(pm)) { list_del(&pkt->list); + spin_unlock_irqrestore(&ept->incomplete_lock, + flags); goto packet_complete; } + spin_unlock_irqrestore(&ept->incomplete_lock, flags); goto done; } } - + spin_unlock_irqrestore(&ept->incomplete_lock, flags); /* This mid is new -- create a packet for it, and put it on * the incomplete list if this fragment is not a last fragment, * otherwise put it on the read queue. @@ -662,15 +950,26 @@ packet_complete: wake_up(&ept->wait_q); spin_unlock_irqrestore(&ept->read_q_lock, flags); done: + if (hdr.confirm_rx) { union rr_control_msg msg; msg.cmd = RPCROUTER_CTRL_CMD_RESUME_TX; msg.cli.pid = hdr.dst_pid; msg.cli.cid = hdr.dst_cid; - + RR("x RESUME_TX id=%d:%08x\n", msg.cli.pid, msg.cli.cid); rpcrouter_send_control_msg(&msg); + +#if defined(CONFIG_MSM_ONCRPCROUTER_DEBUG) + if (smd_rpcrouter_debug_mask & SMEM_LOG) + smem_log_event(SMEM_LOG_PROC_ID_APPS | + RPC_ROUTER_LOG_EVENT_MSG_CFM_SNT, + RPCROUTER_PID_LOCAL, + hdr.dst_cid, + hdr.src_cid); +#endif + } queue_work(rpcrouter_workqueue, &work_read_data); @@ -691,6 +990,7 @@ void msm_rpc_setup_req(struct rpc_request_hdr *hdr, uint32_t prog, hdr->vers = cpu_to_be32(vers); hdr->procedure = cpu_to_be32(proc); } +EXPORT_SYMBOL(msm_rpc_setup_req); struct msm_rpc_endpoint *msm_rpc_open(void) { @@ -707,20 +1007,269 @@ int msm_rpc_close(struct msm_rpc_endpoint *ept) { return msm_rpcrouter_destroy_local_endpoint(ept); } - -int msm_rpc_write(struct msm_rpc_endpoint *ept, void *buffer, int count) +EXPORT_SYMBOL(msm_rpc_close); + +static int msm_rpc_write_pkt( + struct rr_header *hdr, + struct msm_rpc_endpoint *ept, + struct rr_remote_endpoint *r_ept, + void *buffer, + int count, + int first, + int last + ) { - struct rr_header hdr; - uint32_t pacmark; struct rpc_request_hdr *rq = buffer; - struct rr_remote_endpoint *r_ept; + uint32_t pacmark; unsigned long flags; int needed; + DEFINE_WAIT(__wait); - /* TODO: fragmentation for large outbound packets */ - if (count > (RPCROUTER_MSGSIZE_MAX - sizeof(uint32_t)) || !count) - return -EINVAL; + /* Create routing header */ + hdr->type = RPCROUTER_CTRL_CMD_DATA; + hdr->version = RPCROUTER_VERSION; + hdr->src_pid = ept->pid; + hdr->src_cid = ept->cid; + hdr->confirm_rx = 0; + hdr->size = count + sizeof(uint32_t); + + for (;;) { + prepare_to_wait(&ept->restart_wait, &__wait, + TASK_INTERRUPTIBLE); + spin_lock_irqsave(&ept->restart_lock, flags); + if (ept->restart_state == RESTART_NORMAL) { + spin_unlock_irqrestore(&ept->restart_lock, flags); + break; + } + if (signal_pending(current) && + ((!(ept->flags & MSM_RPC_UNINTERRUPTIBLE)))) { + spin_unlock_irqrestore(&ept->restart_lock, flags); + break; + } + spin_unlock_irqrestore(&ept->restart_lock, flags); + schedule(); + } + finish_wait(&ept->restart_wait, &__wait); + + if (signal_pending(current) && + (!(ept->flags & MSM_RPC_UNINTERRUPTIBLE))) { + return -ERESTARTSYS; + } + + for (;;) { + prepare_to_wait(&r_ept->quota_wait, &__wait, + TASK_INTERRUPTIBLE); + spin_lock_irqsave(&r_ept->quota_lock, flags); + if ((r_ept->tx_quota_cntr < RPCROUTER_DEFAULT_RX_QUOTA) || + (r_ept->quota_restart_state != RESTART_NORMAL)) + break; + if (signal_pending(current) && + (!(ept->flags & MSM_RPC_UNINTERRUPTIBLE))) + break; + spin_unlock_irqrestore(&r_ept->quota_lock, flags); + schedule(); + } + finish_wait(&r_ept->quota_wait, &__wait); + + if (r_ept->quota_restart_state != RESTART_NORMAL) { + spin_lock(&ept->restart_lock); + ept->restart_state &= ~RESTART_PEND_NTFY; + spin_unlock(&ept->restart_lock); + spin_unlock_irqrestore(&r_ept->quota_lock, flags); + return -ENETRESET; + } + + if (signal_pending(current) && + (!(ept->flags & MSM_RPC_UNINTERRUPTIBLE))) { + spin_unlock_irqrestore(&r_ept->quota_lock, flags); + return -ERESTARTSYS; + } + r_ept->tx_quota_cntr++; + if (r_ept->tx_quota_cntr == RPCROUTER_DEFAULT_RX_QUOTA) { + hdr->confirm_rx = 1; + +#if defined(CONFIG_MSM_ONCRPCROUTER_DEBUG) + if (smd_rpcrouter_debug_mask & SMEM_LOG) { + if (rq->xid == 0) + smem_log_event(SMEM_LOG_PROC_ID_APPS | + RPC_ROUTER_LOG_EVENT_MID_CFM_REQ, + hdr->dst_pid, + hdr->dst_cid, + hdr->src_cid); + else + smem_log_event(SMEM_LOG_PROC_ID_APPS | + RPC_ROUTER_LOG_EVENT_MSG_CFM_REQ, + hdr->dst_pid, + hdr->dst_cid, + hdr->src_cid); + } +#endif + + } + + /* bump pacmark while interrupts disabled to avoid race + * probably should be atomic op instead + */ + /* Pacmark maintained by ept and incremented for next + * messages when last fragment is set. + */ + pacmark = PACMARK(count, ept->next_pm, first, last); + ept->next_pm += last; + + spin_unlock_irqrestore(&r_ept->quota_lock, flags); + + spin_lock_irqsave(&smd_lock, flags); + spin_lock(&ept->restart_lock); + if (ept->restart_state != RESTART_NORMAL) { + ept->restart_state &= ~RESTART_PEND_NTFY; + spin_unlock(&ept->restart_lock); + spin_unlock_irqrestore(&smd_lock, flags); + return -ENETRESET; + } + + needed = sizeof(*hdr) + hdr->size; + while ((ept->restart_state == RESTART_NORMAL) && + (smd_write_avail(smd_channel) < needed)) { + spin_unlock(&ept->restart_lock); + spin_unlock_irqrestore(&smd_lock, flags); + msleep(250); + spin_lock_irqsave(&smd_lock, flags); + spin_lock(&ept->restart_lock); + } + if (ept->restart_state != RESTART_NORMAL) { + ept->restart_state &= ~RESTART_PEND_NTFY; + spin_unlock(&ept->restart_lock); + spin_unlock_irqrestore(&smd_lock, flags); + return -ENETRESET; + } + + /* TODO: deal with full fifo */ + smd_write(smd_channel, hdr, sizeof(*hdr)); + RAW_HDR("[w rr_h] " + "ver=%i,type=%s,src_pid=%08x,src_cid=%08x," + "confirm_rx=%i,size=%3i,dst_pid=%08x,dst_cid=%08x\n", + hdr->version, type_to_str(hdr->type), hdr->src_pid, hdr->src_cid, + hdr->confirm_rx, hdr->size, hdr->dst_pid, hdr->dst_cid); + smd_write(smd_channel, &pacmark, sizeof(pacmark)); + +#if defined(CONFIG_MSM_ONCRPCROUTER_DEBUG) + if ((smd_rpcrouter_debug_mask & RAW_PMW) && + ((pacmark >> 30 & 0x1) || (pacmark >> 31 & 0x1))) { + uint32_t xid = 0; + if (pacmark >> 30 & 0x1) + xid = ntohl(rq->xid); + if ((pacmark >> 31 & 0x1) || (pacmark >> 30 & 0x1)) + RAW_PMW_NOMASK("xid:0x%03x first=%i,last=%i,mid=%3i," + "len=%3i,src_cid=%x\n", + xid, + pacmark >> 30 & 0x1, + pacmark >> 31 & 0x1, + pacmark >> 16 & 0xF, + pacmark & 0xFF, hdr->src_cid); + } +#endif + + smd_write(smd_channel, buffer, count); + spin_unlock(&ept->restart_lock); + spin_unlock_irqrestore(&smd_lock, flags); + +#if defined(CONFIG_MSM_ONCRPCROUTER_DEBUG) + if (smd_rpcrouter_debug_mask & SMEM_LOG) { + if (rq->xid == 0) + smem_log_event(SMEM_LOG_PROC_ID_APPS | + RPC_ROUTER_LOG_EVENT_MID_WRITTEN, + PACMARK_MID(pacmark), + hdr->dst_cid, + hdr->src_cid); + else + smem_log_event(SMEM_LOG_PROC_ID_APPS | + RPC_ROUTER_LOG_EVENT_MSG_WRITTEN, + ntohl(rq->xid), + hdr->dst_cid, + hdr->src_cid); + } +#endif + + return needed; +} + +static struct msm_rpc_reply *get_pend_reply(struct msm_rpc_endpoint *ept, + uint32_t xid) +{ + unsigned long flags; + struct msm_rpc_reply *reply; + spin_lock_irqsave(&ept->reply_q_lock, flags); + list_for_each_entry(reply, &ept->reply_pend_q, list) { + if (reply->xid == xid) { + list_del(&reply->list); + spin_unlock_irqrestore(&ept->reply_q_lock, flags); + return reply; + } + } + spin_unlock_irqrestore(&ept->reply_q_lock, flags); + return NULL; +} + +static void set_avail_reply(struct msm_rpc_endpoint *ept, + struct msm_rpc_reply *reply) +{ + unsigned long flags; + spin_lock_irqsave(&ept->reply_q_lock, flags); + list_add_tail(&reply->list, &ept->reply_avail_q); + spin_unlock_irqrestore(&ept->reply_q_lock, flags); +} + +static struct msm_rpc_reply *get_avail_reply(struct msm_rpc_endpoint *ept) +{ + struct msm_rpc_reply *reply; + unsigned long flags; + if (list_empty(&ept->reply_avail_q)) { + if (ept->reply_cnt >= RPCROUTER_PEND_REPLIES_MAX) { + printk(KERN_ERR + "exceeding max replies of %d \n", + RPCROUTER_PEND_REPLIES_MAX); + return 0; + } + reply = kmalloc(sizeof(struct msm_rpc_reply), GFP_KERNEL); + if (!reply) + return 0; + D("Adding reply 0x%08x \n", (unsigned int)reply); + memset(reply, 0, sizeof(struct msm_rpc_reply)); + spin_lock_irqsave(&ept->reply_q_lock, flags); + ept->reply_cnt++; + spin_unlock_irqrestore(&ept->reply_q_lock, flags); + } else { + spin_lock_irqsave(&ept->reply_q_lock, flags); + reply = list_first_entry(&ept->reply_avail_q, + struct msm_rpc_reply, + list); + list_del(&reply->list); + spin_unlock_irqrestore(&ept->reply_q_lock, flags); + } + return reply; +} + +static void set_pend_reply(struct msm_rpc_endpoint *ept, + struct msm_rpc_reply *reply) +{ + unsigned long flags; + spin_lock_irqsave(&ept->reply_q_lock, flags); + list_add_tail(&reply->list, &ept->reply_pend_q); + spin_unlock_irqrestore(&ept->reply_q_lock, flags); +} + +int msm_rpc_write(struct msm_rpc_endpoint *ept, void *buffer, int count) +{ + struct rr_header hdr; + struct rpc_request_hdr *rq = buffer; + struct rr_remote_endpoint *r_ept; + struct msm_rpc_reply *reply; + int max_tx; + int tx_cnt; + char *tx_buf; + int rc; + int first_pkt = 1; /* snoop the RPC packet and enforce permissions */ @@ -742,10 +1291,11 @@ int msm_rpc_write(struct msm_rpc_endpoint *ept, void *buffer, int count) return -ENOTCONN; } if ((ept->dst_prog != rq->prog) || - (ept->dst_vers != rq->vers)) { + ((be32_to_cpu(ept->dst_vers) & 0x0fff0000) != + (be32_to_cpu(rq->vers) & 0x0fff0000))) { printk(KERN_ERR - "rr_write: cannot write to %08x:%d " - "(bound to %08x:%d)\n", + "rr_write: cannot write to %08x:%08x " + "(bound to %08x:%08x)\n", be32_to_cpu(rq->prog), be32_to_cpu(rq->vers), be32_to_cpu(ept->dst_prog), be32_to_cpu(ept->dst_vers)); @@ -758,24 +1308,15 @@ int msm_rpc_write(struct msm_rpc_endpoint *ept, void *buffer, int count) ept->dst_pid, ept->dst_cid, count); } else { /* RPC REPLY */ - /* TODO: locking */ - if (ept->reply_pid == 0xffffffff) { - printk(KERN_ERR - "rr_write: rejecting unexpected reply\n"); - return -EINVAL; - } - if (ept->reply_xid != rq->xid) { + reply = get_pend_reply(ept, rq->xid); + if (!reply) { printk(KERN_ERR - "rr_write: rejecting packet w/ bad xid\n"); + "rr_write: rejecting, reply not found \n"); return -EINVAL; } - - hdr.dst_pid = ept->reply_pid; - hdr.dst_cid = ept->reply_cid; - - /* consume this reply */ - ept->reply_pid = 0xffffffff; - + hdr.dst_pid = reply->pid; + hdr.dst_cid = reply->cid; + set_avail_reply(ept, reply); IO("REPLY to xid=%d @ %d:%08x (%d bytes)\n", be32_to_cpu(rq->xid), hdr.dst_pid, hdr.dst_cid, count); } @@ -789,62 +1330,38 @@ int msm_rpc_write(struct msm_rpc_endpoint *ept, void *buffer, int count) return -EHOSTUNREACH; } - /* Create routing header */ - hdr.type = RPCROUTER_CTRL_CMD_DATA; - hdr.version = RPCROUTER_VERSION; - hdr.src_pid = ept->pid; - hdr.src_cid = ept->cid; - hdr.confirm_rx = 0; - hdr.size = count + sizeof(uint32_t); - - for (;;) { - prepare_to_wait(&r_ept->quota_wait, &__wait, - TASK_INTERRUPTIBLE); - spin_lock_irqsave(&r_ept->quota_lock, flags); - if (r_ept->tx_quota_cntr < RPCROUTER_DEFAULT_RX_QUOTA) - break; - if (signal_pending(current) && - (!(ept->flags & MSM_RPC_UNINTERRUPTIBLE))) + tx_cnt = count; + tx_buf = buffer; + + /* The modem's router can only take 500 bytes of data. The + first 8 bytes it uses on the modem side for addressing, + the next 4 bytes are for the pacmark header. */ + max_tx = RPCROUTER_MSGSIZE_MAX - 8 - sizeof(uint32_t); + IO("Writing %d bytes, max pkt size is %d\n", + tx_cnt, max_tx); + while (tx_cnt > 0) { + if (tx_cnt > max_tx) { + rc = msm_rpc_write_pkt(&hdr, ept, r_ept, + tx_buf, max_tx, first_pkt, 0); + if (rc < 0) + return rc; + IO("Wrote %d bytes First %d, Last 0\n", rc, first_pkt); + tx_cnt -= max_tx; + tx_buf += max_tx; + } else { + rc = msm_rpc_write_pkt(&hdr, ept, r_ept, + tx_buf, tx_cnt, first_pkt, 1); + if (rc < 0) + return rc; + IO("Wrote %d bytes First %d Last 1 \n", rc, first_pkt); break; - spin_unlock_irqrestore(&r_ept->quota_lock, flags); - schedule(); - } - finish_wait(&r_ept->quota_wait, &__wait); - - if (signal_pending(current) && - (!(ept->flags & MSM_RPC_UNINTERRUPTIBLE))) { - spin_unlock_irqrestore(&r_ept->quota_lock, flags); - return -ERESTARTSYS; - } - r_ept->tx_quota_cntr++; - if (r_ept->tx_quota_cntr == RPCROUTER_DEFAULT_RX_QUOTA) - hdr.confirm_rx = 1; - - /* bump pacmark while interrupts disabled to avoid race - * probably should be atomic op instead - */ - pacmark = PACMARK(count, ++next_pacmarkid, 1); - - spin_unlock_irqrestore(&r_ept->quota_lock, flags); - - spin_lock_irqsave(&smd_lock, flags); - - needed = sizeof(hdr) + hdr.size; - while (smd_write_avail(smd_channel) < needed) { - spin_unlock_irqrestore(&smd_lock, flags); - msleep(250); - spin_lock_irqsave(&smd_lock, flags); + } + first_pkt = 0; } - /* TODO: deal with full fifo */ - smd_write(smd_channel, &hdr, sizeof(hdr)); - smd_write(smd_channel, &pacmark, sizeof(pacmark)); - smd_write(smd_channel, buffer, count); - - spin_unlock_irqrestore(&smd_lock, flags); - return count; } +EXPORT_SYMBOL(msm_rpc_write); /* * NOTE: It is the responsibility of the caller to kfree buffer @@ -884,6 +1401,7 @@ int msm_rpc_read(struct msm_rpc_endpoint *ept, void **buffer, return rc; } +EXPORT_SYMBOL(msm_rpc_read); int msm_rpc_call(struct msm_rpc_endpoint *ept, uint32_t proc, void *_request, int request_size, @@ -893,6 +1411,7 @@ int msm_rpc_call(struct msm_rpc_endpoint *ept, uint32_t proc, _request, request_size, NULL, 0, timeout); } +EXPORT_SYMBOL(msm_rpc_call); int msm_rpc_call_reply(struct msm_rpc_endpoint *ept, uint32_t proc, void *_request, int request_size, @@ -934,7 +1453,7 @@ int msm_rpc_call_reply(struct msm_rpc_endpoint *ept, uint32_t proc, continue; } /* If an earlier call timed out, we could get the (no - * longer wanted) reply for it. Ignore replies that + * longer wanted) reply for it. Ignore replies that * we don't expect */ if (reply->xid != req->xid) { @@ -963,6 +1482,7 @@ int msm_rpc_call_reply(struct msm_rpc_endpoint *ept, uint32_t proc, kfree(reply); return rc; } +EXPORT_SYMBOL(msm_rpc_call_reply); static inline int ept_packet_available(struct msm_rpc_endpoint *ept) @@ -981,19 +1501,31 @@ int __msm_rpc_read(struct msm_rpc_endpoint *ept, { struct rr_packet *pkt; struct rpc_request_hdr *rq; + struct msm_rpc_reply *reply; DEFINE_WAIT(__wait); unsigned long flags; int rc; IO("READ on ept %p\n", ept); + spin_lock_irqsave(&ept->restart_lock, flags); + if (ept->restart_state != RESTART_NORMAL) { + ept->restart_state &= ~RESTART_PEND_NTFY; + spin_unlock_irqrestore(&ept->restart_lock, flags); + return -ENETRESET; + } + spin_unlock_irqrestore(&ept->restart_lock, flags); if (ept->flags & MSM_RPC_UNINTERRUPTIBLE) { if (timeout < 0) { wait_event(ept->wait_q, ept_packet_available(ept)); + if (!msm_rpc_clear_netreset(ept)) + return -ENETRESET; } else { rc = wait_event_timeout( ept->wait_q, ept_packet_available(ept), timeout); + if (!msm_rpc_clear_netreset(ept)) + return -ENETRESET; if (rc == 0) return -ETIMEDOUT; } @@ -1001,12 +1533,16 @@ int __msm_rpc_read(struct msm_rpc_endpoint *ept, if (timeout < 0) { rc = wait_event_interruptible( ept->wait_q, ept_packet_available(ept)); + if (!msm_rpc_clear_netreset(ept)) + return -ENETRESET; if (rc < 0) return rc; } else { rc = wait_event_interruptible_timeout( ept->wait_q, ept_packet_available(ept), timeout); + if (!msm_rpc_clear_netreset(ept)) + return -ENETRESET; if (rc == 0) return -ETIMEDOUT; } @@ -1031,14 +1567,13 @@ int __msm_rpc_read(struct msm_rpc_endpoint *ept, rq = (void*) pkt->first->data; if ((rc >= (sizeof(uint32_t) * 3)) && (rq->type == 0)) { /* RPC CALL */ - if (ept->reply_pid != 0xffffffff) { - printk(KERN_WARNING - "rr_read: lost previous reply xid...\n"); - } - /* TODO: locking? */ - ept->reply_pid = pkt->hdr.src_pid; - ept->reply_cid = pkt->hdr.src_cid; - ept->reply_xid = rq->xid; + reply = get_avail_reply(ept); + if (!reply) + return -ENOMEM; + reply->cid = pkt->hdr.src_cid; + reply->pid = pkt->hdr.src_pid; + reply->xid = rq->xid; + set_pend_reply(ept, reply); } kfree(pkt); @@ -1047,6 +1582,65 @@ int __msm_rpc_read(struct msm_rpc_endpoint *ept, return rc; } +int msm_rpc_is_compatible_version(uint32_t server_version, + uint32_t client_version) +{ + + if ((server_version & RPC_VERSION_MODE_MASK) != + (client_version & RPC_VERSION_MODE_MASK)) + return 0; + + if (server_version & RPC_VERSION_MODE_MASK) + return server_version == client_version; + + return ((server_version & RPC_VERSION_MAJOR_MASK) == + (client_version & RPC_VERSION_MAJOR_MASK)) && + ((server_version & RPC_VERSION_MINOR_MASK) >= + (client_version & RPC_VERSION_MINOR_MASK)); +} +EXPORT_SYMBOL(msm_rpc_is_compatible_version); + +int msm_rpc_get_compatible_server(uint32_t prog, + uint32_t ver, + uint32_t *found_vers) +{ + struct rr_server *server; + unsigned long flags; + uint32_t found = -1; + if (found_vers == NULL) + return 0; + + spin_lock_irqsave(&server_list_lock, flags); + list_for_each_entry(server, &server_list, list) { + if ((server->prog == prog) && + msm_rpc_is_compatible_version(server->vers, ver)) { + *found_vers = server->vers; + spin_unlock_irqrestore(&server_list_lock, flags); + return 0; + } + } + spin_unlock_irqrestore(&server_list_lock, flags); + return found; +} +EXPORT_SYMBOL(msm_rpc_get_compatible_server); + +struct msm_rpc_endpoint *msm_rpc_connect_compatible(uint32_t prog, + uint32_t vers, unsigned flags) +{ + uint32_t found_vers; + int ret; + ret = msm_rpc_get_compatible_server(prog, vers, &found_vers); + if (ret < 0) + return ERR_PTR(-EHOSTUNREACH); + if (found_vers != vers) { + D("RPC Using new version 0x%08x(0x%08x) prog 0x%08x", + vers, found_vers, prog); + D(" ... Continuing\n"); + } + return msm_rpc_connect(prog, found_vers, flags); +} +EXPORT_SYMBOL(msm_rpc_connect_compatible); + struct msm_rpc_endpoint *msm_rpc_connect(uint32_t prog, uint32_t vers, unsigned flags) { struct msm_rpc_endpoint *ept; @@ -1059,7 +1653,7 @@ struct msm_rpc_endpoint *msm_rpc_connect(uint32_t prog, uint32_t vers, unsigned ept = msm_rpc_open(); if (IS_ERR(ept)) return ept; - + ept->flags = flags; ept->dst_pid = server->pid; ept->dst_cid = server->cid; @@ -1068,6 +1662,7 @@ struct msm_rpc_endpoint *msm_rpc_connect(uint32_t prog, uint32_t vers, unsigned return ept; } +EXPORT_SYMBOL(msm_rpc_connect); /* TODO: permission check? */ int msm_rpc_register_server(struct msm_rpc_endpoint *ept, @@ -1088,7 +1683,7 @@ int msm_rpc_register_server(struct msm_rpc_endpoint *ept, msg.srv.prog = prog; msg.srv.vers = vers; - RR("x NEW_SERVER id=%d:%08x prog=%08x:%d\n", + RR("x NEW_SERVER id=%d:%08x prog=%08x:%08x\n", ept->pid, ept->cid, prog, vers); rc = rpcrouter_send_control_msg(&msg); @@ -1098,6 +1693,20 @@ int msm_rpc_register_server(struct msm_rpc_endpoint *ept, return 0; } +int msm_rpc_clear_netreset(struct msm_rpc_endpoint *ept) +{ + unsigned long flags; + int rc = 1; + RR("RESET RESTART FLAG for EPT:%08x \n", (unsigned int)ept); + spin_lock_irqsave(&ept->restart_lock, flags); + if (ept->restart_state != RESTART_NORMAL) { + ept->restart_state &= ~RESTART_PEND_NTFY; + rc = 0; + } + spin_unlock_irqrestore(&ept->restart_lock, flags); + return rc; +} + /* TODO: permission check -- disallow unreg of somebody else's server */ int msm_rpc_unregister_server(struct msm_rpc_endpoint *ept, uint32_t prog, uint32_t vers) @@ -1111,6 +1720,29 @@ int msm_rpc_unregister_server(struct msm_rpc_endpoint *ept, return 0; } +static int msm_rpcrouter_modem_notify(struct notifier_block *this, + unsigned long code, + void *_cmd) +{ + switch (code) { + case MODEM_NOTIFIER_START_RESET: + NTFY("%s: MODEM_NOTIFIER_START_RESET", __func__); + modem_reset_start_cleanup(); + break; + case MODEM_NOTIFIER_END_RESET: + NTFY("%s: MODEM_NOTIFIER_END_RESET", __func__); + break; + default: + NTFY("%s: default", __func__); + break; + } + return NOTIFY_DONE; +} + +static struct notifier_block msm_rpcrouter_nb = { + .notifier_call = msm_rpcrouter_modem_notify, +}; + static int msm_rpcrouter_probe(struct platform_device *pdev) { int rc; @@ -1130,18 +1762,24 @@ static int msm_rpcrouter_probe(struct platform_device *pdev) if (rc < 0) goto fail_destroy_workqueue; + rc = modem_register_notifier(&msm_rpcrouter_nb); + if (rc < 0) + goto fail_remove_devices; + /* Open up SMD channel 2 */ initialized = 0; - rc = smd_open("SMD_RPCCALL", &smd_channel, NULL, rpcrouter_smdnotify); + rc = smd_open("RPCCALL", &smd_channel, NULL, rpcrouter_smdnotify); if (rc < 0) - goto fail_remove_devices; + goto fail_remove_reset_notifier; queue_work(rpcrouter_workqueue, &work_read_data); return 0; -fail_remove_devices: + fail_remove_reset_notifier: + modem_unregister_notifier(&msm_rpcrouter_nb); + fail_remove_devices: msm_rpcrouter_exit_devices(); -fail_destroy_workqueue: + fail_destroy_workqueue: destroy_workqueue(rpcrouter_workqueue); return rc; } @@ -1149,14 +1787,377 @@ fail_destroy_workqueue: static struct platform_driver msm_smd_channel2_driver = { .probe = msm_rpcrouter_probe, .driver = { - .name = "SMD_RPCCALL", - .owner = THIS_MODULE, + .name = "RPCCALL", + .owner = THIS_MODULE, }, }; +#if defined(CONFIG_DEBUG_FS) +#define HSIZE 13 + +struct sym { + uint32_t val; + char *str; + struct hlist_node node; +}; + +static struct sym oncrpc_syms[] = { + { 0x30000000, "CM" }, + { 0x30000001, "DB" }, + { 0x30000002, "SND" }, + { 0x30000003, "WMS" }, + { 0x30000004, "PDSM" }, + { 0x30000005, "MISC_MODEM_APIS" }, + { 0x30000006, "MISC_APPS_APIS" }, + { 0x30000007, "JOYST" }, + { 0x30000008, "VJOY" }, + { 0x30000009, "JOYSTC" }, + { 0x3000000a, "ADSPRTOSATOM" }, + { 0x3000000b, "ADSPRTOSMTOA" }, + { 0x3000000c, "I2C" }, + { 0x3000000d, "TIME_REMOTE" }, + { 0x3000000e, "NV" }, + { 0x3000000f, "CLKRGM_SEC" }, + { 0x30000010, "RDEVMAP" }, + { 0x30000011, "FS_RAPI" }, + { 0x30000012, "PBMLIB" }, + { 0x30000013, "AUDMGR" }, + { 0x30000014, "MVS" }, + { 0x30000015, "DOG_KEEPALIVE" }, + { 0x30000016, "GSDI_EXP" }, + { 0x30000017, "AUTH" }, + { 0x30000018, "NVRUIMI" }, + { 0x30000019, "MMGSDILIB" }, + { 0x3000001a, "CHARGER" }, + { 0x3000001b, "UIM" }, + { 0x3000001C, "ONCRPCTEST" }, + { 0x3000001d, "PDSM_ATL" }, + { 0x3000001e, "FS_XMOUNT" }, + { 0x3000001f, "SECUTIL " }, + { 0x30000020, "MCCMEID" }, + { 0x30000021, "PM_STROBE_FLASH" }, + { 0x30000022, "DS707_EXTIF" }, + { 0x30000023, "SMD BRIDGE_MODEM" }, + { 0x30000024, "SMD PORT_MGR" }, + { 0x30000025, "BUS_PERF" }, + { 0x30000026, "BUS_MON" }, + { 0x30000027, "MC" }, + { 0x30000028, "MCCAP" }, + { 0x30000029, "MCCDMA" }, + { 0x3000002a, "MCCDS" }, + { 0x3000002b, "MCCSCH" }, + { 0x3000002c, "MCCSRID" }, + { 0x3000002d, "SNM" }, + { 0x3000002e, "MCCSYOBJ" }, + { 0x3000002f, "DS707_APIS" }, + { 0x30000030, "DS_MP_SHIM_APPS_ASYNC" }, + { 0x30000031, "DSRLP_APIS" }, + { 0x30000032, "RLP_APIS" }, + { 0x30000033, "DS_MP_SHIM_MODEM" }, + { 0x30000034, "DSHDR_APIS" }, + { 0x30000035, "DSHDR_MDM_APIS" }, + { 0x30000036, "DS_MP_SHIM_APPS" }, + { 0x30000037, "HDRMC_APIS" }, + { 0x30000038, "SMD_BRIDGE_MTOA" }, + { 0x30000039, "SMD_BRIDGE_ATOM" }, + { 0x3000003a, "DPMAPP_OTG" }, + { 0x3000003b, "DIAG" }, + { 0x3000003c, "GSTK_EXP" }, + { 0x3000003d, "DSBC_MDM_APIS" }, + { 0x3000003e, "HDRMRLP_MDM_APIS" }, + { 0x3000003f, "HDRMRLP_APPS_APIS" }, + { 0x30000040, "HDRMC_MRLP_APIS" }, + { 0x30000041, "PDCOMM_APP_API" }, + { 0x30000042, "DSAT_APIS" }, + { 0x30000043, "MISC_RF_APIS" }, + { 0x30000044, "CMIPAPP" }, + { 0x30000045, "DSMP_UMTS_MODEM_APIS" }, + { 0x30000046, "DSMP_UMTS_APPS_APIS" }, + { 0x30000047, "DSUCSDMPSHIM" }, + { 0x30000048, "TIME_REMOTE_ATOM" }, + { 0x3000004a, "SD" }, + { 0x3000004b, "MMOC" }, + { 0x3000004c, "WLAN_ADP_FTM" }, + { 0x3000004d, "WLAN_CP_CM" }, + { 0x3000004e, "FTM_WLAN" }, + { 0x3000004f, "SDCC_CPRM" }, + { 0x30000050, "CPRMINTERFACE" }, + { 0x30000051, "DATA_ON_MODEM_MTOA_APIS" }, + { 0x30000052, "DATA_ON_APPS_ATOM_APIS" }, + { 0x30000053, "MISC_MODEM_APIS_NONWINMOB" }, + { 0x30000054, "MISC_APPS_APIS_NONWINMOB" }, + { 0x30000055, "PMEM_REMOTE" }, + { 0x30000056, "TCXOMGR" }, + { 0x30000057, "DSUCSDAPPIF_APIS" }, + { 0x30000058, "BT" }, + { 0x30000059, "PD_COMMS_API" }, + { 0x3000005a, "PD_COMMS_CLIENT_API" }, + { 0x3000005b, "PDAPI" }, + { 0x3000005c, "LSA_SUPL_DSM" }, + { 0x3000005d, "TIME_REMOTE_MTOA" }, + { 0x3000005e, "FTM_BT" }, + { 0X3000005f, "DSUCSDAPPIF_APIS" }, + { 0X30000060, "PMAPP_GEN" }, + { 0X30000061, "PM_LIB" }, + { 0X30000062, "KEYPAD" }, + { 0X30000063, "HSU_APP_APIS" }, + { 0X30000064, "HSU_MDM_APIS" }, + { 0X30000065, "ADIE_ADC_REMOTE_ATOM " }, + { 0X30000066, "TLMM_REMOTE_ATOM" }, + { 0X30000067, "UI_CALLCTRL" }, + { 0X30000068, "UIUTILS" }, + { 0X30000069, "PRL" }, + { 0X3000006a, "HW" }, + { 0X3000006b, "OEM_RAPI" }, + { 0X3000006c, "WMSPM" }, + { 0X3000006d, "BTPF" }, + { 0X3000006e, "CLKRGM_SYNC_EVENT" }, + { 0X3000006f, "USB_APPS_RPC" }, + { 0X30000070, "USB_MODEM_RPC" }, + { 0X30000071, "ADC" }, + { 0X30000072, "CAMERAREMOTED" }, + { 0X30000073, "SECAPIREMOTED" }, + { 0X30000074, "DSATAPI" }, + { 0X30000075, "CLKCTL_RPC" }, + { 0X30000076, "BREWAPPCOORD" }, + { 0X30000077, "ALTENVSHELL" }, + { 0X30000078, "WLAN_TRP_UTILS" }, + { 0X30000079, "GPIO_RPC" }, + { 0X3000007a, "PING_RPC" }, + { 0X3000007b, "DSC_DCM_API" }, + { 0X3000007c, "L1_DS" }, + { 0X3000007d, "QCHATPK_APIS" }, + { 0X3000007e, "GPS_API" }, + { 0X3000007f, "OSS_RRCASN_REMOTE" }, + { 0X30000080, "PMAPP_OTG_REMOTE" }, + { 0X30000081, "PING_MDM_RPC" }, + { 0X30000082, "PING_KERNEL_RPC" }, + { 0X30000083, "TIMETICK" }, + { 0X30000084, "WM_BTHCI_FTM " }, + { 0X30000085, "WM_BT_PF" }, + { 0X30000086, "IPA_IPC_APIS" }, + { 0X30000087, "UKCC_IPC_APIS" }, + { 0X30000088, "CMIPSMS " }, + { 0X30000089, "VBATT_REMOTE" }, + { 0X3000008a, "MFPAL" }, + { 0X3000008b, "DSUMTSPDPREG" }, + { 0X3000fe00, "RESTART_DAEMON NUMBER 0" }, + { 0X3000fe01, "RESTART_DAEMON NUMBER 1" }, + { 0X3000feff, "RESTART_DAEMON NUMBER 255" }, + { 0X3000fffe, "BACKWARDS_COMPATIBILITY_IN_RPC_CLNT_LOOKUP" }, + { 0X3000ffff, "RPC_ROUTER_SERVER_PROGRAM" }, +}; + +#define ONCRPC_SYM 0 + +static struct sym_tbl { + struct sym *data; + int size; + struct hlist_head hlist[HSIZE]; +} tbl[] = { + { oncrpc_syms, ARRAY_SIZE(oncrpc_syms) }, +}; + +#define hash(val) (val % HSIZE) + +static void init_syms(void) +{ + int i; + int j; + + for (i = 0; i < ARRAY_SIZE(tbl); ++i) + for (j = 0; j < HSIZE; ++j) + INIT_HLIST_HEAD(&tbl[i].hlist[j]); + + for (i = 0; i < ARRAY_SIZE(tbl); ++i) + for (j = 0; j < tbl[i].size; ++j) { + INIT_HLIST_NODE(&tbl[i].data[j].node); + hlist_add_head(&tbl[i].data[j].node, + &tbl[i].hlist[hash(tbl[i].data[j].val)]); + } +} + +static char *find_sym(uint32_t id, uint32_t val) +{ + struct hlist_node *n; + struct sym *s; + + hlist_for_each(n, &tbl[id].hlist[hash(val)]) { + s = hlist_entry(n, struct sym, node); + if (s->val == val) + return s->str; + } + + return 0; +} + +static int dump_servers(char *buf, int max) +{ + int i = 0; + unsigned long flags; + struct rr_server *svr; + char *sym; + + spin_lock_irqsave(&server_list_lock, flags); + list_for_each_entry(svr, &server_list, list) { + i += scnprintf(buf + i, max - i, "pdev_name: %s\n", + svr->pdev_name); + i += scnprintf(buf + i, max - i, "pid: 0x%08x\n", svr->pid); + i += scnprintf(buf + i, max - i, "cid: 0x%08x\n", svr->cid); + i += scnprintf(buf + i, max - i, "prog: 0x%08x", svr->prog); + sym = find_sym(ONCRPC_SYM, svr->prog); + if (sym) + i += scnprintf(buf + i, max - i, " (%s)\n", sym); + else + i += scnprintf(buf + i, max - i, "\n"); + i += scnprintf(buf + i, max - i, "vers: 0x%08x\n", svr->vers); + i += scnprintf(buf + i, max - i, "\n"); + } + spin_unlock_irqrestore(&server_list_lock, flags); + + return i; +} + +static int dump_remote_endpoints(char *buf, int max) +{ + int i = 0; + unsigned long flags; + struct rr_remote_endpoint *ept; + + spin_lock_irqsave(&remote_endpoints_lock, flags); + list_for_each_entry(ept, &remote_endpoints, list) { + i += scnprintf(buf + i, max - i, "pid: 0x%08x\n", ept->pid); + i += scnprintf(buf + i, max - i, "cid: 0x%08x\n", ept->cid); + i += scnprintf(buf + i, max - i, "tx_quota_cntr: %i\n", + ept->tx_quota_cntr); + i += scnprintf(buf + i, max - i, "quota_restart_state: %i\n", + ept->quota_restart_state); + i += scnprintf(buf + i, max - i, "\n"); + } + spin_unlock_irqrestore(&remote_endpoints_lock, flags); + + return i; +} + +static int dump_msm_rpc_endpoint(char *buf, int max) +{ + int i = 0; + unsigned long flags; + struct msm_rpc_reply *reply; + struct msm_rpc_endpoint *ept; + struct rr_packet *pkt; + char *sym; + + spin_lock_irqsave(&local_endpoints_lock, flags); + list_for_each_entry(ept, &local_endpoints, list) { + i += scnprintf(buf + i, max - i, "pid: 0x%08x\n", ept->pid); + i += scnprintf(buf + i, max - i, "cid: 0x%08x\n", ept->cid); + i += scnprintf(buf + i, max - i, "dst_pid: 0x%08x\n", + ept->dst_pid); + i += scnprintf(buf + i, max - i, "dst_cid: 0x%08x\n", + ept->dst_cid); + i += scnprintf(buf + i, max - i, "dst_prog: 0x%08x", + be32_to_cpu(ept->dst_prog)); + sym = find_sym(ONCRPC_SYM, be32_to_cpu(ept->dst_prog)); + if (sym) + i += scnprintf(buf + i, max - i, " (%s)\n", sym); + else + i += scnprintf(buf + i, max - i, "\n"); + i += scnprintf(buf + i, max - i, "dst_vers: 0x%08x\n", + be32_to_cpu(ept->dst_vers)); + i += scnprintf(buf + i, max - i, "reply_cnt: %i\n", + ept->reply_cnt); + i += scnprintf(buf + i, max - i, "next_pm: %i\n", + ept->next_pm); + i += scnprintf(buf + i, max - i, "restart_state: %i\n", + ept->restart_state); + + i += scnprintf(buf + i, max - i, "outstanding xids:\n"); + spin_lock(&ept->reply_q_lock); + list_for_each_entry(reply, &ept->reply_pend_q, list) + i += scnprintf(buf + i, max - i, " xid = %u\n", + ntohl(reply->xid)); + spin_unlock(&ept->reply_q_lock); + + i += scnprintf(buf + i, max - i, "complete unread packets:\n"); + spin_lock(&ept->read_q_lock); + list_for_each_entry(pkt, &ept->read_q, list) { + i += scnprintf(buf + i, max - i, " mid = %i\n", + pkt->mid); + i += scnprintf(buf + i, max - i, " length = %i\n", + pkt->length); + } + spin_unlock(&ept->read_q_lock); + i += scnprintf(buf + i, max - i, "\n"); + } + spin_unlock_irqrestore(&local_endpoints_lock, flags); + + return i; +} + +#define DEBUG_BUFMAX 4096 +static char debug_buffer[DEBUG_BUFMAX]; + +static ssize_t debug_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + int (*fill)(char *buf, int max) = file->private_data; + int bsize = fill(debug_buffer, DEBUG_BUFMAX); + return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize); +} + +static int debug_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static const struct file_operations debug_ops = { + .read = debug_read, + .open = debug_open, +}; + +static void debug_create(const char *name, mode_t mode, + struct dentry *dent, + int (*fill)(char *buf, int max)) +{ + debugfs_create_file(name, mode, dent, fill, &debug_ops); +} + +static void debugfs_init(void) +{ + struct dentry *dent; + + dent = debugfs_create_dir("smd_rpcrouter", 0); + if (IS_ERR(dent)) + return; + + debug_create("dump_msm_rpc_endpoints", 0444, dent, + dump_msm_rpc_endpoint); + debug_create("dump_remote_endpoints", 0444, dent, + dump_remote_endpoints); + debug_create("dump_servers", 0444, dent, + dump_servers); + + init_syms(); +} + +#else +static void debugfs_init(void) {} +#endif + + static int __init rpcrouter_init(void) { - return platform_driver_register(&msm_smd_channel2_driver); + int ret; + + ret = platform_driver_register(&msm_smd_channel2_driver); + if (ret) + return ret; + + debugfs_init(); + + return ret; } module_init(rpcrouter_init); diff --git a/arch/arm/mach-msm/smd_rpcrouter.h b/arch/arm/mach-msm/smd_rpcrouter.h index 9438ca3780c9..419befe151be 100644 --- a/arch/arm/mach-msm/smd_rpcrouter.h +++ b/arch/arm/mach-msm/smd_rpcrouter.h @@ -1,7 +1,7 @@ /** arch/arm/mach-msm/smd_rpcrouter.h * * Copyright (C) 2007 Google, Inc. - * Copyright (c) 2007 QUALCOMM Incorporated + * Copyright (c) 2007-2009, Code Aurora Forum. All rights reserved. * Author: San Mehat * * This software is licensed under the terms of the GNU General Public @@ -22,17 +22,17 @@ #include #include #include +#include #include #include -#include - /* definitions for the R2R wire protcol */ #define RPCROUTER_VERSION 1 #define RPCROUTER_PROCESSORS_MAX 4 #define RPCROUTER_MSGSIZE_MAX 512 +#define RPCROUTER_PEND_REPLIES_MAX 32 #define RPCROUTER_CLIENT_BCAST_ID 0xffffffff #define RPCROUTER_ROUTER_ADDRESS 0xfffffffe @@ -101,9 +101,13 @@ struct rr_packet { #define PACMARK_MID(n) (((n) >> 16) & 0xFF) #define PACMARK_LEN(n) ((n) & 0xFFFF) -static inline uint32_t PACMARK(uint32_t len, uint32_t mid, uint32_t last) +static inline uint32_t PACMARK(uint32_t len, uint32_t mid, uint32_t first, + uint32_t last) { - return (len & 0xFFFF) | ((mid & 0xFF) << 16) | ((!!last) << 31); + return (len & 0xFFFF) | + ((mid & 0xFF) << 16) | + ((!!first) << 30) | + ((!!last) << 31); } struct rr_server { @@ -126,17 +130,26 @@ struct rr_remote_endpoint { uint32_t cid; int tx_quota_cntr; + int quota_restart_state; spinlock_t quota_lock; wait_queue_head_t quota_wait; struct list_head list; }; +struct msm_rpc_reply { + struct list_head list; + uint32_t pid; + uint32_t cid; + uint32_t xid; /* be32 */ +}; + struct msm_rpc_endpoint { struct list_head list; /* incomplete packets waiting for assembly */ struct list_head incomplete; + spinlock_t incomplete_lock; /* complete packets waiting to be read */ struct list_head read_q; @@ -144,6 +157,11 @@ struct msm_rpc_endpoint { wait_queue_head_t wait_q; unsigned flags; + /* restart handling */ + int restart_state; + spinlock_t restart_lock; + wait_queue_head_t restart_wait; + /* endpoint address */ uint32_t pid; uint32_t cid; @@ -157,14 +175,12 @@ struct msm_rpc_endpoint { uint32_t dst_prog; /* be32 */ uint32_t dst_vers; /* be32 */ - /* reply remote address - * if reply_pid == 0xffffffff, none available - * RPC_REPLY writes may only go to the pid/cid/xid of the - * last RPC_CALL we received. - */ - uint32_t reply_pid; - uint32_t reply_cid; - uint32_t reply_xid; /* be32 */ + /* reply queue for inbound messages */ + struct list_head reply_pend_q; + struct list_head reply_avail_q; + spinlock_t reply_q_lock; + uint32_t reply_cnt; + uint32_t next_pm; /* Pacmark sequence */ /* device node if this endpoint is accessed via userspace */ dev_t dev; diff --git a/arch/arm/mach-msm/smd_rpcrouter_device.c b/arch/arm/mach-msm/smd_rpcrouter_device.c index 4722e644d2d2..b57746cbf392 100644 --- a/arch/arm/mach-msm/smd_rpcrouter_device.c +++ b/arch/arm/mach-msm/smd_rpcrouter_device.c @@ -1,7 +1,7 @@ /* arch/arm/mach-msm/smd_rpcrouter_device.c * * Copyright (C) 2007 Google, Inc. - * Copyright (c) 2007 QUALCOMM Incorporated + * Copyright (c) 2007-2009, Code Aurora Forum. All rights reserved. * Author: San Mehat * * This software is licensed under the terms of the GNU General Public @@ -30,10 +30,11 @@ #include #include -#include #include "smd_rpcrouter.h" +#define SAFETY_MEM_SIZE 65536 + /* Next minor # available for a remote server */ static int next_minor = 1; @@ -63,8 +64,19 @@ static int rpcrouter_open(struct inode *inode, struct file *filp) static int rpcrouter_release(struct inode *inode, struct file *filp) { struct msm_rpc_endpoint *ept; + static unsigned int rpcrouter_release_cnt; + ept = (struct msm_rpc_endpoint *) filp->private_data; + /* A user program with many files open when ends abruptly, + * will cause a flood of REMOVE_CLIENT messages to the + * remote processor. This will cause remote processors + * internal queue to overflow. Inserting a sleep here + * regularly is the effecient option. + */ + if (rpcrouter_release_cnt++ % 2) + msleep(1); + return msm_rpcrouter_destroy_local_endpoint(ept); } @@ -107,7 +119,8 @@ static ssize_t rpcrouter_write(struct file *filp, const char __user *buf, ept = (struct msm_rpc_endpoint *) filp->private_data; - if (count > RPCROUTER_MSGSIZE_MAX) + /* A check for safety, this seems non-standard */ + if (count > SAFETY_MEM_SIZE) return -EINVAL; k_buffer = kmalloc(count, GFP_KERNEL); @@ -139,13 +152,18 @@ static unsigned int rpcrouter_poll(struct file *filp, /* If there's data already in the read queue, return POLLIN. * Else, wait for the requested amount of time, and check again. */ + if (!list_empty(&ept->read_q)) mask |= POLLIN; + if (ept->restart_state != 0) + mask |= POLLERR; if (!mask) { poll_wait(filp, &ept->wait_q, wait); if (!list_empty(&ept->read_q)) mask |= POLLIN; + if (ept->restart_state != 0) + mask |= POLLERR; } return mask; @@ -156,7 +174,7 @@ static long rpcrouter_ioctl(struct file *filp, unsigned int cmd, { struct msm_rpc_endpoint *ept; struct rpcrouter_ioctl_server_args server_args; - int rc; + int rc = 0; uint32_t n; ept = (struct msm_rpc_endpoint *) filp->private_data; @@ -196,6 +214,10 @@ static long rpcrouter_ioctl(struct file *filp, unsigned int cmd, server_args.vers); break; + case RPC_ROUTER_IOCTL_CLEAR_NETRESET: + msm_rpc_clear_netreset(ept); + break; + default: rc = -EINVAL; break; @@ -227,6 +249,7 @@ static struct file_operations rpcrouter_router_fops = { int msm_rpcrouter_create_server_cdev(struct rr_server *server) { int rc; + uint32_t dev_vers; if (next_minor == RPCROUTER_MAX_REMOTE_SERVERS) { printk(KERN_ERR @@ -234,13 +257,25 @@ int msm_rpcrouter_create_server_cdev(struct rr_server *server) "RPCROUTER_MAX_REMOTE_SERVERS\n"); return -ENOBUFS; } + + /* Servers with bit 31 set are remote msm servers with hashkey version. + * Servers with bit 31 not set are remote msm servers with + * backwards compatible version type in which case the minor number + * (lower 16 bits) is set to zero. + * + */ + if ((server->vers & 0x80000000)) + dev_vers = server->vers; + else + dev_vers = server->vers & 0xffff0000; + server->device_number = MKDEV(MAJOR(msm_rpcrouter_devno), next_minor++); server->device = device_create(msm_rpcrouter_class, rpcrouter_device, server->device_number, NULL, "%.8x:%.8x", - server->prog, server->vers); + server->prog, dev_vers); if (IS_ERR(server->device)) { printk(KERN_ERR "rpcrouter: Unable to create device (%ld)\n", @@ -261,10 +296,16 @@ int msm_rpcrouter_create_server_cdev(struct rr_server *server) return 0; } +/* for backward compatible version type (31st bit cleared) + * clearing minor number (lower 16 bits) in device name + * is neccessary for driver binding + */ int msm_rpcrouter_create_server_pdev(struct rr_server *server) { sprintf(server->pdev_name, "rs%.8x:%.8x", - server->prog, server->vers); + server->prog, + (server->vers & RPC_VERSION_MODE_MASK) ? server->vers : + (server->vers & RPC_VERSION_MAJOR_MASK)); server->p_device.base.id = -1; server->p_device.base.name = server->pdev_name; diff --git a/arch/arm/mach-msm/smd_rpcrouter_servers.c b/arch/arm/mach-msm/smd_rpcrouter_servers.c index 791f7908aa57..496ab3fcb0e0 100644 --- a/arch/arm/mach-msm/smd_rpcrouter_servers.c +++ b/arch/arm/mach-msm/smd_rpcrouter_servers.c @@ -1,6 +1,7 @@ /* arch/arm/mach-msm/rpc_servers.c * * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2009, Code Aurora Forum. All rights reserved. * Author: Iliyan Malchev * * This software is licensed under the terms of the GNU General Public @@ -24,7 +25,6 @@ #include #include #include -#include #include #include @@ -56,7 +56,8 @@ static struct msm_rpc_server *rpc_server_find(uint32_t prog, uint32_t vers) mutex_lock(&rpc_server_list_lock); list_for_each_entry(server, &rpc_server_list, list) { - if ((server->prog == prog) && (server->vers == vers)) { + if ((server->prog == prog) && + msm_rpc_is_compatible_version(server->vers, vers)) { mutex_unlock(&rpc_server_list_lock); return server; } @@ -111,7 +112,11 @@ static int rpc_send_accepted_void_reply(struct msm_rpc_endpoint *client, reply->data.acc_hdr.verf_flavor = 0; reply->data.acc_hdr.verf_length = 0; - rc = msm_rpc_write(endpoint, reply_buf, sizeof(reply_buf)); + rc = msm_rpc_write(client, reply_buf, sizeof(reply_buf)); + if (rc == -ENETRESET) { + /* Modem restarted, drop reply, clear state */ + msm_rpc_clear_netreset(client); + } if (rc < 0) printk(KERN_ERR "%s: could not write response: %d\n", @@ -179,6 +184,8 @@ static int rpc_servers_thread(void *data) static int rpcservers_probe(struct platform_device *pdev) { + struct task_struct *server_thread; + endpoint = msm_rpc_open(); if (IS_ERR(endpoint)) return PTR_ERR(endpoint); @@ -188,7 +195,9 @@ static int rpcservers_probe(struct platform_device *pdev) rpc_server_register_all(); /* start the kernel thread */ - kthread_run(rpc_servers_thread, NULL, "krpcserversd"); + server_thread = kthread_run(rpc_servers_thread, NULL, "krpcserversd"); + if (IS_ERR(server_thread)) + return PTR_ERR(server_thread); return 0; } diff --git a/arch/arm/mach-msm/smd_tty.c b/arch/arm/mach-msm/smd_tty.c index f40944958d44..22fca39cd205 100644 --- a/arch/arm/mach-msm/smd_tty.c +++ b/arch/arm/mach-msm/smd_tty.c @@ -1,6 +1,7 @@ /* arch/arm/mach-msm/smd_tty.c * * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2009, Code Aurora Forum. All rights reserved. * Author: Brian Swetland * * This software is licensed under the terms of the GNU General Public @@ -19,14 +20,16 @@ #include #include #include +#include #include #include #include #include +#include "smd_private.h" -#define MAX_SMD_TTYS 32 +#define MAX_SMD_TTYS 53 static DEFINE_MUTEX(smd_tty_lock); @@ -34,28 +37,97 @@ struct smd_tty_info { smd_channel_t *ch; struct tty_struct *tty; int open_count; + struct work_struct tty_work; }; static struct smd_tty_info smd_tty[MAX_SMD_TTYS]; +static struct workqueue_struct *smd_tty_wq; +char *tty_map_tbl[] = +{ + /* 0 */ "DS", + /* 1 */ "DIAG", + /* 2 */ "RPCCALL", + /* 3 */ "RPCRPY", + /* 4 */ "BT", + /* 5 */ "CONTROL", + /* 6 */ "MCPY_RVD", + /* 7 */ "DATA1", + /* 8 */ "DATA2", + /* 9 */ "DATA3", + /* 10 */ "DATA4", + /* 11 */ "DATA5", + /* 12 */ "DATA6", + /* 13 */ "DATA7", + /* 14 */ "DATA8", + /* 15 */ "DATA9", + /* 16 */ "DATA10", + /* 17 */ "DATA11", + /* 18 */ "DATA12", + /* 19 */ "DATA13", + /* 20 */ "DATA14", + /* 21 */ "DATA15", + /* 22 */ "DATA16", + /* 23 */ "DATA17", + /* 24 */ "DATA18", + /* 25 */ "DATA19", + /* 26 */ "DATA20", + /* 27 */ "GPSNMEA", + /* 28 */ "BRG_1", + /* 29 */ "BRG_2", + /* 30 */ "BRG_3", + /* 31 */ "BRG_4", + /* 32 */ "BRG_5", + /* 33 */ "CS_A2M", + /* 34 */ "CS_A2Q6", + /* 35 */ "CS_M2Q6", + /* 36 */ "LOOPBACK", + + /* new dynamically allocated ctl ports */ + /* 37 */ "DATA0_CNTL", /* name does not exist */ + /* 38 */ "DATA1_CNTL", + /* 39 */ "DATA2_CNTL", + /* 40 */ "DATA3_CNTL", + /* 41 */ "DATA4_CNTL", + /* 42 */ "DATA5_CNTL", /* <- smdcntl0 */ + /* 43 */ "DATA6_CNTL", /* <- smdcntl1 */ + /* 44 */ "DATA7_CNTL", /* <- smdcntl2 */ + /* 45 */ "DATA8_CNTL", + /* 46 */ "DATA9_CNTL", + /* 47 */ "DATA10_CNTL", + /* 48 */ "DATA11_CNTL", + /* 49 */ "DATA12_CNTL", + /* 50 */ "DATA13_CNTL", + /* 51 */ "DATA14_CNTL", + /* 52 */ "DATA15_CNTL", +}; -static void smd_tty_notify(void *priv, unsigned event) +static void smd_tty_work_func(struct work_struct *work) { unsigned char *ptr; int avail; - struct smd_tty_info *info = priv; + struct smd_tty_info *info = container_of(work, + struct smd_tty_info, + tty_work); struct tty_struct *tty = info->tty; if (!tty) return; - if (event != SMD_EVENT_DATA) - return; - for (;;) { if (test_bit(TTY_THROTTLED, &tty->flags)) break; + + mutex_lock(&smd_tty_lock); + if (info->ch == 0) { + mutex_unlock(&smd_tty_lock); + break; + } + avail = smd_read_avail(info->ch); - if (avail == 0) break; + if (avail == 0) { + mutex_unlock(&smd_tty_lock); + break; + } avail = tty_prepare_flip_string(tty, &ptr, avail); @@ -66,6 +138,7 @@ static void smd_tty_notify(void *priv, unsigned event) */ printk(KERN_ERR "OOPS - smd_tty_buffer mismatch?!"); } + mutex_unlock(&smd_tty_lock); tty_flip_buffer_push(tty); } @@ -74,20 +147,24 @@ static void smd_tty_notify(void *priv, unsigned event) tty_wakeup(tty); } +static void smd_tty_notify(void *priv, unsigned event) +{ + struct smd_tty_info *info = priv; + + if (event != SMD_EVENT_DATA) + return; + + queue_work(smd_tty_wq, &info->tty_work); +} + static int smd_tty_open(struct tty_struct *tty, struct file *f) { int res = 0; int n = tty->index; struct smd_tty_info *info; - const char *name; - if (n == 0) { - name = "SMD_DS"; - } else if (n == 27) { - name = "SMD_GPSNMEA"; - } else { + if ((n < 0) || (n >= MAX_SMD_TTYS)) return -ENODEV; - } info = smd_tty + n; @@ -96,10 +173,21 @@ static int smd_tty_open(struct tty_struct *tty, struct file *f) if (info->open_count++ == 0) { info->tty = tty; - if (info->ch) { - smd_kick(info->ch); - } else { - res = smd_open(name, &info->ch, info, smd_tty_notify); + if (!info->ch) { + if (strncmp(tty_map_tbl[n], "LOOPBACK", 9) == 0) { + /* set smsm state to SMSM_SMD_LOOPBACK state + ** and wait allowing enough time for Modem side + ** to open the loopback port (Currently, this is + ** this is effecient than polling). + */ + smsm_change_state(SMSM_APPS_STATE, + 0, SMSM_SMD_LOOPBACK); + msleep(100); + } else if (strncmp(tty_map_tbl[n], "DS", 3) == 0) { + tty->low_latency = 1; + } + res = smd_open(tty_map_tbl[n], &info->ch, info, + smd_tty_notify); } } mutex_unlock(&smd_tty_lock); @@ -157,7 +245,23 @@ static int smd_tty_chars_in_buffer(struct tty_struct *tty) static void smd_tty_unthrottle(struct tty_struct *tty) { struct smd_tty_info *info = tty->driver_data; - smd_kick(info->ch); + queue_work(smd_tty_wq, &info->tty_work); + return; +} + +static int smd_tty_tiocmget(struct tty_struct *tty, struct file *file) +{ + struct smd_tty_info *info = tty->driver_data; + + return smd_tiocmget(info->ch); +} + +static int smd_tty_tiocmset(struct tty_struct *tty, struct file *file, + unsigned int set, unsigned int clear) +{ + struct smd_tty_info *info = tty->driver_data; + + return smd_tiocmset(info->ch, set, clear); } static struct tty_operations smd_tty_ops = { @@ -167,6 +271,8 @@ static struct tty_operations smd_tty_ops = { .write_room = smd_tty_write_room, .chars_in_buffer = smd_tty_chars_in_buffer, .unthrottle = smd_tty_unthrottle, + .tiocmget = smd_tty_tiocmget, + .tiocmset = smd_tty_tiocmset, }; static struct tty_driver *smd_tty_driver; @@ -175,9 +281,15 @@ static int __init smd_tty_init(void) { int ret; + smd_tty_wq = create_singlethread_workqueue("smd_tty"); + if (smd_tty_wq == 0) + return -ENOMEM; + smd_tty_driver = alloc_tty_driver(MAX_SMD_TTYS); - if (smd_tty_driver == 0) + if (smd_tty_driver == 0) { + destroy_workqueue(smd_tty_wq); return -ENOMEM; + } smd_tty_driver->owner = THIS_MODULE; smd_tty_driver->driver_name = "smd_tty_driver"; @@ -200,7 +312,19 @@ static int __init smd_tty_init(void) /* this should be dynamic */ tty_register_device(smd_tty_driver, 0, 0); + INIT_WORK(&smd_tty[0].tty_work, smd_tty_work_func); + + tty_register_device(smd_tty_driver, 7, 0); + INIT_WORK(&smd_tty[7].tty_work, smd_tty_work_func); + + tty_register_device(smd_tty_driver, 17, 0); + INIT_WORK(&smd_tty[27].tty_work, smd_tty_work_func); + tty_register_device(smd_tty_driver, 27, 0); + INIT_WORK(&smd_tty[27].tty_work, smd_tty_work_func); + + tty_register_device(smd_tty_driver, SMD_PORT_LOOPBACK, 0); + INIT_WORK(&smd_tty[SMD_PORT_LOOPBACK].tty_work, smd_tty_work_func); return 0; } diff --git a/arch/arm/mach-msm/smem_log.c b/arch/arm/mach-msm/smem_log.c new file mode 100644 index 000000000000..f263c1769a4b --- /dev/null +++ b/arch/arm/mach-msm/smem_log.c @@ -0,0 +1,2019 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +/* + * Shared memory logging implementation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "smd_private.h" + +#define DEBUG +#undef DEBUG + +#ifdef DEBUG +#define D_DUMP_BUFFER(prestr, cnt, buf) \ +do { \ + int i; \ + printk(KERN_ERR "%s", prestr); \ + for (i = 0; i < cnt; i++) \ + printk(KERN_ERR "%.2x", buf[i]); \ + printk(KERN_ERR "\n"); \ +} while (0) +#else +#define D_DUMP_BUFFER(prestr, cnt, buf) +#endif + +#ifdef DEBUG +#define D(x...) printk(x) +#else +#define D(x...) do {} while (0) +#endif + +#define TIMESTAMP_ADDR (MSM_CSR_BASE + 0x04) + +struct smem_log_item { + uint32_t identifier; + uint32_t timetick; + uint32_t data1; + uint32_t data2; + uint32_t data3; +}; + +#define SMEM_LOG_NUM_ENTRIES 2000 +#define SMEM_LOG_EVENTS_SIZE (sizeof(struct smem_log_item) * \ + SMEM_LOG_NUM_ENTRIES) + +#define SMEM_LOG_NUM_STATIC_ENTRIES 150 +#define SMEM_STATIC_LOG_EVENTS_SIZE (sizeof(struct smem_log_item) * \ + SMEM_LOG_NUM_STATIC_ENTRIES) + +#define SMEM_SPINLOCK_SMEM_LOG 2 +#define SMEM_SPINLOCK_STATIC_LOG 5 + +static struct smem_log_item __iomem *smem_log_events; +static uint32_t __iomem *smem_log_idx; +static remote_spinlock_t remote_spinlock; +static struct smem_log_item __iomem *smem_log_static_events; +static uint32_t __iomem *smem_log_static_idx; +static remote_spinlock_t remote_spinlock_static; + +struct smem_log_inst { + struct smem_log_item __iomem *smem_log_cur_events; + uint32_t __iomem *smem_log_cur_idx; + int smem_log_cur_num; + remote_spinlock_t *cur_remote_spinlock; +}; + +#if defined(CONFIG_DEBUG_FS) + +#define HSIZE 13 + +struct sym { + uint32_t val; + char *str; + struct hlist_node node; +}; + +struct sym id_syms[] = { + { SMEM_LOG_PROC_ID_MODEM, "MODM" }, + { SMEM_LOG_PROC_ID_Q6, "QDSP" }, + { SMEM_LOG_PROC_ID_APPS, "APPS" }, +}; + +struct sym base_syms[] = { + { SMEM_LOG_ONCRPC_EVENT_BASE, "ONCRPC" }, + { SMEM_LOG_SMEM_EVENT_BASE, "SMEM" }, + { SMEM_LOG_TMC_EVENT_BASE, "TMC" }, + { SMEM_LOG_TIMETICK_EVENT_BASE, "TIMETICK" }, + { SMEM_LOG_DEM_EVENT_BASE, "DEM" }, + { SMEM_LOG_ERROR_EVENT_BASE, "ERROR" }, + { SMEM_LOG_DCVS_EVENT_BASE, "DCVS" }, + { SMEM_LOG_SLEEP_EVENT_BASE, "SLEEP" }, + { SMEM_LOG_RPC_ROUTER_EVENT_BASE, "ROUTER" }, +}; + +struct sym event_syms[] = { +#if defined(CONFIG_MSM_N_WAY_SMSM) + { DEM_SMSM_ISR, "SMSM_ISR" }, + { DEM_STATE_CHANGE, "STATE_CHANGE" }, + { DEM_STATE_MACHINE_ENTER, "STATE_MACHINE_ENTER" }, + { DEM_ENTER_SLEEP, "ENTER_SLEEP" }, + { DEM_END_SLEEP, "END_SLEEP" }, + { DEM_SETUP_SLEEP, "SETUP_SLEEP" }, + { DEM_SETUP_POWER_COLLAPSE, "SETUP_POWER_COLLAPSE" }, + { DEM_SETUP_SUSPEND, "SETUP_SUSPEND" }, + { DEM_EARLY_EXIT, "EARLY_EXIT" }, + { DEM_WAKEUP_REASON, "WAKEUP_REASON" }, + { DEM_DETECT_WAKEUP, "DETECT_WAKEUP" }, + { DEM_DETECT_RESET, "DETECT_RESET" }, + { DEM_DETECT_SLEEPEXIT, "DETECT_SLEEPEXIT" }, + { DEM_DETECT_RUN, "DETECT_RUN" }, + { DEM_APPS_SWFI, "APPS_SWFI" }, + { DEM_SEND_WAKEUP, "SEND_WAKEUP" }, + { DEM_ASSERT_OKTS, "ASSERT_OKTS" }, + { DEM_NEGATE_OKTS, "NEGATE_OKTS" }, + { DEM_PROC_COMM_CMD, "PROC_COMM_CMD" }, + { DEM_REMOVE_PROC_PWR, "REMOVE_PROC_PWR" }, + { DEM_RESTORE_PROC_PWR, "RESTORE_PROC_PWR" }, + { DEM_SMI_CLK_DISABLED, "SMI_CLK_DISABLED" }, + { DEM_SMI_CLK_ENABLED, "SMI_CLK_ENABLED" }, + { DEM_MAO_INTS, "MAO_INTS" }, + { DEM_APPS_WAKEUP_INT, "APPS_WAKEUP_INT" }, + { DEM_PROC_WAKEUP, "PROC_WAKEUP" }, + { DEM_PROC_POWERUP, "PROC_POWERUP" }, + { DEM_TIMER_EXPIRED, "TIMER_EXPIRED" }, + { DEM_SEND_BATTERY_INFO, "SEND_BATTERY_INFO" }, + { DEM_REMOTE_PWR_CB, "REMOTE_PWR_CB" }, + { DEM_TIME_SYNC_START, "TIME_SYNC_START" }, + { DEM_TIME_SYNC_SEND_VALUE, "TIME_SYNC_SEND_VALUE" }, + { DEM_TIME_SYNC_DONE, "TIME_SYNC_DONE" }, + { DEM_TIME_SYNC_REQUEST, "TIME_SYNC_REQUEST" }, + { DEM_TIME_SYNC_POLL, "TIME_SYNC_POLL" }, + { DEM_TIME_SYNC_INIT, "TIME_SYNC_INIT" }, + { DEM_INIT, "INIT" }, +#else + + { DEM_NO_SLEEP, "NO_SLEEP" }, + { DEM_INSUF_TIME, "INSUF_TIME" }, + { DEMAPPS_ENTER_SLEEP, "APPS_ENTER_SLEEP" }, + { DEMAPPS_DETECT_WAKEUP, "APPS_DETECT_WAKEUP" }, + { DEMAPPS_END_APPS_TCXO, "APPS_END_APPS_TCXO" }, + { DEMAPPS_ENTER_SLEEPEXIT, "APPS_ENTER_SLEEPEXIT" }, + { DEMAPPS_END_APPS_SLEEP, "APPS_END_APPS_SLEEP" }, + { DEMAPPS_SETUP_APPS_PWRCLPS, "APPS_SETUP_APPS_PWRCLPS" }, + { DEMAPPS_PWRCLPS_EARLY_EXIT, "APPS_PWRCLPS_EARLY_EXIT" }, + { DEMMOD_SEND_WAKEUP, "MOD_SEND_WAKEUP" }, + { DEMMOD_NO_APPS_VOTE, "MOD_NO_APPS_VOTE" }, + { DEMMOD_NO_TCXO_SLEEP, "MOD_NO_TCXO_SLEEP" }, + { DEMMOD_BT_CLOCK, "MOD_BT_CLOCK" }, + { DEMMOD_UART_CLOCK, "MOD_UART_CLOCK" }, + { DEMMOD_OKTS, "MOD_OKTS" }, + { DEM_SLEEP_INFO, "SLEEP_INFO" }, + { DEMMOD_TCXO_END, "MOD_TCXO_END" }, + { DEMMOD_END_SLEEP_SIG, "MOD_END_SLEEP_SIG" }, + { DEMMOD_SETUP_APPSSLEEP, "MOD_SETUP_APPSSLEEP" }, + { DEMMOD_ENTER_TCXO, "MOD_ENTER_TCXO" }, + { DEMMOD_WAKE_APPS, "MOD_WAKE_APPS" }, + { DEMMOD_POWER_COLLAPSE_APPS, "MOD_POWER_COLLAPSE_APPS" }, + { DEMMOD_RESTORE_APPS_PWR, "MOD_RESTORE_APPS_PWR" }, + { DEMAPPS_ASSERT_OKTS, "APPS_ASSERT_OKTS" }, + { DEMAPPS_RESTART_START_TIMER, "APPS_RESTART_START_TIMER" }, + { DEMAPPS_ENTER_RUN, "APPS_ENTER_RUN" }, + { DEMMOD_MAO_INTS, "MOD_MAO_INTS" }, + { DEMMOD_POWERUP_APPS_CALLED, "MOD_POWERUP_APPS_CALLED" }, + { DEMMOD_PC_TIMER_EXPIRED, "MOD_PC_TIMER_EXPIRED" }, + { DEM_DETECT_SLEEPEXIT, "_DETECT_SLEEPEXIT" }, + { DEM_DETECT_RUN, "DETECT_RUN" }, + { DEM_SET_APPS_TIMER, "SET_APPS_TIMER" }, + { DEM_NEGATE_OKTS, "NEGATE_OKTS" }, + { DEMMOD_APPS_WAKEUP_INT, "MOD_APPS_WAKEUP_INT" }, + { DEMMOD_APPS_SWFI, "MOD_APPS_SWFI" }, + { DEM_SEND_BATTERY_INFO, "SEND_BATTERY_INFO" }, + { DEM_SMI_CLK_DISABLED, "SMI_CLK_DISABLED" }, + { DEM_SMI_CLK_ENABLED, "SMI_CLK_ENABLED" }, + { DEMAPPS_SETUP_APPS_SUSPEND, "APPS_SETUP_APPS_SUSPEND" }, + { DEM_RPC_EARLY_EXIT, "RPC_EARLY_EXIT" }, + { DEMAPPS_WAKEUP_REASON, "APPS_WAKEUP_REASON" }, + { DEM_INIT, "INIT" }, +#endif + { DEMMOD_UMTS_BASE, "MOD_UMTS_BASE" }, + { DEMMOD_GL1_GO_TO_SLEEP, "GL1_GO_TO_SLEEP" }, + { DEMMOD_GL1_SLEEP_START, "GL1_SLEEP_START" }, + { DEMMOD_GL1_AFTER_GSM_CLK_ON, "GL1_AFTER_GSM_CLK_ON" }, + { DEMMOD_GL1_BEFORE_RF_ON, "GL1_BEFORE_RF_ON" }, + { DEMMOD_GL1_AFTER_RF_ON, "GL1_AFTER_RF_ON" }, + { DEMMOD_GL1_FRAME_TICK, "GL1_FRAME_TICK" }, + { DEMMOD_GL1_WCDMA_START, "GL1_WCDMA_START" }, + { DEMMOD_GL1_WCDMA_ENDING, "GL1_WCDMA_ENDING" }, + { DEMMOD_UMTS_NOT_OKTS, "UMTS_NOT_OKTS" }, + { DEMMOD_UMTS_START_TCXO_SHUTDOWN, "UMTS_START_TCXO_SHUTDOWN" }, + { DEMMOD_UMTS_END_TCXO_SHUTDOWN, "UMTS_END_TCXO_SHUTDOWN" }, + { DEMMOD_UMTS_START_ARM_HALT, "UMTS_START_ARM_HALT" }, + { DEMMOD_UMTS_END_ARM_HALT, "UMTS_END_ARM_HALT" }, + { DEMMOD_UMTS_NEXT_WAKEUP_SCLK, "UMTS_NEXT_WAKEUP_SCLK" }, + { TIME_REMOTE_LOG_EVENT_START, "START" }, + { TIME_REMOTE_LOG_EVENT_GOTO_WAIT, + "GOTO_WAIT" }, + { TIME_REMOTE_LOG_EVENT_GOTO_INIT, + "GOTO_INIT" }, + { ERR_ERROR_FATAL, "ERR_ERROR_FATAL" }, + { ERR_ERROR_FATAL_TASK, "ERR_ERROR_FATAL_TASK" }, + { DCVSAPPS_LOG_IDLE, "DCVSAPPS_LOG_IDLE" }, + { DCVSAPPS_LOG_ERR, "DCVSAPPS_LOG_ERR" }, + { DCVSAPPS_LOG_CHG, "DCVSAPPS_LOG_CHG" }, + { DCVSAPPS_LOG_REG, "DCVSAPPS_LOG_REG" }, + { DCVSAPPS_LOG_DEREG, "DCVSAPPS_LOG_DEREG" }, + { SMEM_LOG_EVENT_CB, "CB" }, + { SMEM_LOG_EVENT_START, "START" }, + { SMEM_LOG_EVENT_INIT, "INIT" }, + { SMEM_LOG_EVENT_RUNNING, "RUNNING" }, + { SMEM_LOG_EVENT_STOP, "STOP" }, + { SMEM_LOG_EVENT_RESTART, "RESTART" }, + { SMEM_LOG_EVENT_SS, "SS" }, + { SMEM_LOG_EVENT_READ, "READ" }, + { SMEM_LOG_EVENT_WRITE, "WRITE" }, + { SMEM_LOG_EVENT_SIGS1, "SIGS1" }, + { SMEM_LOG_EVENT_SIGS2, "SIGS2" }, + { SMEM_LOG_EVENT_WRITE_DM, "WRITE_DM" }, + { SMEM_LOG_EVENT_READ_DM, "READ_DM" }, + { SMEM_LOG_EVENT_SKIP_DM, "SKIP_DM" }, + { SMEM_LOG_EVENT_STOP_DM, "STOP_DM" }, + { SMEM_LOG_EVENT_ISR, "ISR" }, + { SMEM_LOG_EVENT_TASK, "TASK" }, + { SMEM_LOG_EVENT_RS, "RS" }, + { ONCRPC_LOG_EVENT_SMD_WAIT, "SMD_WAIT" }, + { ONCRPC_LOG_EVENT_RPC_WAIT, "RPC_WAIT" }, + { ONCRPC_LOG_EVENT_RPC_BOTH_WAIT, "RPC_BOTH_WAIT" }, + { ONCRPC_LOG_EVENT_RPC_INIT, "RPC_INIT" }, + { ONCRPC_LOG_EVENT_RUNNING, "RUNNING" }, + { ONCRPC_LOG_EVENT_APIS_INITED, "APIS_INITED" }, + { ONCRPC_LOG_EVENT_AMSS_RESET, "AMSS_RESET" }, + { ONCRPC_LOG_EVENT_SMD_RESET, "SMD_RESET" }, + { ONCRPC_LOG_EVENT_ONCRPC_RESET, "ONCRPC_RESET" }, + { ONCRPC_LOG_EVENT_CB, "CB" }, + { ONCRPC_LOG_EVENT_STD_CALL, "STD_CALL" }, + { ONCRPC_LOG_EVENT_STD_REPLY, "STD_REPLY" }, + { ONCRPC_LOG_EVENT_STD_CALL_ASYNC, "STD_CALL_ASYNC" }, + { NO_SLEEP_OLD, "NO_SLEEP_OLD" }, + { INSUF_TIME, "INSUF_TIME" }, + { MOD_UART_CLOCK, "MOD_UART_CLOCK" }, + { SLEEP_INFO, "SLEEP_INFO" }, + { MOD_TCXO_END, "MOD_TCXO_END" }, + { MOD_ENTER_TCXO, "MOD_ENTER_TCXO" }, + { NO_SLEEP_NEW, "NO_SLEEP_NEW" }, + { RPC_ROUTER_LOG_EVENT_UNKNOWN, "UNKNOWN" }, + { RPC_ROUTER_LOG_EVENT_MSG_READ, "MSG_READ" }, + { RPC_ROUTER_LOG_EVENT_MSG_WRITTEN, "MSG_WRITTEN" }, + { RPC_ROUTER_LOG_EVENT_MSG_CFM_REQ, "MSG_CFM_REQ" }, + { RPC_ROUTER_LOG_EVENT_MSG_CFM_SNT, "MSG_CFM_SNT" }, + { RPC_ROUTER_LOG_EVENT_MID_READ, "MID_READ" }, + { RPC_ROUTER_LOG_EVENT_MID_WRITTEN, "MID_WRITTEN" }, + { RPC_ROUTER_LOG_EVENT_MID_CFM_REQ, "MID_CFM_REQ" }, + +}; + +struct sym oncrpc_syms[] = { + { 0x30000000, "CM" }, + { 0x30000001, "DB" }, + { 0x30000002, "SND" }, + { 0x30000003, "WMS" }, + { 0x30000004, "PDSM" }, + { 0x30000005, "MISC_MODEM_APIS" }, + { 0x30000006, "MISC_APPS_APIS" }, + { 0x30000007, "JOYST" }, + { 0x30000008, "VJOY" }, + { 0x30000009, "JOYSTC" }, + { 0x3000000a, "ADSPRTOSATOM" }, + { 0x3000000b, "ADSPRTOSMTOA" }, + { 0x3000000c, "I2C" }, + { 0x3000000d, "TIME_REMOTE" }, + { 0x3000000e, "NV" }, + { 0x3000000f, "CLKRGM_SEC" }, + { 0x30000010, "RDEVMAP" }, + { 0x30000011, "FS_RAPI" }, + { 0x30000012, "PBMLIB" }, + { 0x30000013, "AUDMGR" }, + { 0x30000014, "MVS" }, + { 0x30000015, "DOG_KEEPALIVE" }, + { 0x30000016, "GSDI_EXP" }, + { 0x30000017, "AUTH" }, + { 0x30000018, "NVRUIMI" }, + { 0x30000019, "MMGSDILIB" }, + { 0x3000001a, "CHARGER" }, + { 0x3000001b, "UIM" }, + { 0x3000001C, "ONCRPCTEST" }, + { 0x3000001d, "PDSM_ATL" }, + { 0x3000001e, "FS_XMOUNT" }, + { 0x3000001f, "SECUTIL " }, + { 0x30000020, "MCCMEID" }, + { 0x30000021, "PM_STROBE_FLASH" }, + { 0x30000022, "DS707_EXTIF" }, + { 0x30000023, "SMD BRIDGE_MODEM" }, + { 0x30000024, "SMD PORT_MGR" }, + { 0x30000025, "BUS_PERF" }, + { 0x30000026, "BUS_MON" }, + { 0x30000027, "MC" }, + { 0x30000028, "MCCAP" }, + { 0x30000029, "MCCDMA" }, + { 0x3000002a, "MCCDS" }, + { 0x3000002b, "MCCSCH" }, + { 0x3000002c, "MCCSRID" }, + { 0x3000002d, "SNM" }, + { 0x3000002e, "MCCSYOBJ" }, + { 0x3000002f, "DS707_APIS" }, + { 0x30000030, "DS_MP_SHIM_APPS_ASYNC" }, + { 0x30000031, "DSRLP_APIS" }, + { 0x30000032, "RLP_APIS" }, + { 0x30000033, "DS_MP_SHIM_MODEM" }, + { 0x30000034, "DSHDR_APIS" }, + { 0x30000035, "DSHDR_MDM_APIS" }, + { 0x30000036, "DS_MP_SHIM_APPS" }, + { 0x30000037, "HDRMC_APIS" }, + { 0x30000038, "SMD_BRIDGE_MTOA" }, + { 0x30000039, "SMD_BRIDGE_ATOM" }, + { 0x3000003a, "DPMAPP_OTG" }, + { 0x3000003b, "DIAG" }, + { 0x3000003c, "GSTK_EXP" }, + { 0x3000003d, "DSBC_MDM_APIS" }, + { 0x3000003e, "HDRMRLP_MDM_APIS" }, + { 0x3000003f, "HDRMRLP_APPS_APIS" }, + { 0x30000040, "HDRMC_MRLP_APIS" }, + { 0x30000041, "PDCOMM_APP_API" }, + { 0x30000042, "DSAT_APIS" }, + { 0x30000043, "MISC_RF_APIS" }, + { 0x30000044, "CMIPAPP" }, + { 0x30000045, "DSMP_UMTS_MODEM_APIS" }, + { 0x30000046, "DSMP_UMTS_APPS_APIS" }, + { 0x30000047, "DSUCSDMPSHIM" }, + { 0x30000048, "TIME_REMOTE_ATOM" }, + { 0x3000004a, "SD" }, + { 0x3000004b, "MMOC" }, + { 0x3000004c, "WLAN_ADP_FTM" }, + { 0x3000004d, "WLAN_CP_CM" }, + { 0x3000004e, "FTM_WLAN" }, + { 0x3000004f, "SDCC_CPRM" }, + { 0x30000050, "CPRMINTERFACE" }, + { 0x30000051, "DATA_ON_MODEM_MTOA_APIS" }, + { 0x30000052, "DATA_ON_APPS_ATOM_APIS" }, + { 0x30000053, "MISC_MODEM_APIS_NONWINMOB" }, + { 0x30000054, "MISC_APPS_APIS_NONWINMOB" }, + { 0x30000055, "PMEM_REMOTE" }, + { 0x30000056, "TCXOMGR" }, + { 0x30000057, "DSUCSDAPPIF_APIS" }, + { 0x30000058, "BT" }, + { 0x30000059, "PD_COMMS_API" }, + { 0x3000005a, "PD_COMMS_CLIENT_API" }, + { 0x3000005b, "PDAPI" }, + { 0x3000005c, "LSA_SUPL_DSM" }, + { 0x3000005d, "TIME_REMOTE_MTOA" }, + { 0x3000005e, "FTM_BT" }, + { 0X3000005f, "DSUCSDAPPIF_APIS" }, + { 0X30000060, "PMAPP_GEN" }, + { 0X30000061, "PM_LIB" }, + { 0X30000062, "KEYPAD" }, + { 0X30000063, "HSU_APP_APIS" }, + { 0X30000064, "HSU_MDM_APIS" }, + { 0X30000065, "ADIE_ADC_REMOTE_ATOM " }, + { 0X30000066, "TLMM_REMOTE_ATOM" }, + { 0X30000067, "UI_CALLCTRL" }, + { 0X30000068, "UIUTILS" }, + { 0X30000069, "PRL" }, + { 0X3000006a, "HW" }, + { 0X3000006b, "OEM_RAPI" }, + { 0X3000006c, "WMSPM" }, + { 0X3000006d, "BTPF" }, + { 0X3000006e, "CLKRGM_SYNC_EVENT" }, + { 0X3000006f, "USB_APPS_RPC" }, + { 0X30000070, "USB_MODEM_RPC" }, + { 0X30000071, "ADC" }, + { 0X30000072, "CAMERAREMOTED" }, + { 0X30000073, "SECAPIREMOTED" }, + { 0X30000074, "DSATAPI" }, + { 0X30000075, "CLKCTL_RPC" }, + { 0X30000076, "BREWAPPCOORD" }, + { 0X30000077, "ALTENVSHELL" }, + { 0X30000078, "WLAN_TRP_UTILS" }, + { 0X30000079, "GPIO_RPC" }, + { 0X3000007a, "PING_RPC" }, + { 0X3000007b, "DSC_DCM_API" }, + { 0X3000007c, "L1_DS" }, + { 0X3000007d, "QCHATPK_APIS" }, + { 0X3000007e, "GPS_API" }, + { 0X3000007f, "OSS_RRCASN_REMOTE" }, + { 0X30000080, "PMAPP_OTG_REMOTE" }, + { 0X30000081, "PING_MDM_RPC" }, + { 0X30000082, "PING_KERNEL_RPC" }, + { 0X30000083, "TIMETICK" }, + { 0X30000084, "WM_BTHCI_FTM " }, + { 0X30000085, "WM_BT_PF" }, + { 0X30000086, "IPA_IPC_APIS" }, + { 0X30000087, "UKCC_IPC_APIS" }, + { 0X30000088, "CMIPSMS " }, + { 0X30000089, "VBATT_REMOTE" }, + { 0X3000008a, "MFPAL" }, + { 0X3000008b, "DSUMTSPDPREG" }, + { 0X3000fe00, "RESTART_DAEMON NUMBER 0" }, + { 0X3000fe01, "RESTART_DAEMON NUMBER 1" }, + { 0X3000feff, "RESTART_DAEMON NUMBER 255" }, + { 0X3000fffe, "BACKWARDS_COMPATIBILITY_IN_RPC_CLNT_LOOKUP" }, + { 0X3000ffff, "RPC_ROUTER_SERVER_PROGRAM" }, + { 0x31000000, "CM CB" }, + { 0x31000001, "DB CB" }, + { 0x31000002, "SND CB" }, + { 0x31000003, "WMS CB" }, + { 0x31000004, "PDSM CB" }, + { 0x31000005, "MISC_MODEM_APIS CB" }, + { 0x31000006, "MISC_APPS_APIS CB" }, + { 0x31000007, "JOYST CB" }, + { 0x31000008, "VJOY CB" }, + { 0x31000009, "JOYSTC CB" }, + { 0x3100000a, "ADSPRTOSATOM CB" }, + { 0x3100000b, "ADSPRTOSMTOA CB" }, + { 0x3100000c, "I2C CB" }, + { 0x3100000d, "TIME_REMOTE CB" }, + { 0x3100000e, "NV CB" }, + { 0x3100000f, "CLKRGM_SEC CB" }, + { 0x31000010, "RDEVMAP CB" }, + { 0x31000011, "FS_RAPI CB" }, + { 0x31000012, "PBMLIB CB" }, + { 0x31000013, "AUDMGR CB" }, + { 0x31000014, "MVS CB" }, + { 0x31000015, "DOG_KEEPALIVE CB" }, + { 0x31000016, "GSDI_EXP CB" }, + { 0x31000017, "AUTH CB" }, + { 0x31000018, "NVRUIMI CB" }, + { 0x31000019, "MMGSDILIB CB" }, + { 0x3100001a, "CHARGER CB" }, + { 0x3100001b, "UIM CB" }, + { 0x3100001C, "ONCRPCTEST CB" }, + { 0x3100001d, "PDSM_ATL CB" }, + { 0x3100001e, "FS_XMOUNT CB" }, + { 0x3100001f, "SECUTIL CB" }, + { 0x31000020, "MCCMEID" }, + { 0x31000021, "PM_STROBE_FLASH CB" }, + { 0x31000022, "DS707_EXTIF CB" }, + { 0x31000023, "SMD BRIDGE_MODEM CB" }, + { 0x31000024, "SMD PORT_MGR CB" }, + { 0x31000025, "BUS_PERF CB" }, + { 0x31000026, "BUS_MON CB" }, + { 0x31000027, "MC CB" }, + { 0x31000028, "MCCAP CB" }, + { 0x31000029, "MCCDMA CB" }, + { 0x3100002a, "MCCDS CB" }, + { 0x3100002b, "MCCSCH CB" }, + { 0x3100002c, "MCCSRID CB" }, + { 0x3100002d, "SNM CB" }, + { 0x3100002e, "MCCSYOBJ CB" }, + { 0x3100002f, "DS707_APIS CB" }, + { 0x31000030, "DS_MP_SHIM_APPS_ASYNC CB" }, + { 0x31000031, "DSRLP_APIS CB" }, + { 0x31000032, "RLP_APIS CB" }, + { 0x31000033, "DS_MP_SHIM_MODEM CB" }, + { 0x31000034, "DSHDR_APIS CB" }, + { 0x31000035, "DSHDR_MDM_APIS CB" }, + { 0x31000036, "DS_MP_SHIM_APPS CB" }, + { 0x31000037, "HDRMC_APIS CB" }, + { 0x31000038, "SMD_BRIDGE_MTOA CB" }, + { 0x31000039, "SMD_BRIDGE_ATOM CB" }, + { 0x3100003a, "DPMAPP_OTG CB" }, + { 0x3100003b, "DIAG CB" }, + { 0x3100003c, "GSTK_EXP CB" }, + { 0x3100003d, "DSBC_MDM_APIS CB" }, + { 0x3100003e, "HDRMRLP_MDM_APIS CB" }, + { 0x3100003f, "HDRMRLP_APPS_APIS CB" }, + { 0x31000040, "HDRMC_MRLP_APIS CB" }, + { 0x31000041, "PDCOMM_APP_API CB" }, + { 0x31000042, "DSAT_APIS CB" }, + { 0x31000043, "MISC_RF_APIS CB" }, + { 0x31000044, "CMIPAPP CB" }, + { 0x31000045, "DSMP_UMTS_MODEM_APIS CB" }, + { 0x31000046, "DSMP_UMTS_APPS_APIS CB" }, + { 0x31000047, "DSUCSDMPSHIM CB" }, + { 0x31000048, "TIME_REMOTE_ATOM CB" }, + { 0x3100004a, "SD CB" }, + { 0x3100004b, "MMOC CB" }, + { 0x3100004c, "WLAN_ADP_FTM CB" }, + { 0x3100004d, "WLAN_CP_CM CB" }, + { 0x3100004e, "FTM_WLAN CB" }, + { 0x3100004f, "SDCC_CPRM CB" }, + { 0x31000050, "CPRMINTERFACE CB" }, + { 0x31000051, "DATA_ON_MODEM_MTOA_APIS CB" }, + { 0x31000052, "DATA_ON_APPS_ATOM_APIS CB" }, + { 0x31000053, "MISC_APIS_NONWINMOB CB" }, + { 0x31000054, "MISC_APPS_APIS_NONWINMOB CB" }, + { 0x31000055, "PMEM_REMOTE CB" }, + { 0x31000056, "TCXOMGR CB" }, + { 0x31000057, "DSUCSDAPPIF_APIS CB" }, + { 0x31000058, "BT CB" }, + { 0x31000059, "PD_COMMS_API CB" }, + { 0x3100005a, "PD_COMMS_CLIENT_API CB" }, + { 0x3100005b, "PDAPI CB" }, + { 0x3100005c, "LSA_SUPL_DSM CB" }, + { 0x3100005d, "TIME_REMOTE_MTOA CB" }, + { 0x3100005e, "FTM_BT CB" }, + { 0X3100005f, "DSUCSDAPPIF_APIS CB" }, + { 0X31000060, "PMAPP_GEN CB" }, + { 0X31000061, "PM_LIB CB" }, + { 0X31000062, "KEYPAD CB" }, + { 0X31000063, "HSU_APP_APIS CB" }, + { 0X31000064, "HSU_MDM_APIS CB" }, + { 0X31000065, "ADIE_ADC_REMOTE_ATOM CB" }, + { 0X31000066, "TLMM_REMOTE_ATOM CB" }, + { 0X31000067, "UI_CALLCTRL CB" }, + { 0X31000068, "UIUTILS CB" }, + { 0X31000069, "PRL CB" }, + { 0X3100006a, "HW CB" }, + { 0X3100006b, "OEM_RAPI CB" }, + { 0X3100006c, "WMSPM CB" }, + { 0X3100006d, "BTPF CB" }, + { 0X3100006e, "CLKRGM_SYNC_EVENT CB" }, + { 0X3100006f, "USB_APPS_RPC CB" }, + { 0X31000070, "USB_MODEM_RPC CB" }, + { 0X31000071, "ADC CB" }, + { 0X31000072, "CAMERAREMOTED CB" }, + { 0X31000073, "SECAPIREMOTED CB" }, + { 0X31000074, "DSATAPI CB" }, + { 0X31000075, "CLKCTL_RPC CB" }, + { 0X31000076, "BREWAPPCOORD CB" }, + { 0X31000077, "ALTENVSHELL CB" }, + { 0X31000078, "WLAN_TRP_UTILS CB" }, + { 0X31000079, "GPIO_RPC CB" }, + { 0X3100007a, "PING_RPC CB" }, + { 0X3100007b, "DSC_DCM_API CB" }, + { 0X3100007c, "L1_DS CB" }, + { 0X3100007d, "QCHATPK_APIS CB" }, + { 0X3100007e, "GPS_API CB" }, + { 0X3100007f, "OSS_RRCASN_REMOTE CB" }, + { 0X31000080, "PMAPP_OTG_REMOTE CB" }, + { 0X31000081, "PING_MDM_RPC CB" }, + { 0X31000082, "PING_KERNEL_RPC CB" }, + { 0X31000083, "TIMETICK CB" }, + { 0X31000084, "WM_BTHCI_FTM CB" }, + { 0X31000085, "WM_BT_PF CB" }, + { 0X31000086, "IPA_IPC_APIS CB" }, + { 0X31000087, "UKCC_IPC_APIS CB" }, + { 0X31000088, "CMIPSMS CB" }, + { 0X31000089, "VBATT_REMOTE CB" }, + { 0X3100008a, "MFPAL CB" }, + { 0X3100008b, "DSUMTSPDPREG CB" }, + { 0X3100fe00, "RESTART_DAEMON NUMBER 0 CB" }, + { 0X3100fe01, "RESTART_DAEMON NUMBER 1 CB" }, + { 0X3100feff, "RESTART_DAEMON NUMBER 255 CB" }, + { 0X3100fffe, "BACKWARDS_COMPATIBILITY_IN_RPC_CLNT_LOOKUP CB" }, + { 0X3100ffff, "RPC_ROUTER_SERVER_PROGRAM CB" }, +}; + +struct sym wakeup_syms[] = { + { 0x00000040, "OTHER" }, + { 0x00000020, "RESET" }, + { 0x00000010, "ALARM" }, + { 0x00000008, "TIMER" }, + { 0x00000004, "GPIO" }, + { 0x00000002, "INT" }, + { 0x00000001, "RPC" }, + { 0x00000000, "NONE" }, +}; + +struct sym wakeup_int_syms[] = { + { 0, "MDDI_EXT" }, + { 1, "MDDI_PRI" }, + { 2, "MDDI_CLIENT"}, + { 3, "USB_OTG" }, + { 4, "I2CC" }, + { 5, "SDC1_0" }, + { 6, "SDC1_1" }, + { 7, "SDC2_0" }, + { 8, "SDC2_1" }, + { 9, "ADSP_A9A11" }, + { 10, "UART1" }, + { 11, "UART2" }, + { 12, "UART3" }, + { 13, "DP_RX_DATA" }, + { 14, "DP_RX_DATA2" }, + { 15, "DP_RX_DATA3" }, + { 16, "DM_UART" }, + { 17, "DM_DP_RX_DATA" }, + { 18, "KEYSENSE" }, + { 19, "HSSD" }, + { 20, "NAND_WR_ER_DONE" }, + { 21, "NAND_OP_DONE" }, + { 22, "TCHSCRN1" }, + { 23, "TCHSCRN2" }, + { 24, "TCHSCRN_SSBI" }, + { 25, "USB_HS" }, + { 26, "UART2_DM_RX" }, + { 27, "UART2_DM" }, + { 28, "SDC4_1" }, + { 29, "SDC4_0" }, + { 30, "SDC3_1" }, + { 31, "SDC3_0" }, +}; + +struct sym smsm_syms[] = { + { 0x80000000, "UN" }, + { 0x7F000000, "ERR" }, + { 0x00800000, "SMLP" }, + { 0x00400000, "ADWN" }, + { 0x00200000, "PWRS" }, + { 0x00100000, "DWLD" }, + { 0x00080000, "SRBT" }, + { 0x00040000, "SDWN" }, + { 0x00020000, "ARBT" }, + { 0x00010000, "REL" }, + { 0x00008000, "SLE" }, + { 0x00004000, "SLP" }, + { 0x00002000, "WFPI" }, + { 0x00001000, "EEX" }, + { 0x00000800, "TIN" }, + { 0x00000400, "TWT" }, + { 0x00000200, "PWRC" }, + { 0x00000100, "RUN" }, + { 0x00000080, "SA" }, + { 0x00000040, "RES" }, + { 0x00000020, "RIN" }, + { 0x00000010, "RWT" }, + { 0x00000008, "SIN" }, + { 0x00000004, "SWT" }, + { 0x00000002, "OE" }, + { 0x00000001, "I" }, +}; + +/* never reorder */ +struct sym voter_d2_syms[] = { + { 0x00000001, NULL }, + { 0x00000002, NULL }, + { 0x00000004, NULL }, + { 0x00000008, NULL }, + { 0x00000010, NULL }, + { 0x00000020, NULL }, + { 0x00000040, NULL }, + { 0x00000080, NULL }, + { 0x00000100, NULL }, + { 0x00000200, NULL }, + { 0x00000400, NULL }, + { 0x00000800, NULL }, + { 0x00001000, NULL }, + { 0x00002000, NULL }, + { 0x00004000, NULL }, + { 0x00008000, NULL }, + { 0x00010000, NULL }, + { 0x00020000, NULL }, + { 0x00040000, NULL }, + { 0x00080000, NULL }, + { 0x00100000, NULL }, + { 0x00200000, NULL }, + { 0x00400000, NULL }, + { 0x00800000, NULL }, + { 0x01000000, NULL }, + { 0x02000000, NULL }, + { 0x04000000, NULL }, + { 0x08000000, NULL }, + { 0x10000000, NULL }, + { 0x20000000, NULL }, + { 0x40000000, NULL }, + { 0x80000000, NULL }, +}; + +/* never reorder */ +struct sym voter_d3_syms[] = { + { 0x00000001, NULL }, + { 0x00000002, NULL }, + { 0x00000004, NULL }, + { 0x00000008, NULL }, + { 0x00000010, NULL }, + { 0x00000020, NULL }, + { 0x00000040, NULL }, + { 0x00000080, NULL }, + { 0x00000100, NULL }, + { 0x00000200, NULL }, + { 0x00000400, NULL }, + { 0x00000800, NULL }, + { 0x00001000, NULL }, + { 0x00002000, NULL }, + { 0x00004000, NULL }, + { 0x00008000, NULL }, + { 0x00010000, NULL }, + { 0x00020000, NULL }, + { 0x00040000, NULL }, + { 0x00080000, NULL }, + { 0x00100000, NULL }, + { 0x00200000, NULL }, + { 0x00400000, NULL }, + { 0x00800000, NULL }, + { 0x01000000, NULL }, + { 0x02000000, NULL }, + { 0x04000000, NULL }, + { 0x08000000, NULL }, + { 0x10000000, NULL }, + { 0x20000000, NULL }, + { 0x40000000, NULL }, + { 0x80000000, NULL }, +}; + +struct sym dem_state_master_syms[] = { + { 0, "INIT" }, + { 1, "RUN" }, + { 2, "SLEEP_WAIT" }, + { 3, "SLEEP_CONFIRMED" }, + { 4, "SLEEP_EXIT" }, + { 5, "RSA" }, + { 6, "EARLY_EXIT" }, + { 7, "RSA_DELAYED" }, + { 8, "RSA_CHECK_INTS" }, + { 9, "RSA_CONFIRMED" }, + { 10, "RSA_WAKING" }, + { 11, "RSA_RESTORE" }, + { 12, "RESET" }, +}; + +struct sym dem_state_slave_syms[] = { + { 0, "INIT" }, + { 1, "RUN" }, + { 2, "SLEEP_WAIT" }, + { 3, "SLEEP_EXIT" }, + { 4, "SLEEP_RUN_PENDING" }, + { 5, "POWER_COLLAPSE" }, + { 6, "CHECK_INTERRUPTS" }, + { 7, "SWFI" }, + { 8, "WFPI" }, + { 9, "EARLY_EXIT" }, + { 10, "RESET_RECOVER" }, + { 11, "RESET_ACKNOWLEDGE" }, + { 12, "ERROR" }, +}; + +struct sym smsm_entry_type_syms[] = { + { 0, "SMSM_APPS_STATE" }, + { 1, "SMSM_MODEM_STATE" }, + { 2, "SMSM_Q6_STATE" }, + { 3, "SMSM_APPS_DEM" }, + { 4, "SMSM_MODEM_DEM" }, + { 5, "SMSM_Q6_DEM" }, + { 6, "SMSM_POWER_MASTER_DEM" }, + { 7, "SMSM_TIME_MASTER_DEM" }, +}; + +struct sym smsm_state_syms[] = { + { 0x00000001, "INIT" }, + { 0x00000002, "OSENTERED" }, + { 0x00000004, "SMDWAIT" }, + { 0x00000008, "SMDINIT" }, + { 0x00000010, "RPCWAIT" }, + { 0x00000020, "RPCINIT" }, + { 0x00000040, "RESET" }, + { 0x00000080, "RSA" }, + { 0x00000100, "RUN" }, + { 0x00000200, "PWRC" }, + { 0x00000400, "TIMEWAIT" }, + { 0x00000800, "TIMEINIT" }, + { 0x00001000, "PWRC_EARLY_EXIT" }, + { 0x00002000, "WFPI" }, + { 0x00004000, "SLEEP" }, + { 0x00008000, "SLEEPEXIT" }, + { 0x00010000, "OEMSBL_RELEASE" }, + { 0x00020000, "APPS_REBOOT" }, + { 0x00040000, "SYSTEM_POWER_DOWN" }, + { 0x00080000, "SYSTEM_REBOOT" }, + { 0x00100000, "SYSTEM_DOWNLOAD" }, + { 0x00200000, "PWRC_SUSPEND" }, + { 0x00400000, "APPS_SHUTDOWN" }, + { 0x00800000, "SMD_LOOPBACK" }, + { 0x01000000, "RUN_QUIET" }, + { 0x02000000, "MODEM_WAIT" }, + { 0x04000000, "MODEM_BREAK" }, + { 0x08000000, "MODEM_CONTINUE" }, + { 0x80000000, "UNKNOWN" }, +}; + +#define ID_SYM 0 +#define BASE_SYM 1 +#define EVENT_SYM 2 +#define ONCRPC_SYM 3 +#define WAKEUP_SYM 4 +#define WAKEUP_INT_SYM 5 +#define SMSM_SYM 6 +#define VOTER_D2_SYM 7 +#define VOTER_D3_SYM 8 +#define DEM_STATE_MASTER_SYM 9 +#define DEM_STATE_SLAVE_SYM 10 +#define SMSM_ENTRY_TYPE_SYM 11 +#define SMSM_STATE_SYM 12 + +static struct sym_tbl { + struct sym *data; + int size; + struct hlist_head hlist[HSIZE]; +} tbl[] = { + { id_syms, ARRAY_SIZE(id_syms) }, + { base_syms, ARRAY_SIZE(base_syms) }, + { event_syms, ARRAY_SIZE(event_syms) }, + { oncrpc_syms, ARRAY_SIZE(oncrpc_syms) }, + { wakeup_syms, ARRAY_SIZE(wakeup_syms) }, + { wakeup_int_syms, ARRAY_SIZE(wakeup_int_syms) }, + { smsm_syms, ARRAY_SIZE(smsm_syms) }, + { voter_d2_syms, ARRAY_SIZE(voter_d2_syms) }, + { voter_d3_syms, ARRAY_SIZE(voter_d3_syms) }, + { dem_state_master_syms, ARRAY_SIZE(dem_state_master_syms) }, + { dem_state_slave_syms, ARRAY_SIZE(dem_state_slave_syms) }, + { smsm_entry_type_syms, ARRAY_SIZE(smsm_entry_type_syms) }, + { smsm_state_syms, ARRAY_SIZE(smsm_state_syms) }, +}; + +static void find_voters(void) +{ + void *x, *next; + unsigned size; + int i = 0, j = 0; + + x = smem_get_entry(SMEM_SLEEP_STATIC, &size); + next = x; + while (next && (next < (x + size)) && + ((i + j) < (ARRAY_SIZE(voter_d3_syms) + + ARRAY_SIZE(voter_d2_syms)))) { + + if (i < ARRAY_SIZE(voter_d3_syms)) { + voter_d3_syms[i].str = (char *) next; + i++; + } else if (i >= ARRAY_SIZE(voter_d3_syms) && + j < ARRAY_SIZE(voter_d2_syms)) { + voter_d2_syms[j].str = (char *) next; + j++; + } + + next += 9; + } +} + +#define hash(val) (val % HSIZE) + +static void init_syms(void) +{ + int i; + int j; + + for (i = 0; i < ARRAY_SIZE(tbl); ++i) + for (j = 0; j < HSIZE; ++j) + INIT_HLIST_HEAD(&tbl[i].hlist[j]); + + for (i = 0; i < ARRAY_SIZE(tbl); ++i) + for (j = 0; j < tbl[i].size; ++j) { + INIT_HLIST_NODE(&tbl[i].data[j].node); + hlist_add_head(&tbl[i].data[j].node, + &tbl[i].hlist[hash(tbl[i].data[j].val)]); + } +} + +static char *find_sym(uint32_t id, uint32_t val) +{ + struct hlist_node *n; + struct sym *s; + + hlist_for_each(n, &tbl[id].hlist[hash(val)]) { + s = hlist_entry(n, struct sym, node); + if (s->val == val) + return s->str; + } + + return 0; +} + +#else +static void init_syms(void) {} +#endif + +static inline unsigned int read_timestamp(void) +{ + unsigned int tick; + + do { + tick = readl(TIMESTAMP_ADDR); + } while (tick != (tick = readl(TIMESTAMP_ADDR))); + + return tick; +} + +static void smem_log_event_from_user(struct smem_log_inst *inst, + const char __user *buf, int size, int num) +{ + uint32_t idx; + uint32_t next_idx; + unsigned long flags; + uint32_t identifier = 0; + uint32_t timetick = 0; + int first = 1; + int ret; + + remote_spin_lock_irqsave(inst->cur_remote_spinlock, flags); + + while (num--) { + idx = *inst->smem_log_cur_idx; + + if (idx < inst->smem_log_cur_num) { + ret = copy_from_user(&inst->smem_log_cur_events[idx], + buf, size); + if (ret) { + printk("ERROR %s:%i tried to write " + "%i got ret %i", + __func__, __LINE__, + size, size - ret); + goto out; + } + + if (first) { + identifier = + inst->smem_log_cur_events[idx]. + identifier; + timetick = read_timestamp(); + first = 0; + } else { + identifier |= SMEM_LOG_CONT; + } + inst->smem_log_cur_events[idx].identifier = + identifier; + inst->smem_log_cur_events[idx].timetick = + timetick; + } + + next_idx = idx + 1; + if (next_idx >= inst->smem_log_cur_num) + next_idx = 0; + *inst->smem_log_cur_idx = next_idx; + + buf += sizeof(struct smem_log_item); + } + + out: + remote_spin_unlock_irqrestore(inst->cur_remote_spinlock, flags); +} + +static void _smem_log_event( + struct smem_log_item __iomem *events, + uint32_t __iomem *_idx, + remote_spinlock_t *lock, + int num, + uint32_t id, uint32_t data1, uint32_t data2, + uint32_t data3) +{ + struct smem_log_item item; + uint32_t idx; + uint32_t next_idx; + unsigned long flags; + + item.timetick = read_timestamp(); + item.identifier = id; + item.data1 = data1; + item.data2 = data2; + item.data3 = data3; + + remote_spin_lock_irqsave(lock, flags); + + idx = *_idx; + + if (idx < num) { + memcpy(&events[idx], + &item, sizeof(item)); + } + + next_idx = idx + 1; + if (next_idx >= num) + next_idx = 0; + *_idx = next_idx; + + remote_spin_unlock_irqrestore(lock, flags); +} + +static void _smem_log_event6( + struct smem_log_item __iomem *events, + uint32_t __iomem *_idx, + remote_spinlock_t *lock, + int num, + uint32_t id, uint32_t data1, uint32_t data2, + uint32_t data3, uint32_t data4, uint32_t data5, + uint32_t data6) +{ + struct smem_log_item item[2]; + uint32_t idx; + uint32_t next_idx; + unsigned long flags; + + item[0].timetick = read_timestamp(); + item[0].identifier = id; + item[0].data1 = data1; + item[0].data2 = data2; + item[0].data3 = data3; + item[1].identifier = item[0].identifier; + item[1].timetick = item[0].timetick; + item[1].data1 = data4; + item[1].data2 = data5; + item[1].data3 = data6; + + remote_spin_lock_irqsave(lock, flags); + + idx = *_idx; + + if (idx < (num-1)) { + memcpy(&events[idx], + &item, sizeof(item)); + } + + next_idx = idx + 2; + if (next_idx >= num) + next_idx = 0; + *_idx = next_idx; + + remote_spin_unlock_irqrestore(lock, flags); +} + +void smem_log_event(uint32_t id, uint32_t data1, uint32_t data2, + uint32_t data3) +{ + _smem_log_event(smem_log_events, smem_log_idx, + &remote_spinlock, SMEM_LOG_NUM_ENTRIES, + id, data1, data2, data3); +} + +void smem_log_event6(uint32_t id, uint32_t data1, uint32_t data2, + uint32_t data3, uint32_t data4, uint32_t data5, + uint32_t data6) +{ + _smem_log_event6(smem_log_events, smem_log_idx, + &remote_spinlock, SMEM_LOG_NUM_ENTRIES, + id, data1, data2, data3, data4, data5, data6); +} + +void smem_log_event_to_static(uint32_t id, uint32_t data1, uint32_t data2, + uint32_t data3) +{ + _smem_log_event(smem_log_static_events, smem_log_static_idx, + &remote_spinlock_static, SMEM_LOG_NUM_STATIC_ENTRIES, + id, data1, data2, data3); +} + +void smem_log_event6_to_static(uint32_t id, uint32_t data1, uint32_t data2, + uint32_t data3, uint32_t data4, uint32_t data5, + uint32_t data6) +{ + _smem_log_event6(smem_log_static_events, smem_log_static_idx, + &remote_spinlock_static, SMEM_LOG_NUM_STATIC_ENTRIES, + id, data1, data2, data3, data4, data5, data6); +} + +static int _smem_log_init(void) +{ + smem_log_events = + (struct smem_log_item *)smem_alloc(SMEM_SMEM_LOG_EVENTS, + SMEM_LOG_EVENTS_SIZE); + smem_log_idx = (uint32_t *)smem_alloc(SMEM_SMEM_LOG_IDX, + sizeof(uint32_t)); + if (!smem_log_events || !smem_log_idx) { + printk(KERN_INFO "smem_log_init: no log or log_idx allocated, " + "smem_log disabled"); + return -EIO; + } + + smem_log_static_events = + (struct smem_log_item *) + smem_alloc(SMEM_SMEM_STATIC_LOG_EVENTS, + SMEM_STATIC_LOG_EVENTS_SIZE); + smem_log_static_idx = (uint32_t *)smem_alloc(SMEM_SMEM_STATIC_LOG_IDX, + sizeof(uint32_t)); + if (!smem_log_static_events || !smem_log_static_idx) { + printk(KERN_INFO "smem_log_init: no static log or log_idx " + "allocated, smem_log disabled"); + return -EIO; + } + + remote_spin_lock_init(&remote_spinlock, SMEM_SPINLOCK_SMEM_LOG); + remote_spin_lock_init(&remote_spinlock_static, + SMEM_SPINLOCK_STATIC_LOG); + + init_syms(); + + return 0; +} + +static ssize_t smem_log_read_bin(struct file *fp, char __user *buf, + size_t count, loff_t *pos) +{ + int idx; + int orig_idx; + unsigned long flags; + int ret; + int tot_bytes = 0; + struct smem_log_inst *inst; + + inst = fp->private_data; + + remote_spin_lock_irqsave(inst->cur_remote_spinlock, flags); + + orig_idx = *inst->smem_log_cur_idx; + idx = orig_idx; + + while (1) { + idx--; + if (idx < 0) + idx = inst->smem_log_cur_num - 1; + if (idx == orig_idx) { + ret = tot_bytes; + break; + } + + if ((tot_bytes + sizeof(struct smem_log_item)) > count) { + ret = tot_bytes; + break; + } + + ret = copy_to_user(buf, &smem_log_events[idx], + sizeof(struct smem_log_item)); + if (ret) { + ret = -EIO; + break; + } + + tot_bytes += sizeof(struct smem_log_item); + + buf += sizeof(struct smem_log_item); + } + + remote_spin_unlock_irqrestore(inst->cur_remote_spinlock, flags); + + return ret; +} + +static ssize_t smem_log_read(struct file *fp, char __user *buf, + size_t count, loff_t *pos) +{ + char loc_buf[128]; + int i; + int idx; + int orig_idx; + unsigned long flags; + int ret; + int tot_bytes = 0; + struct smem_log_inst *inst; + + inst = fp->private_data; + + remote_spin_lock_irqsave(inst->cur_remote_spinlock, flags); + + orig_idx = *inst->smem_log_cur_idx; + idx = orig_idx; + + while (1) { + idx--; + if (idx < 0) + idx = inst->smem_log_cur_num - 1; + if (idx == orig_idx) { + ret = tot_bytes; + break; + } + + i = scnprintf(loc_buf, 128, + "0x%x 0x%x 0x%x 0x%x 0x%x\n", + smem_log_events[idx].identifier, + smem_log_events[idx].timetick, + smem_log_events[idx].data1, + smem_log_events[idx].data2, + smem_log_events[idx].data3); + if (i == 0) { + ret = -EIO; + break; + } + + if ((tot_bytes + i) > count) { + ret = tot_bytes; + break; + } + + tot_bytes += i; + + ret = copy_to_user(buf, loc_buf, i); + if (ret) { + ret = -EIO; + break; + } + + buf += i; + } + + remote_spin_unlock_irqrestore(inst->cur_remote_spinlock, flags); + + return ret; +} + +static ssize_t smem_log_write_bin(struct file *fp, const char __user *buf, + size_t count, loff_t *pos) +{ + if (count < sizeof(struct smem_log_item)) + return -EINVAL; + + smem_log_event_from_user(fp->private_data, buf, + sizeof(struct smem_log_item), + count / sizeof(struct smem_log_item)); + + return count; +} + +static ssize_t smem_log_write(struct file *fp, const char __user *buf, + size_t count, loff_t *pos) +{ + int ret; + const char delimiters[] = " ,;"; + char locbuf[256] = {0}; + uint32_t val[10]; + int vals = 0; + char *token; + char *running; + struct smem_log_inst *inst; + unsigned long res; + + inst = fp->private_data; + + if (count < 0) { + printk(KERN_ERR "ERROR: %s passed neg count = %i\n", + __func__, count); + return -EINVAL; + } + + count = count > 255 ? 255 : count; + + locbuf[count] = '\0'; + + ret = copy_from_user(locbuf, buf, count); + if (ret != 0) { + printk(KERN_ERR "ERROR: %s could not copy %i bytes\n", + __func__, ret); + return -EINVAL; + } + + D(KERN_ERR "%s: ", __func__); + D_DUMP_BUFFER("We got", len, locbuf); + + running = locbuf; + + token = strsep(&running, delimiters); + while (token && vals < ARRAY_SIZE(val)) { + if (*token != '\0') { + D(KERN_ERR "%s: ", __func__); + D_DUMP_BUFFER("", strlen(token), token); + ret = strict_strtoul(token, 0, &res); + if (ret) { + printk(KERN_ERR "ERROR: %s:%i got bad char " + "at strict_strtoul\n", + __func__, __LINE__-4); + return -EINVAL; + } + val[vals++] = res; + } + token = strsep(&running, delimiters); + } + + if (vals > 5) { + if (inst->smem_log_cur_events == smem_log_events) + smem_log_event6(val[0], val[2], val[3], val[4], + val[7], val[8], val[9]); + else if (inst->smem_log_cur_events == smem_log_static_events) + smem_log_event6_to_static(val[0], + val[2], val[3], val[4], + val[7], val[8], val[9]); + else + return -1; + } else { + if (inst->smem_log_cur_events == smem_log_events) + smem_log_event(val[0], val[2], val[3], val[4]); + else if (inst->smem_log_cur_events == smem_log_static_events) + smem_log_event_to_static(val[0], + val[2], val[3], val[4]); + else + return -1; + } + + return count; +} + +static int smem_log_open(struct inode *ip, struct file *fp) +{ + struct smem_log_inst *inst; + + inst = kzalloc(sizeof(struct smem_log_inst), GFP_KERNEL); + + if (IS_ERR(inst)) { + printk(KERN_ERR "ERROR:%s:%i:%s kmalloc() ENOMEM\n", + __FILE__, + __LINE__-5, + __func__); + return -ENOMEM; + } + + inst->smem_log_cur_idx = smem_log_idx; + inst->smem_log_cur_events = smem_log_events; + inst->smem_log_cur_num = SMEM_LOG_NUM_ENTRIES; + inst->cur_remote_spinlock = &remote_spinlock; + + fp->private_data = inst; + + return 0; +} + + +static int smem_log_release(struct inode *ip, struct file *fp) +{ + kfree(fp->private_data); + + return 0; +} + +static int smem_log_ioctl(struct inode *ip, struct file *fp, + unsigned int cmd, unsigned long arg); + +static const struct file_operations smem_log_fops = { + .owner = THIS_MODULE, + .read = smem_log_read, + .write = smem_log_write, + .open = smem_log_open, + .release = smem_log_release, + .ioctl = smem_log_ioctl, +}; + +static const struct file_operations smem_log_bin_fops = { + .owner = THIS_MODULE, + .read = smem_log_read_bin, + .write = smem_log_write_bin, + .open = smem_log_open, + .release = smem_log_release, + .ioctl = smem_log_ioctl, +}; + +static int smem_log_ioctl(struct inode *ip, struct file *fp, + unsigned int cmd, unsigned long arg) +{ + struct smem_log_inst *inst; + + inst = fp->private_data; + + switch (cmd) { + default: + return -ENOTTY; + + case SMIOC_SETMODE: + if (arg == SMIOC_TEXT) { + D("%s set text mode\n", __func__); + fp->f_op = &smem_log_fops; + } else if (arg == SMIOC_BINARY) { + D("%s set bin mode\n", __func__); + fp->f_op = &smem_log_bin_fops; + } else { + return -EINVAL; + } + break; + case SMIOC_SETLOG: + if (arg == SMIOC_LOG) { + inst->smem_log_cur_events = smem_log_events; + inst->smem_log_cur_idx = smem_log_idx; + inst->smem_log_cur_num = SMEM_LOG_NUM_ENTRIES; + inst->cur_remote_spinlock = &remote_spinlock; + } else if (arg == SMIOC_STATIC_LOG) { + inst->smem_log_cur_events = smem_log_static_events; + inst->smem_log_cur_idx = smem_log_static_idx; + inst->smem_log_cur_num = SMEM_LOG_NUM_STATIC_ENTRIES; + inst->cur_remote_spinlock = &remote_spinlock_static; + } else { + return -EINVAL; + } + break; + } + + return 0; +} + +static struct miscdevice smem_log_dev = { + .minor = MISC_DYNAMIC_MINOR, + .name = "smem_log", + .fops = &smem_log_fops, +}; + +#if defined(CONFIG_DEBUG_FS) + +static int debug_dump(char *buf, int max) +{ + unsigned int idx; + int orig_idx; + unsigned long flags; + int i = 0; + + remote_spin_lock_irqsave(&remote_spinlock, flags); + + orig_idx = *smem_log_idx; + idx = orig_idx; + + while (1) { + idx++; + if (idx > SMEM_LOG_NUM_ENTRIES - 1) + idx = 0; + if (idx == orig_idx) + break; + + if (idx < SMEM_LOG_NUM_ENTRIES) { + if (!smem_log_events[idx].identifier) + continue; + + i += scnprintf(buf + i, max - i, + "%08x %08x %08x %08x %08x\n", + smem_log_events[idx].identifier, + smem_log_events[idx].timetick, + smem_log_events[idx].data1, + smem_log_events[idx].data2, + smem_log_events[idx].data3); + } + } + + remote_spin_unlock_irqrestore(&remote_spinlock, flags); + + return i; +} + +static int debug_dump_sym(char *buf, int max) +{ + unsigned int idx; + int orig_idx; + unsigned long flags; + int i = 0; + + char *proc; + char *sub; + char *id; + char *sym = NULL; + + uint32_t data[3]; + + uint32_t proc_val = 0; + uint32_t sub_val = 0; + uint32_t id_val = 0; + uint32_t id_only_val = 0; + uint32_t data1 = 0; + uint32_t data2 = 0; + uint32_t data3 = 0; + + int k; + + find_voters(); /* need to call each time in case voters come and go */ + + i += scnprintf(buf + i, max - i, "Voters:\n"); + for (k = 0; k < ARRAY_SIZE(voter_d3_syms); ++k) + if (voter_d3_syms[k].str) + i += scnprintf(buf + i, max - i, "%s ", + voter_d3_syms[k].str); + for (k = 0; k < ARRAY_SIZE(voter_d2_syms); ++k) + if (voter_d2_syms[k].str) + i += scnprintf(buf + i, max - i, "%s ", + voter_d2_syms[k].str); + i += scnprintf(buf + i, max - i, "\n"); + + remote_spin_lock_irqsave(&remote_spinlock, flags); + + orig_idx = *smem_log_idx; + idx = orig_idx; + + while (1) { + idx++; + if (idx > SMEM_LOG_NUM_ENTRIES - 1) + idx = 0; + if (idx == orig_idx) { + i += scnprintf(buf + i, max - i, "\n"); + break; + } + if (idx < SMEM_LOG_NUM_ENTRIES) { + if (!smem_log_events[idx].identifier) + continue; + + proc_val = PROC & smem_log_events[idx].identifier; + sub_val = SUB & smem_log_events[idx].identifier; + id_val = (SUB | ID) & smem_log_events[idx].identifier; + id_only_val = ID & smem_log_events[idx].identifier; + data1 = smem_log_events[idx].data1; + data2 = smem_log_events[idx].data2; + data3 = smem_log_events[idx].data3; + + if (!(proc_val & SMEM_LOG_CONT)) { + i += scnprintf(buf + i, max - i, "\n"); + + proc = find_sym(ID_SYM, proc_val); + + if (proc) + i += scnprintf(buf + i, max - i, + "%4s: ", + proc); + else + i += scnprintf(buf + i, max - i, + "%04x: ", + PROC & + smem_log_events[idx]. + identifier); + + i += scnprintf(buf + i, max - i, + "%10u ", + smem_log_events[idx].timetick); + + sub = find_sym(BASE_SYM, sub_val); + + if (sub) + i += scnprintf(buf + i, max - i, + "%9s: ", + sub); + else + i += scnprintf(buf + i, max - i, + "%08x: ", + sub_val); + + id = find_sym(EVENT_SYM, id_val); + + if (id) + i += scnprintf(buf + i, max - i, + "%11s: ", + id); + else + i += scnprintf(buf + i, max - i, + "%08x: ", + id_only_val); + } + + if ((proc_val & SMEM_LOG_CONT) && + (id_val == ONCRPC_LOG_EVENT_STD_CALL || + id_val == ONCRPC_LOG_EVENT_STD_REPLY)) { + data[0] = data1; + data[1] = data2; + data[2] = data3; + i += scnprintf(buf + i, max - i, + " %.16s", + (char *) data); + } else if (proc_val & SMEM_LOG_CONT) { + i += scnprintf(buf + i, max - i, + " %08x %08x %08x", + data1, + data2, + data3); + } else if (id_val == ONCRPC_LOG_EVENT_STD_CALL) { + sym = find_sym(ONCRPC_SYM, data2); + + if (sym) + i += scnprintf(buf + i, max - i, + "xid:%4i %8s proc:%3i", + data1, + sym, + data3); + else + i += scnprintf(buf + i, max - i, + "xid:%4i %08x proc:%3i", + data1, + data2, + data3); +#if defined(CONFIG_MSM_N_WAY_SMSM) + } else if (id_val == DEM_STATE_CHANGE) { + if (data1 == 1) { + i += scnprintf(buf + i, + max - i, + "MASTER: "); + sym = find_sym(DEM_STATE_MASTER_SYM, + data2); + } else if (data1 == 0) { + i += scnprintf(buf + i, + max - i, + " SLAVE: "); + sym = find_sym(DEM_STATE_SLAVE_SYM, + data2); + } else { + i += scnprintf(buf + i, + max - i, + "%x: ", + data1); + sym = NULL; + } + if (sym) + i += scnprintf(buf + i, + max - i, + "from:%s ", + sym); + else + i += scnprintf(buf + i, + max - i, + "from:0x%x ", + data2); + + if (data1 == 1) + sym = find_sym(DEM_STATE_MASTER_SYM, + data3); + else if (data1 == 0) + sym = find_sym(DEM_STATE_SLAVE_SYM, + data3); + else + sym = NULL; + if (sym) + i += scnprintf(buf + i, + max - i, + "to:%s ", + sym); + else + i += scnprintf(buf + i, + max - i, + "to:0x%x ", + data3); + + } else if (id_val == DEM_STATE_MACHINE_ENTER) { + i += scnprintf(buf + i, + max - i, + "swfi:%i timer:%i manexit:%i", + data1, data2, data3); + + } else if (id_val == DEM_TIME_SYNC_REQUEST || + id_val == DEM_TIME_SYNC_POLL || + id_val == DEM_TIME_SYNC_INIT) { + sym = find_sym(SMSM_ENTRY_TYPE_SYM, + data1); + if (sym) + i += scnprintf(buf + i, + max - i, + "hostid:%s", + sym); + else + i += scnprintf(buf + i, + max - i, + "hostid:%x", + data1); + + } else if (id_val == DEM_TIME_SYNC_START || + id_val == DEM_TIME_SYNC_SEND_VALUE) { + unsigned mask = 0x1; + unsigned tmp = 0; + if (id_val == DEM_TIME_SYNC_START) + i += scnprintf(buf + i, + max - i, + "req:"); + else + i += scnprintf(buf + i, + max - i, + "pol:"); + while (mask) { + if (mask & data1) { + sym = find_sym( + SMSM_ENTRY_TYPE_SYM, + tmp); + if (sym) + i += scnprintf(buf + i, + max - i, + "%s ", + sym); + else + i += scnprintf(buf + i, + max - i, + "%i ", + tmp); + } + mask <<= 1; + tmp++; + } + if (id_val == DEM_TIME_SYNC_SEND_VALUE) + i += scnprintf(buf + i, + max - i, + "tick:%x", + data2); + } else if (id_val == DEM_SMSM_ISR) { + unsigned vals[] = {data2, data3}; + unsigned j; + unsigned mask; + unsigned tmp; + unsigned once; + sym = find_sym(SMSM_ENTRY_TYPE_SYM, + data1); + if (sym) + i += scnprintf(buf + i, + max - i, + "%s ", + sym); + else + i += scnprintf(buf + i, + max - i, + "%x ", + data1); + + for (j = 0; j < ARRAY_SIZE(vals); ++j) { + i += scnprintf(buf + i, max - i, "["); + mask = 0x80000000; + once = 0; + while (mask) { + tmp = vals[j] & mask; + mask >>= 1; + if (!tmp) + continue; + sym = find_sym(SMSM_STATE_SYM, + tmp); + + if (once) + i += scnprintf(buf + i, + max - i, + " "); + if (sym) + i += scnprintf(buf + i, + max - i, + "%s", + sym); + else + i += scnprintf(buf + i, + max - i, + "0x%x", + tmp); + once = 1; + } + i += scnprintf(buf + i, max - i, "] "); + } +#else + } else if (id_val == DEMAPPS_WAKEUP_REASON) { + unsigned mask = 0x80000000; + unsigned tmp = 0; + while (mask) { + tmp = data1 & mask; + mask >>= 1; + if (!tmp) + continue; + sym = find_sym(WAKEUP_SYM, tmp); + if (sym) + i += scnprintf(buf + i, + max - i, + "%s ", + sym); + else + i += scnprintf(buf + i, + max - i, + "%08x ", + tmp); + } + i += scnprintf(buf + i, max - i, + "%08x %08x", + data2, + data3); + } else if (id_val == DEMMOD_APPS_WAKEUP_INT) { + sym = find_sym(WAKEUP_INT_SYM, data1); + + if (sym) + i += scnprintf(buf + i, max - i, + "%s %08x %08x", + sym, + data2, + data3); + else + i += scnprintf(buf + i, max - i, + "%08x %08x %08x", + data1, + data2, + data3); + } else if (id_val == DEM_NO_SLEEP || + id_val == NO_SLEEP_NEW) { + unsigned vals[] = {data3, data2}; + unsigned j; + unsigned mask; + unsigned tmp; + unsigned once; + i += scnprintf(buf + i, max - i, "%08x ", + data1); + i += scnprintf(buf + i, max - i, "["); + once = 0; + for (j = 0; j < ARRAY_SIZE(vals); ++j) { + mask = 0x00000001; + while (mask) { + tmp = vals[j] & mask; + mask <<= 1; + if (!tmp) + continue; + if (j == 0) + sym = find_sym( + VOTER_D3_SYM, + tmp); + else + sym = find_sym( + VOTER_D2_SYM, + tmp); + + if (once) + i += scnprintf(buf + i, + max - i, + " "); + if (sym) + i += scnprintf(buf + i, + max - i, + "%s", + sym); + else + i += scnprintf(buf + i, + max - i, + "%08x", + tmp); + once = 1; + } + } + i += scnprintf(buf + i, max - i, "] "); +#endif + } else if (id_val == SMEM_LOG_EVENT_CB) { + unsigned vals[] = {data2, data3}; + unsigned j; + unsigned mask; + unsigned tmp; + unsigned once; + i += scnprintf(buf + i, max - i, "%08x ", + data1); + for (j = 0; j < ARRAY_SIZE(vals); ++j) { + i += scnprintf(buf + i, max - i, "["); + mask = 0x80000000; + once = 0; + while (mask) { + tmp = vals[j] & mask; + mask >>= 1; + if (!tmp) + continue; + sym = find_sym(SMSM_SYM, tmp); + + if (once) + i += scnprintf(buf + i, + max - i, + " "); + if (sym) + i += scnprintf(buf + i, + max - i, + "%s", + sym); + else + i += scnprintf(buf + i, + max - i, + "%08x", + tmp); + once = 1; + } + i += scnprintf(buf + i, max - i, "] "); + } + } else { + i += scnprintf(buf + i, max - i, + "%08x %08x %08x", + data1, + data2, + data3); + } + } + } + + remote_spin_unlock_irqrestore(&remote_spinlock, flags); + + return i; +} + +static int debug_dump_static(char *buf, int max) +{ + unsigned int idx; + int orig_idx; + unsigned long flags; + int i = 0; + + remote_spin_lock_irqsave(&remote_spinlock_static, flags); + + orig_idx = *smem_log_static_idx; + idx = orig_idx; + + while (1) { + idx++; + if (idx > SMEM_LOG_NUM_ENTRIES - 1) + idx = 0; + if (idx == orig_idx) + break; + + if (idx < SMEM_LOG_NUM_STATIC_ENTRIES) { + if (!smem_log_static_events[idx].identifier) + continue; + + i += scnprintf(buf + i, max - i, + "%08x %08x %08x %08x %08x\n", + smem_log_static_events[idx].identifier, + smem_log_static_events[idx].timetick, + smem_log_static_events[idx].data1, + smem_log_static_events[idx].data2, + smem_log_static_events[idx].data3); + } + } + + remote_spin_unlock_irqrestore(&remote_spinlock_static, flags); + + return i; +} + +#define SMEM_LOG_ITEM_PRINT_SIZE 160 + +#define SMEM_LOG_CUR_EVENTS_PRINT_SIZE \ +(SMEM_LOG_ITEM_PRINT_SIZE * SMEM_LOG_NUM_ENTRIES) + +static char debug_buffer[SMEM_LOG_CUR_EVENTS_PRINT_SIZE]; + +static ssize_t debug_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + int (*fill)(char *buf, int max) = file->private_data; + int bsize = fill(debug_buffer, SMEM_LOG_CUR_EVENTS_PRINT_SIZE); + return simple_read_from_buffer(buf, count, ppos, debug_buffer, + bsize); +} + +static int debug_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static const struct file_operations debug_ops = { + .read = debug_read, + .open = debug_open, +}; + +static void debug_create(const char *name, mode_t mode, + struct dentry *dent, + int (*fill)(char *buf, int max)) +{ + debugfs_create_file(name, mode, dent, fill, &debug_ops); +} + +static void smem_log_debugfs_init(void) +{ + struct dentry *dent; + + dent = debugfs_create_dir("smem_log", 0); + if (IS_ERR(dent)) + return; + + debug_create("dump", 0444, dent, debug_dump); + debug_create("dump_sym", 0444, dent, debug_dump_sym); + debug_create("dump_static", 0444, dent, debug_dump_static); +} +#else +static void smem_log_debugfs_init(void) {} +#endif + +static int __init smem_log_init(void) +{ + int ret; + + ret = _smem_log_init(); + if (ret < 0) + return ret; + + smem_log_debugfs_init(); + + return misc_register(&smem_log_dev); +} + + +module_init(smem_log_init); + +MODULE_DESCRIPTION("smem log"); +MODULE_LICENSE("GPL v2"); diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c new file mode 100644 index 000000000000..978f7af6d60c --- /dev/null +++ b/arch/arm/mach-msm/socinfo.c @@ -0,0 +1,326 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +/* + * SOC Info Routines + * + */ + +#include +#include +#include "socinfo.h" +#include "smd_private.h" + +/* Used to parse shared memory. Must match the modem. */ +struct socinfo_legacy { + uint32_t format; + uint32_t id; + uint32_t version; + char build_id[32]; +}; + +struct socinfo_raw { + struct socinfo_legacy legacy; + + /* only valid when format==2 */ + uint32_t raw_id; + uint32_t raw_version; +}; + +static union { + struct socinfo_legacy legacy; + struct socinfo_raw raw; +} *socinfo; + +static enum msm_cpu cpu_of_id[] = { + /* Uninitialized IDs are not known to run Linux. + * MSM_CPU_UNKNOWN is set to 0 to ensure these IDs are + * considered as unknown CPUs. */ + + /* 7x01 IDs */ + [1] = MSM_CPU_7X01, + [16] = MSM_CPU_7X01, + [17] = MSM_CPU_7X01, + [18] = MSM_CPU_7X01, + [19] = MSM_CPU_7X01, + [23] = MSM_CPU_7X01, + [25] = MSM_CPU_7X01, + [26] = MSM_CPU_7X01, + [32] = MSM_CPU_7X01, + [33] = MSM_CPU_7X01, + [34] = MSM_CPU_7X01, + [35] = MSM_CPU_7X01, + + /* 7x25 IDs */ + [20] = MSM_CPU_7X25, + [21] = MSM_CPU_7X25, + [24] = MSM_CPU_7X25, + [27] = MSM_CPU_7X25, + [39] = MSM_CPU_7X25, + [40] = MSM_CPU_7X25, + [41] = MSM_CPU_7X25, + [42] = MSM_CPU_7X25, + + /* 7x27 IDs */ + [43] = MSM_CPU_7X27, + [44] = MSM_CPU_7X27, + + /* 8x50 IDs */ + [30] = MSM_CPU_8X50, + [36] = MSM_CPU_8X50, + [37] = MSM_CPU_8X50, + [38] = MSM_CPU_8X50, + + /* Last known ID. */ + [53] = MSM_CPU_UNKNOWN, +}; + +static enum msm_cpu cur_cpu; + +uint32_t socinfo_get_id(void) +{ + return (socinfo) ? socinfo->legacy.id : 0; +} + +uint32_t socinfo_get_version(void) +{ + return (socinfo) ? socinfo->legacy.version : 0; +} + +char *socinfo_get_build_id(void) +{ + return (socinfo) ? socinfo->legacy.build_id : NULL; +} + +uint32_t socinfo_get_raw_id(void) +{ + return socinfo ? + (socinfo->legacy.format == 2 ? socinfo->raw.raw_id : 0) + : 0; +} + +uint32_t socinfo_get_raw_version(void) +{ + return socinfo ? + (socinfo->legacy.format == 2 ? socinfo->raw.raw_version : 0) + : 0; +} + +enum msm_cpu socinfo_get_msm_cpu(void) +{ + return cur_cpu; +} + +static ssize_t +socinfo_show_id(struct sys_device *dev, + struct sysdev_attribute *attr, + char *buf) +{ + if (!socinfo) { + printk(KERN_ERR "%s: No socinfo found!", __func__); + return 0; + } + + return snprintf(buf, PAGE_SIZE, "%u\n", socinfo_get_id()); +} + +static ssize_t +socinfo_show_version(struct sys_device *dev, + struct sysdev_attribute *attr, + char *buf) +{ + uint32_t version; + + if (!socinfo) { + printk(KERN_ERR "%s: No socinfo found!", __func__); + return 0; + } + + version = socinfo_get_version(); + return snprintf(buf, PAGE_SIZE, "%u.%u\n", + SOCINFO_VERSION_MAJOR(version), + SOCINFO_VERSION_MINOR(version)); +} + +static ssize_t +socinfo_show_build_id(struct sys_device *dev, + struct sysdev_attribute *attr, + char *buf) +{ + if (!socinfo) { + printk(KERN_ERR "%s: No socinfo found!", __func__); + return 0; + } + + return snprintf(buf, PAGE_SIZE, "%-.32s\n", socinfo_get_build_id()); +} + +static ssize_t +socinfo_show_raw_id(struct sys_device *dev, + struct sysdev_attribute *attr, + char *buf) +{ + if (!socinfo) { + printk(KERN_ERR "%s: No socinfo found!", __func__); + return 0; + } + if (socinfo->legacy.format != 2) { + printk(KERN_ERR "%s: Raw ID not available!", __func__); + return 0; + } + + return snprintf(buf, PAGE_SIZE, "%u\n", socinfo_get_raw_id()); +} + +static ssize_t +socinfo_show_raw_version(struct sys_device *dev, + struct sysdev_attribute *attr, + char *buf) +{ + if (!socinfo) { + printk(KERN_ERR "%s: No socinfo found!", __func__); + return 0; + } + if (socinfo->legacy.format != 2) { + printk(KERN_ERR "%s: Raw version not available!", __func__); + return 0; + } + + return snprintf(buf, PAGE_SIZE, "%u\n", socinfo_get_raw_version()); +} + +static struct sysdev_attribute socinfo_legacy_files[] = { + _SYSDEV_ATTR(id, 0444, socinfo_show_id, NULL), + _SYSDEV_ATTR(version, 0444, socinfo_show_version, NULL), + _SYSDEV_ATTR(build_id, 0444, socinfo_show_build_id, NULL), +}; + +static struct sysdev_attribute socinfo_raw_files[] = { + _SYSDEV_ATTR(raw_id, 0444, socinfo_show_raw_id, NULL), + _SYSDEV_ATTR(raw_version, 0444, socinfo_show_raw_version, NULL), +}; + +static struct sysdev_class soc_sysdev_class = { + .name = "soc", +}; + +static struct sys_device soc_sys_device = { + .id = 0, + .cls = &soc_sysdev_class, +}; + +static void __init socinfo_create_files(struct sys_device *dev, + struct sysdev_attribute files[], + int size) +{ + int i; + for (i = 0; i < size; i++) { + int err = sysdev_create_file(dev, &files[i]); + if (err) { + printk(KERN_ERR "%s: sysdev_create_file(%s)=%d\n", + __func__, files[i].attr.name, err); + return; + } + } +} + +static void __init socinfo_init_sysdev(void) +{ + int err; + + err = sysdev_class_register(&soc_sysdev_class); + if (err) { + printk(KERN_ERR "%s: sysdev_class_register fail (%d)\n", + __func__, err); + return; + } + err = sysdev_register(&soc_sys_device); + if (err) { + printk(KERN_ERR "%s: sysdev_register fail (%d)\n", + __func__, err); + return; + } + socinfo_create_files(&soc_sys_device, socinfo_legacy_files, + ARRAY_SIZE(socinfo_legacy_files)); + if (socinfo->legacy.format != 2) + return; + socinfo_create_files(&soc_sys_device, socinfo_raw_files, + ARRAY_SIZE(socinfo_raw_files)); +} + +int __init socinfo_init(void) +{ + socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID, sizeof(struct socinfo_raw)); + if (!socinfo) + socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID, + sizeof(struct socinfo_legacy)); + + if (!socinfo) { + printk(KERN_ERR "%s: Can't find SMEM_HW_SW_BUILD_ID\n", + __func__); + return -EIO; + } + + WARN(!socinfo_get_id(), "Unknown SOC ID!\n"); + WARN(socinfo_get_id() >= ARRAY_SIZE(cpu_of_id), + "New IDs added! ID => CPU mapping might need an update.\n"); + + if (socinfo->legacy.id < ARRAY_SIZE(cpu_of_id)) + cur_cpu = cpu_of_id[socinfo->legacy.id]; + + socinfo_init_sysdev(); + return 0; +} diff --git a/arch/arm/mach-msm/socinfo.h b/arch/arm/mach-msm/socinfo.h new file mode 100644 index 000000000000..60c24e00d776 --- /dev/null +++ b/arch/arm/mach-msm/socinfo.h @@ -0,0 +1,116 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef _ARCH_ARM_MACH_MSM_SOCINFO_H_ +#define _ARCH_ARM_MACH_MSM_SOCINFO_H_ + +/* + * SOC version type with major number in the upper 16 bits and minor + * number in the lower 16 bits. For example: + * 1.0 -> 0x00010000 + * 2.3 -> 0x00020003 + */ +#define SOCINFO_VERSION_MAJOR(ver) ((ver & 0xffff0000) >> 16) +#define SOCINFO_VERSION_MINOR(ver) (ver & 0x0000ffff) + +enum msm_cpu { + MSM_CPU_UNKNOWN = 0, + MSM_CPU_7X01, + MSM_CPU_7X25, + MSM_CPU_7X27, + MSM_CPU_8X50, +}; + +enum msm_cpu socinfo_get_msm_cpu(void); +uint32_t socinfo_get_id(void); +uint32_t socinfo_get_version(void); +char *socinfo_get_build_id(void); +int __init socinfo_init(void) __must_check; + +static inline int cpu_is_msm7x01(void) +{ + enum msm_cpu cpu = socinfo_get_msm_cpu(); + + BUG_ON(cpu == MSM_CPU_UNKNOWN); + return cpu == MSM_CPU_7X01; +} + +static inline int cpu_is_msm7x25(void) +{ + enum msm_cpu cpu = socinfo_get_msm_cpu(); + + BUG_ON(cpu == MSM_CPU_UNKNOWN); + return cpu == MSM_CPU_7X25; +} + +static inline int cpu_is_msm7x27(void) +{ + enum msm_cpu cpu = socinfo_get_msm_cpu(); + + BUG_ON(cpu == MSM_CPU_UNKNOWN); + return cpu == MSM_CPU_7X27; +} + +static inline int cpu_is_qsd8x50(void) +{ + enum msm_cpu cpu = socinfo_get_msm_cpu(); + + BUG_ON(cpu == MSM_CPU_UNKNOWN); + return cpu == MSM_CPU_8X50; +} + +#endif diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c index a78e7484cb8b..8075e9225073 100644 --- a/arch/arm/mach-msm/timer.c +++ b/arch/arm/mach-msm/timer.c @@ -1,6 +1,7 @@ /* linux/arch/arm/mach-msm/timer.c * * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2009, Code Aurora Forum. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -26,6 +27,7 @@ #include #include "smd_private.h" +#include "timer.h" enum { MSM_TIMER_DEBUG_SYNC = 1U << 0, @@ -47,7 +49,12 @@ module_param_named(debug_mask, msm_timer_debug_mask, int, S_IRUGO | S_IWUSR | S_ #define CSR_PROTECTION_EN 1 #define GPT_HZ 32768 +#if defined(CONFIG_ARCH_QSD) +#define DGT_HZ 4800000 /* DGT is run with divider of 4 */ +#else #define DGT_HZ 19200000 /* 19.2 MHz or 600 KHz after shift */ +#endif +#define SCLK_HZ 32768 enum { MSM_CLOCK_FLAGS_UNSTABLE_COUNT = 1U << 0, @@ -79,6 +86,12 @@ enum { static struct msm_clock msm_clocks[]; static struct msm_clock *msm_active_clock; +struct msm_timer_sync_data_t { + struct msm_clock *clock; + uint32_t timeout; + int exit_sleep; +}; + static irqreturn_t msm_timer_interrupt(int irq, void *dev_id) { struct clock_event_device *evt = dev_id; @@ -121,7 +134,7 @@ static cycle_t msm_dgt_read(struct clocksource *cs) { struct msm_clock *clock = &msm_clocks[MSM_CLOCK_DGT]; if (clock->stopped) - return clock->stopped_tick; + return clock->stopped_tick >> MSM_DGT_SHIFT; return (msm_read_timer_count(clock) + clock->offset) >> MSM_DGT_SHIFT; } @@ -181,7 +194,8 @@ static void msm_timer_set_mode(enum clock_event_mode mode, break; case CLOCK_EVT_MODE_ONESHOT: clock->stopped = 0; - clock->offset = -msm_read_timer_count(clock) + clock->stopped_tick; + clock->offset = -msm_read_timer_count(clock) + + clock->stopped_tick; msm_active_clock = clock; writel(TIMER_ENABLE_EN, clock->regbase + TIMER_ENABLE); break; @@ -190,30 +204,125 @@ static void msm_timer_set_mode(enum clock_event_mode mode, msm_active_clock = NULL; clock->smem_in_sync = 0; clock->stopped = 1; - clock->stopped_tick = (msm_read_timer_count(clock) + - clock->offset) >> clock->shift; + clock->stopped_tick = msm_read_timer_count(clock) + + clock->offset; writel(0, clock->regbase + TIMER_ENABLE); break; } local_irq_restore(irq_flags); } -static inline int check_timeout(struct msm_clock *clock, uint32_t timeout) +/* + * Retrieve the cycle count from the slow clock through SMEM and optionally + * synchronize local clock(s) with the slow clock. The function implements + * the inter-processor time-sync protocol. + * + * time_start and time_expired are callbacks that must be specified. The + * protocol uses them to detect timeout. The update callback is optional. + * If not NULL, update will be called so that it can update local clock(s). + * + * The function does not use the argument data directly; it passes data to + * the callbacks. + * + * Return value: + * 0: the operation failed + * >0: the slow clock value after time-sync + */ +#if defined(CONFIG_MSM_N_WAY_SMSM) +static uint32_t msm_timer_sync_sclk( + void (*time_start)(struct msm_timer_sync_data_t *data), + bool (*time_expired)(struct msm_timer_sync_data_t *data), + void (*update)(struct msm_timer_sync_data_t *data, uint32_t clk_val), + struct msm_timer_sync_data_t *data) { - return (int32_t)(msm_read_timer_count(clock) - timeout) <= 0; -} + /* Time Master State Bits */ + #define MASTER_BITS_PER_CPU 1 + #define MASTER_TIME_PENDING \ + (0x01UL << (MASTER_BITS_PER_CPU * SMSM_APPS_STATE)) + + /* Time Slave State Bits */ + #define SLAVE_TIME_REQUEST 0x0400 + #define SLAVE_TIME_POLL 0x0800 + #define SLAVE_TIME_INIT 0x1000 + + uint32_t *smem_clock; + uint32_t smem_clock_val; + uint32_t state; + + smem_clock = smem_alloc(SMEM_SMEM_SLOW_CLOCK_VALUE, sizeof(uint32_t)); + if (smem_clock == NULL) { + printk(KERN_ERR "no smem clock\n"); + return 0; + } -static uint32_t msm_timer_sync_smem_clock(int exit_sleep) + state = smsm_get_state(SMSM_MODEM_STATE); + if ((state & SMSM_INIT) == 0) { + printk(KERN_ERR "smsm not initialized\n"); + return 0; + } + + time_start(data); + while ((state = smsm_get_state(SMSM_TIME_MASTER_DEM)) & + MASTER_TIME_PENDING) { + if (time_expired(data)) { + printk(KERN_INFO "get_smem_clock: timeout 1 still " + "invalid state %x\n", state); + return 0; + } + } + + smsm_change_state(SMSM_APPS_DEM, SLAVE_TIME_POLL | SLAVE_TIME_INIT, + SLAVE_TIME_REQUEST); + + time_start(data); + while (!((state = smsm_get_state(SMSM_TIME_MASTER_DEM)) & + MASTER_TIME_PENDING)) { + if (time_expired(data)) { + printk(KERN_INFO "get_smem_clock: timeout 2 still " + "invalid state %x\n", state); + smem_clock_val = 0; + goto sync_sclk_exit; + } + } + + smsm_change_state(SMSM_APPS_DEM, SLAVE_TIME_REQUEST, SLAVE_TIME_POLL); + + time_start(data); + do { + smem_clock_val = *smem_clock; + } while (smem_clock_val == 0 && !time_expired(data)); + + state = smsm_get_state(SMSM_TIME_MASTER_DEM); + + if (smem_clock_val) { + if (update != NULL) + update(data, smem_clock_val); + + if (msm_timer_debug_mask & MSM_TIMER_DEBUG_SYNC) + printk(KERN_INFO + "get_smem_clock: state %x clock %u\n", + state, smem_clock_val); + } else { + printk(KERN_INFO "get_smem_clock: timeout state %x clock %u\n", + state, smem_clock_val); + } + +sync_sclk_exit: + smsm_change_state(SMSM_APPS_DEM, SLAVE_TIME_REQUEST | SLAVE_TIME_POLL, + SLAVE_TIME_INIT); + return smem_clock_val; +} +#else /* CONFIG_MSM_N_WAY_SMSM */ +static uint32_t msm_timer_sync_sclk( + void (*time_start)(struct msm_timer_sync_data_t *data), + bool (*time_expired)(struct msm_timer_sync_data_t *data), + void (*update)(struct msm_timer_sync_data_t *data, uint32_t clk_val), + struct msm_timer_sync_data_t *data) { - struct msm_clock *clock = &msm_clocks[MSM_CLOCK_GPT]; uint32_t *smem_clock; uint32_t smem_clock_val; - uint32_t timeout; - uint32_t entry_time; - uint32_t timeout_delta; uint32_t last_state; uint32_t state; - uint32_t new_offset; smem_clock = smem_alloc(SMEM_SMEM_SLOW_CLOCK_VALUE, sizeof(uint32_t)); @@ -223,75 +332,167 @@ static uint32_t msm_timer_sync_smem_clock(int exit_sleep) return 0; } - if (!exit_sleep && clock->smem_in_sync) - return 0; - - timeout_delta = (clock->freq >> (7 - clock->shift)); /* 7.8ms */ - - last_state = state = smsm_get_state(); - if (*smem_clock) { + last_state = state = smsm_get_state(SMSM_MODEM_STATE); + smem_clock_val = *smem_clock; + if (smem_clock_val) { printk(KERN_INFO "get_smem_clock: invalid start state %x " - "clock %u\n", state, *smem_clock); - smsm_change_state(SMSM_TIMEWAIT, SMSM_TIMEINIT); - entry_time = msm_read_timer_count(clock); - timeout = entry_time + timeout_delta; - while (*smem_clock != 0 && check_timeout(clock, timeout)) + "clock %u\n", state, smem_clock_val); + smsm_change_state(SMSM_APPS_STATE, + SMSM_TIMEWAIT, SMSM_TIMEINIT); + + time_start(data); + while (*smem_clock != 0 && !time_expired(data)) ; - if (*smem_clock) { + + smem_clock_val = *smem_clock; + if (smem_clock_val) { printk(KERN_INFO "get_smem_clock: timeout still " - "invalid state %x clock %u in %d ticks\n", - state, *smem_clock, - msm_read_timer_count(clock) - entry_time); + "invalid state %x clock %u\n", + state, smem_clock_val); return 0; } } - entry_time = msm_read_timer_count(clock); - timeout = entry_time + timeout_delta; - smsm_change_state(SMSM_TIMEINIT, SMSM_TIMEWAIT); + + time_start(data); + smsm_change_state(SMSM_APPS_STATE, SMSM_TIMEINIT, SMSM_TIMEWAIT); do { smem_clock_val = *smem_clock; - state = smsm_get_state(); + state = smsm_get_state(SMSM_MODEM_STATE); if (state != last_state) { last_state = state; - printk(KERN_INFO "get_smem_clock: state %x clock %u\n", - state, smem_clock_val); - } - } while (smem_clock_val == 0 && check_timeout(clock, timeout)); - if (smem_clock_val) { - new_offset = smem_clock_val - msm_read_timer_count(clock); - if (clock->offset + clock->smem_offset != new_offset) { - if (exit_sleep) - clock->offset = new_offset - clock->smem_offset; - else - clock->smem_offset = new_offset - clock->offset; - clock->smem_in_sync = 1; if (msm_timer_debug_mask & MSM_TIMER_DEBUG_SYNC) - printk(KERN_INFO "get_smem_clock: state %x " - "clock %u new offset %u+%u\n", - state, smem_clock_val, - clock->offset, clock->smem_offset); + printk(KERN_INFO + "get_smem_clock: state %x clock %u\n", + state, smem_clock_val); } + } while (smem_clock_val == 0 && !time_expired(data)); + + if (smem_clock_val) { + if (update != NULL) + update(data, smem_clock_val); } else { - printk(KERN_INFO "get_smem_clock: timeout state %x clock %u " - "in %d ticks\n", state, *smem_clock, - msm_read_timer_count(clock) - entry_time); + printk(KERN_INFO "get_smem_clock: timeout state %x clock %u\n", + state, smem_clock_val); } - smsm_change_state(SMSM_TIMEWAIT, SMSM_TIMEINIT); - entry_time = msm_read_timer_count(clock); - timeout = entry_time + timeout_delta; - while (*smem_clock != 0 && check_timeout(clock, timeout)) + + smsm_change_state(SMSM_APPS_STATE, SMSM_TIMEWAIT, SMSM_TIMEINIT); + time_start(data); + while (*smem_clock != 0 && !time_expired(data)) ; + if (*smem_clock) printk(KERN_INFO "get_smem_clock: exit timeout state %x " - "clock %u in %d ticks\n", state, *smem_clock, - msm_read_timer_count(clock) - entry_time); + "clock %u\n", state, *smem_clock); return smem_clock_val; } +#endif /* CONFIG_MSM_N_WAY_SMSM */ + +/* + * Callback function that initializes the timeout value. + */ +static void msm_timer_sync_smem_clock_time_start( + struct msm_timer_sync_data_t *data) +{ + /* approx 1/128th of a second */ + uint32_t delta = data->clock->freq >> 7 << data->clock->shift; + data->timeout = msm_read_timer_count(data->clock) + delta; +} + +/* + * Callback function that checks the timeout. + */ +static bool msm_timer_sync_smem_clock_time_expired( + struct msm_timer_sync_data_t *data) +{ + uint32_t delta = msm_read_timer_count(data->clock) - data->timeout; + return ((int32_t) delta) > 0; +} + +/* + * Callback function that updates clock(s) with the specified slow clock + * value. The GPT clock is always updated. + */ +static void msm_timer_sync_smem_clock_update( + struct msm_timer_sync_data_t *data, uint32_t clock_value) +{ + struct msm_clock *clocks[2]; + uint32_t timer_counts[2]; + uint32_t new_offset; + int i; + + clocks[0] = data->clock; + + if (data->clock != &msm_clocks[MSM_CLOCK_GPT]) + clocks[1] = &msm_clocks[MSM_CLOCK_GPT]; + else + clocks[1] = NULL; + + for (i = 0; i < ARRAY_SIZE(clocks); i++) { + if (clocks[i] == NULL) + continue; + + timer_counts[i] = msm_read_timer_count(clocks[i]); + } + + for (i = 0; i < ARRAY_SIZE(clocks); i++) { + if (clocks[i] == NULL) + continue; + + new_offset = clock_value * + ((clocks[i]->freq << clocks[i]->shift) / SCLK_HZ) - + timer_counts[i]; + + if (clocks[i]->offset + clocks[i]->smem_offset != new_offset) { + if (data->exit_sleep) + clocks[i]->offset + = new_offset - clocks[i]->smem_offset; + else + clocks[i]->smem_offset + = new_offset - clocks[i]->offset; + + clocks[i]->smem_in_sync = 1; + + if (msm_timer_debug_mask & MSM_TIMER_DEBUG_SYNC) + printk(KERN_INFO "get_smem_clock: " + "clock %u new offset %u+%u\n", + clock_value, clocks[i]->offset, + clocks[i]->smem_offset); + } + } +} + +/* + * Synchronize clock(s) with the slow clock through SMEM. + * + * Return value: + * 0: the operation failed + * >0: the slow clock value after time-sync + */ +static uint32_t msm_timer_sync_smem_clock(struct msm_clock *clock, + int exit_sleep) +{ + struct msm_timer_sync_data_t data; + + if (!exit_sleep && clock->smem_in_sync && + msm_clocks[MSM_CLOCK_GPT].smem_in_sync) + return 0; + + data.clock = clock; + data.timeout = 0; + data.exit_sleep = exit_sleep; + + return msm_timer_sync_sclk( + msm_timer_sync_smem_clock_time_start, + msm_timer_sync_smem_clock_time_expired, + msm_timer_sync_smem_clock_update, + &data); +} static void msm_timer_reactivate_alarm(struct msm_clock *clock) { long alarm_delta = clock->alarm_vtime - clock->offset - msm_read_timer_count(clock); + alarm_delta >>= clock->shift; if (alarm_delta < (long)clock->write_delay + 4) alarm_delta = clock->write_delay + 4; while (msm_timer_set_next_event(alarm_delta, &clock->clockevent)) @@ -305,14 +506,14 @@ int64_t msm_timer_enter_idle(void) uint32_t count; int32_t delta; - if (clock != &msm_clocks[MSM_CLOCK_GPT]) - return 0; + BUG_ON(clock != &msm_clocks[MSM_CLOCK_GPT] && + clock != &msm_clocks[MSM_CLOCK_DGT]); - msm_timer_sync_smem_clock(0); + msm_timer_sync_smem_clock(clock, 0); count = msm_read_timer_count(clock); if (clock->stopped++ == 0) - clock->stopped_tick = (count + clock->offset) >> clock->shift; + clock->stopped_tick = count + clock->offset; alarm = readl(clock->regbase + TIMER_MATCH_VAL); delta = alarm - count; if (delta <= -(int32_t)((clock->freq << clock->shift) >> 10)) { @@ -331,19 +532,85 @@ void msm_timer_exit_idle(int low_power) struct msm_clock *clock = msm_active_clock; uint32_t smem_clock; - if (clock != &msm_clocks[MSM_CLOCK_GPT]) - return; + BUG_ON(clock != &msm_clocks[MSM_CLOCK_GPT] && + clock != &msm_clocks[MSM_CLOCK_DGT]); if (low_power) { - if (!(readl(clock->regbase + TIMER_ENABLE) & TIMER_ENABLE_EN)) { +#if !defined(CONFIG_ARCH_QSD) + if (!(readl(clock->regbase+TIMER_ENABLE) & TIMER_ENABLE_EN)) +#endif + { writel(TIMER_ENABLE_EN, clock->regbase + TIMER_ENABLE); - smem_clock = msm_timer_sync_smem_clock(1); + if (clock != &msm_clocks[MSM_CLOCK_GPT]) { + struct msm_clock *gpt = + &msm_clocks[MSM_CLOCK_GPT]; + writel(TIMER_ENABLE_EN, + gpt->regbase + TIMER_ENABLE); + } + smem_clock = msm_timer_sync_smem_clock(clock, 1); } msm_timer_reactivate_alarm(clock); } clock->stopped--; } +/* + * Callback function that initializes the timeout value. + */ +static void msm_timer_get_smem_clock_time_start( + struct msm_timer_sync_data_t *data) +{ + data->timeout = 10000; +} + +/* + * Callback function that checks the timeout. + */ +static bool msm_timer_get_smem_clock_time_expired( + struct msm_timer_sync_data_t *data) +{ + return --data->timeout <= 0; +} + +/* + * Retrieve the cycle count from the slow clock through SMEM and + * convert it into nanoseconds. + * + * On exit, if period is not NULL, it contains the period of the + * slow clock in nanoseconds, i.e. how long the cycle count wraps + * around. + * + * Return value: + * 0: the operation failed; period is not set either + * >0: time in nanoseconds + */ +int64_t msm_timer_get_smem_clock_time(int64_t *period) +{ + struct msm_timer_sync_data_t data; + uint32_t clock_value; + int64_t tmp; + + memset(&data, 0, sizeof(data)); + clock_value = msm_timer_sync_sclk( + msm_timer_get_smem_clock_time_start, + msm_timer_get_smem_clock_time_expired, + NULL, + &data); + + if (!clock_value) + return 0; + + if (period) { + tmp = (int64_t)UINT_MAX; + tmp = tmp * NSEC_PER_SEC / SCLK_HZ; + *period = tmp; + } + + tmp = (int64_t)clock_value; + tmp = tmp * NSEC_PER_SEC / SCLK_HZ; + return tmp; +} + unsigned long long sched_clock(void) { static cycle_t saved_ticks; @@ -464,7 +731,6 @@ static void __init msm_timer_init(void) struct clock_event_device *ce = &clock->clockevent; struct clocksource *cs = &clock->clocksource; writel(0, clock->regbase + TIMER_ENABLE); - writel(0, clock->regbase + TIMER_CLEAR); writel(~0, clock->regbase + TIMER_MATCH_VAL); ce->mult = div_sc(clock->freq, NSEC_PER_SEC, ce->shift); diff --git a/arch/arm/mach-msm/timer.h b/arch/arm/mach-msm/timer.h new file mode 100644 index 000000000000..43b1a17bf56c --- /dev/null +++ b/arch/arm/mach-msm/timer.h @@ -0,0 +1,67 @@ +/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef _ARCH_ARM_MACH_MSM_TIMER_H_ +#define _ARCH_ARM_MACH_MSM_TIMER_H_ + +extern struct sys_timer msm_timer; + +int64_t msm_timer_enter_idle(void); +void msm_timer_exit_idle(int low_power); +int64_t msm_timer_get_smem_clock_time(int64_t *period); + +#endif diff --git a/arch/arm/mach-msm/vreg.c b/arch/arm/mach-msm/vreg.c index fcb0b9f25684..2cb7e88fe300 100644 --- a/arch/arm/mach-msm/vreg.c +++ b/arch/arm/mach-msm/vreg.c @@ -1,6 +1,7 @@ /* arch/arm/mach-msm/vreg.c * * Copyright (C) 2008 Google, Inc. + * Copyright (c) 2009, Code Aurora Forum. All rights reserved. * Author: Brian Swetland * * This software is licensed under the terms of the GNU General Public @@ -22,45 +23,55 @@ #include "proc_comm.h" +#if defined(CONFIG_MSM_VREG_SWITCH_INVERTED) +#define VREG_SWITCH_ENABLE 0 +#define VREG_SWITCH_DISABLE 1 +#else +#define VREG_SWITCH_ENABLE 1 +#define VREG_SWITCH_DISABLE 0 +#endif + struct vreg { const char *name; unsigned id; + int status; }; -#define VREG(_name, _id) { .name = _name, .id = _id, } +#define VREG(_name, _id, _status) \ + { .name = _name, .id = _id, .status = _status } static struct vreg vregs[] = { - VREG("msma", 0), - VREG("msmp", 1), - VREG("msme1", 2), - VREG("msmc1", 3), - VREG("msmc2", 4), - VREG("gp3", 5), - VREG("msme2", 6), - VREG("gp4", 7), - VREG("gp1", 8), - VREG("tcxo", 9), - VREG("pa", 10), - VREG("rftx", 11), - VREG("rfrx1", 12), - VREG("rfrx2", 13), - VREG("synt", 14), - VREG("wlan", 15), - VREG("usb", 16), - VREG("boost", 17), - VREG("mmc", 18), - VREG("ruim", 19), - VREG("msmc0", 20), - VREG("gp2", 21), - VREG("gp5", 22), - VREG("gp6", 23), - VREG("rf", 24), - VREG("rf_vco", 26), - VREG("mpll", 27), - VREG("s2", 28), - VREG("s3", 29), - VREG("rfubm", 30), - VREG("ncp", 31), + VREG("msma", 0, 0), + VREG("msmp", 1, 0), + VREG("msme1", 2, 0), + VREG("msmc1", 3, 0), + VREG("msmc2", 4, 0), + VREG("gp3", 5, 0), + VREG("msme2", 6, 0), + VREG("gp4", 7, 0), + VREG("gp1", 8, 0), + VREG("tcxo", 9, 0), + VREG("pa", 10, 0), + VREG("rftx", 11, 0), + VREG("rfrx1", 12, 0), + VREG("rfrx2", 13, 0), + VREG("synt", 14, 0), + VREG("wlan", 15, 0), + VREG("usb", 16, 0), + VREG("boost", 17, 0), + VREG("mmc", 18, 0), + VREG("ruim", 19, 0), + VREG("msmc0", 20, 0), + VREG("gp2", 21, 0), + VREG("gp5", 22, 0), + VREG("gp6", 23, 0), + VREG("rf", 24, 0), + VREG("rf_vco", 26, 0), + VREG("mpll", 27, 0), + VREG("s2", 28, 0), + VREG("s3", 29, 0), + VREG("rfubm", 30, 0), + VREG("ncp", 31, 0), }; struct vreg *vreg_get(struct device *dev, const char *id) @@ -70,8 +81,9 @@ struct vreg *vreg_get(struct device *dev, const char *id) if (!strcmp(vregs[n].name, id)) return vregs + n; } - return 0; + return ERR_PTR(-ENOENT); } +EXPORT_SYMBOL(vreg_get); void vreg_put(struct vreg *vreg) { @@ -80,22 +92,31 @@ void vreg_put(struct vreg *vreg) int vreg_enable(struct vreg *vreg) { unsigned id = vreg->id; - unsigned enable = 1; - return msm_proc_comm(PCOM_VREG_SWITCH, &id, &enable); + int enable = VREG_SWITCH_ENABLE; + + vreg->status = msm_proc_comm(PCOM_VREG_SWITCH, &id, &enable); + return vreg->status; } +EXPORT_SYMBOL(vreg_enable); -void vreg_disable(struct vreg *vreg) +int vreg_disable(struct vreg *vreg) { unsigned id = vreg->id; - unsigned enable = 0; - msm_proc_comm(PCOM_VREG_SWITCH, &id, &enable); + int disable = VREG_SWITCH_DISABLE; + + vreg->status = msm_proc_comm(PCOM_VREG_SWITCH, &id, &disable); + return vreg->status; } +EXPORT_SYMBOL(vreg_disable); int vreg_set_level(struct vreg *vreg, unsigned mv) { unsigned id = vreg->id; - return msm_proc_comm(PCOM_VREG_SET_LEVEL, &id, &mv); + + vreg->status = msm_proc_comm(PCOM_VREG_SET_LEVEL, &id, &mv); + return vreg->status; } +EXPORT_SYMBOL(vreg_set_level); #if defined(CONFIG_DEBUG_FS) @@ -118,7 +139,14 @@ static int vreg_debug_set(void *data, u64 val) static int vreg_debug_get(void *data, u64 *val) { - return -ENOSYS; + struct vreg *vreg = data; + + if (!vreg->status) + *val = 0; + else + *val = 1; + + return 0; } DEFINE_SIMPLE_ATTRIBUTE(vreg_fops, vreg_debug_get, vreg_debug_set, "%llu\n"); -- cgit v1.2.3 From e581638558ef6f6280b6b3f809184d6991277f86 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Sat, 2 Jan 2010 08:06:51 -0800 Subject: arm: msm: add mmc.h to mach includes Signed-off-by: Daniel Walker --- arch/arm/mach-msm/include/mach/mmc.h | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/include/mach/mmc.h b/arch/arm/mach-msm/include/mach/mmc.h index 0ecf25426284..306de3d73fff 100644 --- a/arch/arm/mach-msm/include/mach/mmc.h +++ b/arch/arm/mach-msm/include/mach/mmc.h @@ -1,26 +1,16 @@ /* - * arch/arm/include/asm/mach/mmc.h + * arch/arm/mach-msm/include/mach/mmc.h */ -#ifndef ASMARM_MACH_MMC_H -#define ASMARM_MACH_MMC_H +#ifndef ASM_ARCH_MACH_MMC_H +#define ASM_ARCH_MACH_MMC_H #include -#include -#include - -struct embedded_sdio_data { - struct sdio_cis cis; - struct sdio_cccr cccr; - struct sdio_embedded_func *funcs; - int num_funcs; -}; struct mmc_platform_data { unsigned int ocr_mask; /* available voltages */ u32 (*translate_vdd)(struct device *, unsigned int); unsigned int (*status)(struct device *); - struct embedded_sdio_data *embedded_sdio; - int (*register_status_notify)(void (*callback)(int card_present, void *dev_id), void *dev_id); + unsigned long irq_flags; }; #endif -- cgit v1.2.3 From f6324835dc4f917f66b180075836e5e5644aae04 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Tue, 29 Dec 2009 11:59:37 -0800 Subject: arch/arm/mach-msm/devices.c --- arch/arm/mach-msm/devices.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/devices.c b/arch/arm/mach-msm/devices.c index d9edc27c6f5c..8465be7cbc64 100644 --- a/arch/arm/mach-msm/devices.c +++ b/arch/arm/mach-msm/devices.c @@ -91,7 +91,7 @@ struct platform_device msm_device_uart3 = { .resource = resources_uart3, }; -#if defined(CONFIG_ARCH_QSD) +#if defined(CONFIG_ARCH_MSM_SCORPION) #define MSM_UART1DM_PHYS 0xA0200000 #define MSM_UART2DM_PHYS 0xA0900000 #else @@ -199,7 +199,7 @@ struct platform_device msm_device_smd = { .id = -1, }; -#if defined(CONFIG_ARCH_QSD) +#if defined(CONFIG_ARCH_MSM_SCORPION) #define MSM_SDC1_BASE 0xA0300000 #define MSM_SDC2_BASE 0xA0400000 #define MSM_SDC3_BASE 0xA0500000 -- cgit v1.2.3 From 0f9051c82b0bbd164338032682fe99e15c5fd4d6 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Tue, 29 Dec 2009 11:59:37 -0800 Subject: arch/arm/mach-msm/gpio.c --- arch/arm/mach-msm/gpio.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/gpio.c b/arch/arm/mach-msm/gpio.c index 91f6c710286c..4d1336b5c407 100644 --- a/arch/arm/mach-msm/gpio.c +++ b/arch/arm/mach-msm/gpio.c @@ -170,7 +170,7 @@ struct msm_gpio_chip msm_gpio_chips[] = { }, .chip = { .start = 95, -#if defined(CONFIG_ARCH_QSD) +#if defined(CONFIG_ARCH_MSM_SCORPION) .end = 103, #else .end = 106, @@ -195,7 +195,7 @@ struct msm_gpio_chip msm_gpio_chips[] = { .oe = GPIO_OE_5, }, .chip = { -#if defined(CONFIG_ARCH_QSD) +#if defined(CONFIG_ARCH_MSM_SCORPION) .start = 104, .end = 121, #else @@ -210,7 +210,7 @@ struct msm_gpio_chip msm_gpio_chips[] = { .clear_detect_status = msm_gpio_clear_detect_status } }, -#if defined(CONFIG_ARCH_QSD) +#if defined(CONFIG_ARCH_MSM_SCORPION) { .regs = { .out = GPIO_OUT_6, -- cgit v1.2.3 From dd0593472cc9e036ad39a9f18d54f0ed13dd063a Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Tue, 29 Dec 2009 11:59:37 -0800 Subject: arch/arm/mach-msm/gpio_hw.h --- arch/arm/mach-msm/gpio_hw.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/gpio_hw.h b/arch/arm/mach-msm/gpio_hw.h index e9f38664bbe5..72e83efcd7f4 100644 --- a/arch/arm/mach-msm/gpio_hw.h +++ b/arch/arm/mach-msm/gpio_hw.h @@ -33,7 +33,7 @@ #define GPIO1_REG(off) (MSM_GPIO1_BASE + 0x800 + (off)) #define GPIO2_REG(off) (MSM_GPIO2_BASE + 0xC00 + (off)) -#if defined(CONFIG_ARCH_QSD) +#if defined(CONFIG_ARCH_MSM_SCORPION) #include "gpio_hw-8xxx.h" #else #include "gpio_hw-7xxx.h" -- cgit v1.2.3 From eaa2f93f6b163b1ac0f87ea85d889a072d2bf6a7 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Tue, 29 Dec 2009 11:59:37 -0800 Subject: arch/arm/mach-msm/include/mach/irqs.h --- arch/arm/mach-msm/include/mach/irqs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/include/mach/irqs.h b/arch/arm/mach-msm/include/mach/irqs.h index 69af8fc00c9d..ed5c12602b68 100644 --- a/arch/arm/mach-msm/include/mach/irqs.h +++ b/arch/arm/mach-msm/include/mach/irqs.h @@ -22,7 +22,7 @@ #define NR_MSM_IRQS 64 #define NR_BOARD_IRQS 64 -#if defined(CONFIG_ARCH_QSD) +#if defined(CONFIG_ARCH_MSM_SCORPION) #include "irqs-8xxx.h" #include "sirc.h" #else -- cgit v1.2.3 From 229bcbfaea8a2863f010a3aa6b8c4f59ed834166 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Tue, 29 Dec 2009 11:59:38 -0800 Subject: arch/arm/mach-msm/include/mach/msm_iomap.h --- arch/arm/mach-msm/include/mach/msm_iomap.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/include/mach/msm_iomap.h b/arch/arm/mach-msm/include/mach/msm_iomap.h index 22e1ecb52555..60df1ef0c4a9 100644 --- a/arch/arm/mach-msm/include/mach/msm_iomap.h +++ b/arch/arm/mach-msm/include/mach/msm_iomap.h @@ -45,7 +45,7 @@ #endif #define MSM_VIC_BASE IOMEM(0xE0000000) -#if defined(CONFIG_ARCH_QSD) +#if defined(CONFIG_ARCH_MSM_SCORPION) #define MSM_VIC_PHYS 0xAC000000 #else #define MSM_VIC_PHYS 0xC0000000 @@ -53,7 +53,7 @@ #define MSM_VIC_SIZE SZ_4K #define MSM_CSR_BASE IOMEM(0xE0001000) -#if defined(CONFIG_ARCH_QSD) +#if defined(CONFIG_ARCH_MSM_SCORPION) #define MSM_CSR_PHYS 0xAC100000 #else #define MSM_CSR_PHYS 0xC0100000 @@ -69,7 +69,7 @@ #define MSM_DMOV_SIZE SZ_4K #define MSM_GPIO1_BASE IOMEM(0xE0003000) -#if defined(CONFIG_ARCH_QSD) +#if defined(CONFIG_ARCH_MSM_SCORPION) #define MSM_GPIO1_PHYS 0xA9000000 #else #define MSM_GPIO1_PHYS 0xA9200000 @@ -77,7 +77,7 @@ #define MSM_GPIO1_SIZE SZ_4K #define MSM_GPIO2_BASE IOMEM(0xE0004000) -#if defined(CONFIG_ARCH_QSD) +#if defined(CONFIG_ARCH_MSM_SCORPION) #define MSM_GPIO2_PHYS 0xA9100000 #else #define MSM_GPIO2_PHYS 0xA9300000 -- cgit v1.2.3 From 298c0d7a5616edd0f53f1c3992d33f9ba09b2716 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Tue, 29 Dec 2009 11:59:38 -0800 Subject: arch/arm/mach-msm/include/mach/sirc.h --- arch/arm/mach-msm/include/mach/sirc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/include/mach/sirc.h b/arch/arm/mach-msm/include/mach/sirc.h index c902cb12ddd6..19efd24cd367 100644 --- a/arch/arm/mach-msm/include/mach/sirc.h +++ b/arch/arm/mach-msm/include/mach/sirc.h @@ -76,7 +76,7 @@ void msm_init_sirc(void); void msm_sirc_enter_sleep(void); void msm_sirc_exit_sleep(void); -#if defined(CONFIG_ARCH_QSD) +#if defined(CONFIG_ARCH_MSM_SCORPION) #include -- cgit v1.2.3 From b3966e1c2d3f6befc9b507eeaf1dce56eb54e7a7 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Tue, 29 Dec 2009 11:59:39 -0800 Subject: arch/arm/mach-msm/irq.c --- arch/arm/mach-msm/irq.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/irq.c b/arch/arm/mach-msm/irq.c index 399147e8fc6d..8a33e21b2d02 100644 --- a/arch/arm/mach-msm/irq.c +++ b/arch/arm/mach-msm/irq.c @@ -58,7 +58,7 @@ module_param_named(debug_mask, msm_irq_debug_mask, int, S_IRUGO | S_IWUSR | S_IW #define VIC_INT_POLARITY1 VIC_REG(0x0054) /* 1: NEG, 0: POS */ #define VIC_NO_PEND_VAL VIC_REG(0x0060) -#if defined(CONFIG_ARCH_QSD) +#if defined(CONFIG_ARCH_MSM_SCORPION) #define VIC_NO_PEND_VAL_FIQ VIC_REG(0x0064) #define VIC_INT_MASTEREN VIC_REG(0x0068) /* 1: IRQ, 2: FIQ */ #define VIC_CONFIG VIC_REG(0x006C) /* 1: USE SC VIC */ @@ -82,7 +82,7 @@ module_param_named(debug_mask, msm_irq_debug_mask, int, S_IRUGO | S_IWUSR | S_IW #define VIC_IRQ_VEC_PEND_RD VIC_REG(0x00D4) /* pending vector addr */ #define VIC_IRQ_VEC_WR VIC_REG(0x00D8) -#if defined(CONFIG_ARCH_QSD) +#if defined(CONFIG_ARCH_MSM_SCORPION) #define VIC_FIQ_VEC_RD VIC_REG(0x00DC) #define VIC_FIQ_VEC_PEND_RD VIC_REG(0x00E0) #define VIC_FIQ_VEC_WR VIC_REG(0x00E4) @@ -161,7 +161,7 @@ static uint8_t msm_irq_to_smsm[NR_IRQS] = { [INT_GP_TIMER_EXP] = SMSM_FAKE_IRQ, [INT_DEBUG_TIMER_EXP] = SMSM_FAKE_IRQ, [INT_ADSP_A11] = SMSM_FAKE_IRQ, -#if defined(CONFIG_ARCH_QSD) +#if defined(CONFIG_ARCH_MSM_SCORPION) [INT_SIRC_0] = SMSM_FAKE_IRQ, [INT_SIRC_1] = SMSM_FAKE_IRQ, #endif -- cgit v1.2.3 From 612bf2c6615b802ea27b3b6c8b91db1e426e068e Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Tue, 29 Dec 2009 11:59:39 -0800 Subject: arch/arm/mach-msm/pm.c --- arch/arm/mach-msm/pm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/pm.c b/arch/arm/mach-msm/pm.c index b61b592841c9..29b0ce9805d3 100644 --- a/arch/arm/mach-msm/pm.c +++ b/arch/arm/mach-msm/pm.c @@ -894,7 +894,7 @@ static int __init msm_pm_init(void) return -ENODEV; } -#if defined(CONFIG_ARCH_QSD) +#if defined(CONFIG_ARCH_MSM_SCORPION) /* The bootloader is responsible for initializing many of Scorpion's * coprocessor registers for things like cache timing. The state of * these coprocessor registers is lost on reset, so part of the @@ -908,7 +908,7 @@ static int __init msm_pm_init(void) printk(KERN_ERR "msm_pm_init: failed to map reset vector\n"); return -ENODEV; } -#endif /* CONFIG_ARCH_QSD */ +#endif /* CONFIG_ARCH_MSM_SCORPION */ BUG_ON(msm_pm_modes == NULL); -- cgit v1.2.3 From 5c41f2affc7868ee5c31e79a0faaeb0ebcb4aa09 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Tue, 29 Dec 2009 11:59:39 -0800 Subject: arch/arm/mach-msm/pm2.c --- arch/arm/mach-msm/pm2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/pm2.c b/arch/arm/mach-msm/pm2.c index faef1daef944..88f07b056f77 100644 --- a/arch/arm/mach-msm/pm2.c +++ b/arch/arm/mach-msm/pm2.c @@ -1568,7 +1568,7 @@ static int __init msm_pm_init(void) return -ENODEV; } -#ifdef CONFIG_ARCH_QSD +#ifdef CONFIG_ARCH_MSM_SCORPION /* The bootloader is responsible for initializing many of Scorpion's * coprocessor registers for things like cache timing. The state of * these coprocessor registers is lost on reset, so part of the @@ -1582,7 +1582,7 @@ static int __init msm_pm_init(void) printk(KERN_ERR "%s: failed to map reset vector\n", __func__); return -ENODEV; } -#endif /* CONFIG_ARCH_QSD */ +#endif /* CONFIG_ARCH_MSM_SCORPION */ BUG_ON(msm_pm_modes == NULL); -- cgit v1.2.3 From 695cd6a0f9df4d1909d4f40a0dcc16ac6e96880b Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Tue, 29 Dec 2009 11:59:39 -0800 Subject: arch/arm/mach-msm/timer.c --- arch/arm/mach-msm/timer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c index 8075e9225073..a5cc69977384 100644 --- a/arch/arm/mach-msm/timer.c +++ b/arch/arm/mach-msm/timer.c @@ -49,7 +49,7 @@ module_param_named(debug_mask, msm_timer_debug_mask, int, S_IRUGO | S_IWUSR | S_ #define CSR_PROTECTION_EN 1 #define GPT_HZ 32768 -#if defined(CONFIG_ARCH_QSD) +#if defined(CONFIG_ARCH_MSM_SCORPION) #define DGT_HZ 4800000 /* DGT is run with divider of 4 */ #else #define DGT_HZ 19200000 /* 19.2 MHz or 600 KHz after shift */ @@ -536,7 +536,7 @@ void msm_timer_exit_idle(int low_power) clock != &msm_clocks[MSM_CLOCK_DGT]); if (low_power) { -#if !defined(CONFIG_ARCH_QSD) +#if !defined(CONFIG_ARCH_MSM_SCORPION) if (!(readl(clock->regbase+TIMER_ENABLE) & TIMER_ENABLE_EN)) #endif { -- cgit v1.2.3 From 7b8bd68c8f457195dafc34fc1018d3e65cf13b41 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Wed, 30 Dec 2009 08:09:43 -0800 Subject: add stacked memory comment --- arch/arm/mach-msm/include/mach/memory.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/include/mach/memory.h b/arch/arm/mach-msm/include/mach/memory.h index 77316bb85e15..6a9ed85700d9 100644 --- a/arch/arm/mach-msm/include/mach/memory.h +++ b/arch/arm/mach-msm/include/mach/memory.h @@ -25,7 +25,7 @@ #define PHYS_OFFSET UL(0x10000000) #endif -#else +#else /* !CONFIG_MSM_STACKED_MEMORY */ #define PHYS_OFFSET UL(0x00200000) -- cgit v1.2.3 From 732fb7c321414a056084bd254fb22951075333b5 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Wed, 30 Dec 2009 08:10:35 -0800 Subject: ARM11 macro in memory.h --- arch/arm/mach-msm/include/mach/memory.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/include/mach/memory.h b/arch/arm/mach-msm/include/mach/memory.h index 6a9ed85700d9..7cf04464e9a6 100644 --- a/arch/arm/mach-msm/include/mach/memory.h +++ b/arch/arm/mach-msm/include/mach/memory.h @@ -34,7 +34,7 @@ #ifndef __ASSEMBLY__ void *alloc_bootmem_aligned(unsigned long size, unsigned long alignment); -#ifdef CONFIG_ARCH_MSM +#ifdef CONFIG_ARCH_MSM_ARM11 void write_to_strongly_ordered_memory(void); #include -- cgit v1.2.3 From 120adfac78997f734bcca888255a49aa7c1223d0 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Wed, 30 Dec 2009 08:49:12 -0800 Subject: Move stacked memory Kconfig option. --- arch/arm/mach-msm/Kconfig | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index d065cf586a8a..7ea8228423b0 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -1,13 +1,5 @@ if ARCH_MSM || ARCH_QSD -config MSM_STACKED_MEMORY - bool "Stacked Memory" - default y - help - This option is used to indicate the presence of on-die stacked - memory. When present this memory bank is used for a high speed - shared memory interface. When not present regular RAM is used. - config MSM_AMSS_VERSION int default 6210 if MSM_AMSS_VERSION_6210 @@ -157,6 +149,14 @@ config MACH_QSD8X50_COMET help Support for the Qualcomm Comet eval board. + +config MSM_STACKED_MEMORY + bool "Stacked Memory" + default y + help + This option is used to indicate the presence of on-die stacked + memory. When present this memory bank is used for a high speed + shared memory interface. When not present regular RAM is used. choice prompt "Default Timer" default MSM7X00A_USE_GP_TIMER -- cgit v1.2.3 From cebd3c66e05e0178fdbb0f52d8ddfd677100d6c3 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Wed, 30 Dec 2009 08:54:03 -0800 Subject: Move AMSS version selection. --- arch/arm/mach-msm/Kconfig | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index 7ea8228423b0..74e050b3b7d1 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -1,25 +1,7 @@ if ARCH_MSM || ARCH_QSD -config MSM_AMSS_VERSION - int - default 6210 if MSM_AMSS_VERSION_6210 - default 6220 if MSM_AMSS_VERSION_6220 - default 6225 if MSM_AMSS_VERSION_6225 - choice - prompt "AMSS modem firmware version" - - default MSM_AMSS_VERSION_6225 - - config MSM_AMSS_VERSION_6210 - bool "6.2.10" - - config MSM_AMSS_VERSION_6220 - bool "6.2.20" - config MSM_AMSS_VERSION_6225 - bool "6.2.20 + New ADSP" -endchoice comment "MSM Board Type" depends on ARCH_MSM @@ -157,6 +139,27 @@ config MSM_STACKED_MEMORY This option is used to indicate the presence of on-die stacked memory. When present this memory bank is used for a high speed shared memory interface. When not present regular RAM is used. + +config MSM_AMSS_VERSION + int + default 6210 if MSM_AMSS_VERSION_6210 + default 6220 if MSM_AMSS_VERSION_6220 + default 6225 if MSM_AMSS_VERSION_6225 + +choice + prompt "AMSS modem firmware version" + + default MSM_AMSS_VERSION_6225 + + config MSM_AMSS_VERSION_6210 + bool "6.2.10" + + config MSM_AMSS_VERSION_6220 + bool "6.2.20" + + config MSM_AMSS_VERSION_6225 + bool "6.2.20 + New ADSP" +endchoice choice prompt "Default Timer" default MSM7X00A_USE_GP_TIMER -- cgit v1.2.3 From 615903dbef05ab72869daa884fa28fae77e6b422 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Wed, 30 Dec 2009 08:57:16 -0800 Subject: Move serial port selection Kconfig option. --- arch/arm/mach-msm/Kconfig | 47 +++++++++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 20 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index 74e050b3b7d1..194112ea76e4 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -3,32 +3,14 @@ if ARCH_MSM || ARCH_QSD choice -comment "MSM Board Type" - depends on ARCH_MSM - -config MSM_DEBUG_UART - int - default 1 if MSM_DEBUG_UART1 - default 2 if MSM_DEBUG_UART2 - default 3 if MSM_DEBUG_UART3 -choice - prompt "Debug UART" - default MSM_DEBUG_UART_NONE - config MSM_DEBUG_UART_NONE - bool "None" - config MSM_DEBUG_UART1 - bool "UART1" - config MSM_DEBUG_UART2 - bool "UART2" - config MSM_DEBUG_UART3 - bool "UART3" -endchoice +comment "MSM Board Type" + depends on ARCH_MSM config MACH_HALIBUT depends on ARCH_MSM @@ -160,6 +142,31 @@ choice config MSM_AMSS_VERSION_6225 bool "6.2.20 + New ADSP" endchoice + +config MSM_DEBUG_UART + int + default 1 if MSM_DEBUG_UART1 + default 2 if MSM_DEBUG_UART2 + default 3 if MSM_DEBUG_UART3 + +choice + prompt "Debug UART" + + default MSM_DEBUG_UART_NONE + + config MSM_DEBUG_UART_NONE + bool "None" + + config MSM_DEBUG_UART1 + bool "UART1" + + config MSM_DEBUG_UART2 + bool "UART2" + + config MSM_DEBUG_UART3 + bool "UART3" +endchoice + choice prompt "Default Timer" default MSM7X00A_USE_GP_TIMER -- cgit v1.2.3 From 16e85f4d33b44e2486fdb697dcb5666b7fbb26e6 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Wed, 30 Dec 2009 08:59:28 -0800 Subject: Move HTC headset kconfig. --- arch/arm/mach-msm/Kconfig | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index 194112ea76e4..81058250223d 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -68,14 +68,6 @@ config MACH_SAPPHIRE default n bool "Sapphire" -config HTC_HEADSET - tristate "HTC 2 Wire detection driver" - default n - help - Provides support for detecting HTC 2 wire devices, such as wired - headset, on the trout platform. Can be used with the msm serial - debugger, but not with serial console. - config TROUT_BATTCHG depends on MACH_TROUT && POWER_SUPPLY default y @@ -296,6 +288,14 @@ config MSM_SUSPEND_STATS_FIRST_BUCKET endif # MSM_IDLE_STATS +config HTC_HEADSET + tristate "HTC 2 Wire detection driver" + default n + help + Provides support for detecting HTC 2 wire devices, such as wired + headset, on the trout platform. Can be used with the msm serial + debugger, but not with serial console. + config QSD_SVS bool "QSD Static Voltage Scaling" depends on (MACH_QSD8X50_SURF || MACH_QSD8X50_FFA || MACH_QSD8X50_COMET) -- cgit v1.2.3 From 0b8292cfe82ed895c5591b8375ef9608b65a6909 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Wed, 30 Dec 2009 09:00:34 -0800 Subject: Move trout bettery charger option. --- arch/arm/mach-msm/Kconfig | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index 81058250223d..0d93c43b0fe8 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -68,11 +68,6 @@ config MACH_SAPPHIRE default n bool "Sapphire" -config TROUT_BATTCHG - depends on MACH_TROUT && POWER_SUPPLY - default y - bool "Trout battery / charger driver" - config HTC_PWRSINK depends on MSM_SMD default n @@ -296,6 +291,11 @@ config HTC_HEADSET headset, on the trout platform. Can be used with the msm serial debugger, but not with serial console. +config TROUT_BATTCHG + depends on MACH_TROUT && POWER_SUPPLY + default y + bool "Trout battery / charger driver" + config QSD_SVS bool "QSD Static Voltage Scaling" depends on (MACH_QSD8X50_SURF || MACH_QSD8X50_FFA || MACH_QSD8X50_COMET) -- cgit v1.2.3 From 073d2bf3e1c4b336bdcd6308c4ca2b6e3c806b96 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Wed, 30 Dec 2009 09:03:30 -0800 Subject: Move HTC power sink Kconfig option. --- arch/arm/mach-msm/Kconfig | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index 0d93c43b0fe8..648c859dd1c5 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -68,11 +68,6 @@ config MACH_SAPPHIRE default n bool "Sapphire" -config HTC_PWRSINK - depends on MSM_SMD - default n - bool "HTC Power Sink Driver" - comment "QSD Board Type" depends on ARCH_QSD @@ -296,6 +291,11 @@ config TROUT_BATTCHG default y bool "Trout battery / charger driver" +config HTC_PWRSINK + depends on MSM_SMD + default n + bool "HTC Power Sink Driver" + config QSD_SVS bool "QSD Static Voltage Scaling" depends on (MACH_QSD8X50_SURF || MACH_QSD8X50_FFA || MACH_QSD8X50_COMET) -- cgit v1.2.3 From 189ed52f349f6189a21c78b220ad5d88ff3cc72c Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Wed, 30 Dec 2009 09:08:51 -0800 Subject: Add new naming w/ 7x00 Kconfig board changes. --- arch/arm/mach-msm/Kconfig | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index 648c859dd1c5..c539479dedf1 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -1,20 +1,28 @@ -if ARCH_MSM || ARCH_QSD +if ARCH_MSM choice + prompt "MSM SoC Type" + default ARCH_MSM7X00A +config ARCH_MSM7X01A + bool "MSM7x00A / MSM7x01A" + select ARCH_MSM_ARM11 + select CPU_V6 +endchoice +config ARCH_MSM_ARM11 + bool -comment "MSM Board Type" - depends on ARCH_MSM +menu "MSM Board Selection" config MACH_HALIBUT - depends on ARCH_MSM select CPU_V6 + depends on ARCH_MSM7X01A depends on MSM_STACKED_MEMORY default y bool "Halibut Board (QCT SURF7201A)" @@ -22,7 +30,7 @@ config MACH_HALIBUT Support for the Qualcomm SURF7201A eval board. config MACH_MSM7201A_SURF - depends on ARCH_MSM + depends on ARCH_MSM7X01A depends on MSM_STACKED_MEMORY default y bool "MSM7201A SURF" @@ -30,7 +38,7 @@ config MACH_MSM7201A_SURF Support for the Qualcomm MSM7201A SURF eval board. config MACH_MSM7201A_FFA - depends on ARCH_MSM + depends on ARCH_MSM7X01A depends on MSM_STACKED_MEMORY default y bool "MSM7201A FFA" @@ -39,6 +47,7 @@ config MACH_MSM7201A_FFA config MACH_TROUT select CPU_V6 + depends on ARCH_MSM7X01A depends on MSM_STACKED_MEMORY default y bool "HTC Dream (aka trout)" @@ -64,7 +73,7 @@ config MACH_MSM7X27_FFA # config TROUT_H2W config MACH_SAPPHIRE - depends on ARCH_MSM + depends on ARCH_MSM7X01A default n bool "Sapphire" -- cgit v1.2.3 From e50884ae1503916f86afa90168c4513b152f88f6 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Wed, 30 Dec 2009 09:10:33 -0800 Subject: Add Kconfig options for 7x27 board types. --- arch/arm/mach-msm/Kconfig | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index c539479dedf1..8306e3ee3d68 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -9,6 +9,10 @@ config ARCH_MSM7X01A select ARCH_MSM_ARM11 select CPU_V6 +config ARCH_MSM7X27 + bool "MSM7x27" + select ARCH_MSM_ARM11 + select CPU_V6 @@ -55,7 +59,7 @@ config MACH_TROUT Support for the HTC Dream, T-Mobile G1, Android ADP1 devices. config MACH_MSM7X27_SURF - depends on ARCH_MSM + depends on ARCH_MSM7X27 depends on !MSM_STACKED_MEMORY default y bool "MSM7x27 SURF" @@ -63,7 +67,7 @@ config MACH_MSM7X27_SURF Support for the Qualcomm MSM7x27 SURF eval board. config MACH_MSM7X27_FFA - depends on ARCH_MSM + depends on ARCH_MSM7X27 depends on !MSM_STACKED_MEMORY default y bool "MSM7x27 FFA" -- cgit v1.2.3 From ff6e78c364723f19e9a152d9158816afb5999a47 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Wed, 30 Dec 2009 09:15:00 -0800 Subject: Update QSD 8k board support Kconfig options. --- arch/arm/mach-msm/Kconfig | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index 8306e3ee3d68..5d7db1ea2d09 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -15,11 +15,17 @@ config ARCH_MSM7X27 select CPU_V6 +config ARCH_QSD8X50 + bool "QSD8X50" + select ARCH_MSM_SCORPION + select CPU_V7 endchoice config ARCH_MSM_ARM11 bool +config ARCH_MSM_SCORPION + bool menu "MSM Board Selection" @@ -81,11 +87,8 @@ config MACH_SAPPHIRE default n bool "Sapphire" -comment "QSD Board Type" - depends on ARCH_QSD - config MACH_QSD8X50_SURF - depends on ARCH_QSD + depends on ARCH_QSD8X50 depends on MSM_STACKED_MEMORY default y bool "QSD8x50 SURF" @@ -93,7 +96,7 @@ config MACH_QSD8X50_SURF Support for the Qualcomm QSD8x50 SURF eval board. config MACH_QSD8X50_FFA - depends on ARCH_QSD + depends on ARCH_QSD8X50 depends on MSM_STACKED_MEMORY default y bool "QSD8x50 FFA" @@ -101,13 +104,14 @@ config MACH_QSD8X50_FFA Support for the Qualcomm QSD8x50 FFA eval board. config MACH_QSD8X50_COMET - depends on ARCH_QSD + depends on ARCH_QSD8X50 depends on MSM_STACKED_MEMORY default n bool "QSD8x50 Comet" help Support for the Qualcomm Comet eval board. +endmenu config MSM_STACKED_MEMORY bool "Stacked Memory" -- cgit v1.2.3 From bd384730f47fa6e41157202ed384138223ecf956 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Thu, 31 Dec 2009 11:39:27 -0800 Subject: msm: select VERIFY_PERMISSION_FAULT on qsd8x50 Signed-off-by: Daniel Walker --- arch/arm/mach-msm/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index 5d7db1ea2d09..f3cdcf42ff1b 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -18,6 +18,7 @@ config ARCH_MSM7X27 config ARCH_QSD8X50 bool "QSD8X50" select ARCH_MSM_SCORPION + select VERIFY_PERMISSION_FAULT select CPU_V7 endchoice -- cgit v1.2.3 From d785859b95e74c41902169a2d021ea53121b33ef Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Wed, 30 Dec 2009 09:16:01 -0800 Subject: Add 7x30 Kconfig options. --- arch/arm/mach-msm/Kconfig | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index f3cdcf42ff1b..b7fab7fdf0a3 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -14,6 +14,10 @@ config ARCH_MSM7X27 select ARCH_MSM_ARM11 select CPU_V6 +config ARCH_MSM7X30 + bool "MSM7x30" + select ARCH_MSM_SCORPION + select CPU_V7 config ARCH_QSD8X50 bool "QSD8X50" -- cgit v1.2.3 From c7c4c935ba9aef2e83b2f485c97d412a9da86cde Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Wed, 30 Dec 2009 09:23:32 -0800 Subject: New naming for shared memory interface version kconfig option. --- arch/arm/mach-msm/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index b7fab7fdf0a3..947ac070b293 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -343,8 +343,8 @@ config MSM_SMD choice prompt "MSM Shared memory interface version" depends on MSM_SMD - default MSM_SMD_PKG3 if ARCH_MSM - default MSM_SMD_PKG4 if ARCH_QSD + default MSM_SMD_PKG3 if ARCH_MSM_ARM11 + default MSM_SMD_PKG4 if ARCH_MSM_SCORPION config MSM_SMD_PKG3 bool "Package 3" -- cgit v1.2.3 From 7c9295b955eff8e5fd11c966c38dd81a86402ca8 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Wed, 30 Dec 2009 09:24:21 -0800 Subject: Add Kconfig name update for MSM N-way --- arch/arm/mach-msm/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index 947ac070b293..fd42ed16d062 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -354,7 +354,7 @@ choice endchoice config MSM_N_WAY_SMD - depends on (MSM_SMD && (ARCH_QSD || MACH_MSM7X27_SURF || MACH_MSM7X27_FFA)) + depends on (MSM_SMD && (ARCH_MSM_SCORPION || ARCH_MSM7X27)) default y bool "MSM N-WAY SMD support" help -- cgit v1.2.3 From 156f36fbc3b7ca08ac6e8826edd7d8c2ff321b0d Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Wed, 30 Dec 2009 09:30:01 -0800 Subject: n-way Kconfig changes. --- arch/arm/mach-msm/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index fd42ed16d062..3c9bdd2c01d1 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -362,7 +362,7 @@ config MSM_N_WAY_SMD normal APPS-MODEM SMD communication. config MSM_N_WAY_SMSM - depends on (MSM_SMD && (ARCH_QSD || MACH_MSM7X27_SURF || MACH_MSM7X27_FFA)) + depends on (MSM_SMD && (ARCH_MSM_SCORPION || ARCH_MSM7X27)) default y bool "MSM N-WAY SMSM support" help -- cgit v1.2.3 From e74fc5c38688df10a1e443d0e01de5367449284c Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Wed, 30 Dec 2009 09:30:31 -0800 Subject: Dal rpc kconfig changes. --- arch/arm/mach-msm/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index 3c9bdd2c01d1..e82eb8602ff1 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -410,7 +410,7 @@ config MSM_RPCSERVER_HANDSET config MSM_DALRPC bool "DAL RPC support" - depends on ARCH_QSD + depends on ARCH_MSM_SCORPION default y help Supports RPC calls to DAL devices on remote processor cores. -- cgit v1.2.3 From 679e6661b14e9acb6b4c31d37c4d28d933bdd6f1 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Wed, 30 Dec 2009 09:31:02 -0800 Subject: DMA test module Kconfig changes. --- arch/arm/mach-msm/Kconfig | 1 - 1 file changed, 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index e82eb8602ff1..6f3ca954e41e 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -470,7 +470,6 @@ config MSM_VREG_SWITCH_INVERTED config MSM_DMA_TEST tristate "MSM DMA test module" - depends on (ARCH_MSM || ARCH_QSD) default m help Intended to be compiled as a module. Provides a device node -- cgit v1.2.3 From c6fad6f5e289ea1b91f86e0c898bb19920f1c7b2 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Wed, 30 Dec 2009 09:34:13 -0800 Subject: QSD audio Kconfig changes. --- arch/arm/mach-msm/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index 6f3ca954e41e..b5b6a158a4cf 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -488,7 +488,7 @@ config WIFI_MEM_PREALLOC config QSD_AUDIO bool "QSD audio" - depends on (ARCH_QSD && MSM_DALRPC) + depends on (ARCH_MSM_SCORPION && MSM_DALRPC) default y help Provides PCM, MP3, and AAC audio playback. -- cgit v1.2.3 From d1d31efb0da271577e67700b9b5193658cc2d578 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Wed, 30 Dec 2009 09:35:11 -0800 Subject: Update surf gpio keypad kconfig. --- arch/arm/mach-msm/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index b5b6a158a4cf..039ef0eed643 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -509,7 +509,7 @@ config AUDIO_ENHANCED_AAC_PLUS config SURF_FFA_GPIO_KEYPAD bool "MSM SURF/FFA GPIO keypad" - depends on (ARCH_QSD || ARCH_MSM) && INPUT_GPIO = "y" + depends on INPUT_GPIO = "y" default y help Select if the GPIO keypad is attached. -- cgit v1.2.3 From 00bf34c62a34da5f90c24209c384be9c8ab714f3 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Wed, 30 Dec 2009 09:37:20 -0800 Subject: Drop unused trout h2wKconfig option. --- arch/arm/mach-msm/Kconfig | 2 -- 1 file changed, 2 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index 039ef0eed643..024713ffa411 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -85,8 +85,6 @@ config MACH_MSM7X27_FFA help Support for the Qualcomm MSM7x27 FFA eval board. -# config TROUT_H2W - config MACH_SAPPHIRE depends on ARCH_MSM7X01A default n -- cgit v1.2.3 From 4dcaa0e0a70f8e62b439dd5185f74b365b1e7b40 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Tue, 29 Dec 2009 11:59:36 -0800 Subject: arch/arm/mach-msm/Makefile --- arch/arm/mach-msm/Makefile | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 44db40cbb6e6..059da63bb9eb 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -12,10 +12,10 @@ obj-y += socinfo.o obj-y += cpufreq.o obj-y += nohlt.o -obj-$(CONFIG_ARCH_MSM) += acpuclock.o obj-$(CONFIG_ARCH_MSM) += pmic.o -obj-$(CONFIG_ARCH_QSD) += acpuclock-8x50.o sirc.o obj-$(CONFIG_ARCH_QSD) += pmic.o +obj-$(CONFIG_ARCH_MSM_ARM11) += acpuclock.o +obj-$(CONFIG_ARCH_MSM_SCORPION) += acpuclock-8x50.o sirc.o obj-$(CONFIG_CPU_V6) += idle-v6.o obj-$(CONFIG_CPU_V7) += idle-v7.o @@ -41,8 +41,9 @@ obj-$(CONFIG_MSM_DMA_TEST) += dma_test.o obj-$(CONFIG_SURF_FFA_GPIO_KEYPAD) += keypad-surf-ffa.o obj-$(CONFIG_MACH_TROUT) += board-dream.o -obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o -obj-$(CONFIG_MACH_MSM7201A_FFA) += board-halibut.o +obj-$(CONFIG_ARCH_MSM7X01A) += board-halibut.o +obj-$(CONFIG_MACH_TROUT) += board-trout.o board-trout-gpio.o +obj-$(CONFIG_MACH_TROUT) += board-trout-keypad.o board-trout-panel.o obj-$(CONFIG_MACH_TROUT) += htc_akm_cal.o htc_wifi_nvs.o htc_acoustic.o obj-$(CONFIG_MACH_TROUT) += board-trout-mmc.o board-trout-wifi.o obj-$(CONFIG_MACH_QSD8X50_SURF) += board-qsd8x50.o @@ -51,8 +52,7 @@ obj-$(CONFIG_MACH_QSD8X50_COMET) += board-comet.o obj-$(CONFIG_TROUT_H2W) += board-trout-h2w.o obj-$(CONFIG_TROUT_BATTCHG) += htc_battery.o obj-$(CONFIG_TROUT_PWRSINK) += htc_pwrsink.o -obj-$(CONFIG_MACH_MSM7X27_SURF) += board-msm7x27.o -obj-$(CONFIG_MACH_MSM7X27_FFA) += board-msm7x27.o +obj-$(CONFIG_ARCH_MSM7X27) += board-msm7x27.o obj-$(CONFIG_QSD_AUDIO) += qdsp6/ -- cgit v1.2.3 From dcf224816c1b36724c5d21953de8884a867fc9f6 Mon Sep 17 00:00:00 2001 From: "Rhee, C. Joon" Date: Wed, 6 May 2009 17:36:54 -0700 Subject: [ARM] msm: remove msme2 vreg control msme2 needs to be controlled through pmic instead of vreg api. pmic_lp_mode_control() api is needed for msme2 power line control. Signed-off-by: Rhee, C. Joon --- arch/arm/mach-msm/board-qsd8x50.c | 1 - 1 file changed, 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/board-qsd8x50.c b/arch/arm/mach-msm/board-qsd8x50.c index 4bfd7ef84245..05c84ac5a4d5 100644 --- a/arch/arm/mach-msm/board-qsd8x50.c +++ b/arch/arm/mach-msm/board-qsd8x50.c @@ -451,7 +451,6 @@ static void msm_fb_mddi_power_save(int on) } msm_fb_vreg_config("gp5", flag_on); - msm_fb_vreg_config("msme2", !flag_on); msm_fb_vreg_config("boost", flag_on); if (flag_on && machine_is_qsd8x50_ffa()) { -- cgit v1.2.3 From 88b0b8805bab9f99261c254009a2db1aaaad7650 Mon Sep 17 00:00:00 2001 From: Saravana Kannan Date: Fri, 8 May 2009 20:18:56 -0700 Subject: [ARM] msm: acpuclock: Rewrite runtime clock plan selection. The run time fix up of a single ACPU clock plan table is difficult to understand for many people and also couldn't handle certain clock plans elegantly. Make clock plan selection code more maintainable by using a separate, mostly-static table for each supported clock plan. Minor fixups are still used if the fix ups are simple and avoid adding several tables. Signed-off-by: Saravana Kannan --- arch/arm/mach-msm/acpuclock.c | 397 +++++++++++++++++++----------------------- 1 file changed, 178 insertions(+), 219 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/acpuclock.c b/arch/arm/mach-msm/acpuclock.c index 8e19d8531ae9..3ef81c5fde4e 100644 --- a/arch/arm/mach-msm/acpuclock.c +++ b/arch/arm/mach-msm/acpuclock.c @@ -72,13 +72,6 @@ struct shared_pll_control { } pll[PLL_BASE + ACPU_PLL_END]; }; -static remote_spinlock_t pll_lock; -static struct shared_pll_control *pll_control; - -static struct clock_state drv_state = { 0 }; - -static void __init acpuclk_init(void); - struct clkctl_acpu_speed { unsigned int use_for_scaling; unsigned int a11clk_khz; @@ -87,59 +80,175 @@ struct clkctl_acpu_speed { unsigned int a11clk_src_div; unsigned int ahbclk_khz; unsigned int ahbclk_div; - int vdd; unsigned int axiclk_khz; + int vdd; unsigned long lpj; /* loops_per_jiffy */ /* Index in acpu_freq_tbl[] for steppings. */ short down; short up; }; +static remote_spinlock_t pll_lock; +static struct shared_pll_control *pll_control; +static struct clock_state drv_state = { 0 }; +static struct clkctl_acpu_speed *acpu_freq_tbl; + +static void __init acpuclk_init(void); + /* - * ACPU speed table. Complete table is shown but certain speeds are commented - * out to optimized speed switching. Initalize loops_per_jiffy to 0. + * ACPU freq tables used for different PLLs frequency combinations. The + * correct table is selected during init. * * Table stepping up/down is calculated during boot to choose the largest * frequency jump that's less than max_speed_delta_khz and preferrably on the * same PLL. If no frequencies using the same PLL are within * max_speed_delta_khz, then the farthest frequency that is within * max_speed_delta_khz is chosen. - * - * The table is initialized with the most common clock plan. Table fix up is - * done during boot up to match the actual clock plan supported by the - * hardware. */ -#if (1) -static struct clkctl_acpu_speed acpu_freq_tbl[] = { - { 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 0, 30720, 0, 0, 8 }, - { 0, 61440, ACPU_PLL_0, 4, 3, 61440, 0, 0, 30720, 0, 0, 8 }, - { 0, 81920, ACPU_PLL_0, 4, 2, 40960, 1, 0, 61440, 0, 0, 8 }, - { 0, 96000, ACPU_PLL_1, 1, 7, 48000, 1, 0, 61440, 0, 0, 9 }, - { 1, 122880, ACPU_PLL_0, 4, 1, 61440, 1, 3, 61440, 0, 0, 8 }, - { 0, 128000, ACPU_PLL_1, 1, 5, 64000, 1, 3, 61440, 0, 0, 12 }, - { 0, 176000, ACPU_PLL_2, 2, 5, 88000, 1, 3, 61440, 0, 0, 11 }, - { 0, 192000, ACPU_PLL_1, 1, 3, 64000, 2, 3, 61440, 0, 0, 12 }, - { 1, 245760, ACPU_PLL_0, 4, 0, 81920, 2, 4, 61440, 0, 0, 12 }, - { 1, 256000, ACPU_PLL_1, 1, 2, 128000, 1, 5, 128000, 0, 0, 12 }, - { 0, 264000, ACPU_PLL_2, 2, 3, 88000, 2, 5, 128000, 0, 6, 13 }, - { 0, 352000, ACPU_PLL_2, 2, 2, 88000, 3, 5, 128000, 0, 6, 13 }, - { 1, 384000, ACPU_PLL_1, 1, 1, 128000, 2, 6, 128000, 0, 5, -1 }, - { 1, 528000, ACPU_PLL_2, 2, 1, 132000, 3, 7, 128000, 0, 11, -1 }, + +/* 7x01/7x25 normal with GSM capable modem */ +static struct clkctl_acpu_speed pll0_245_pll1_768_pll2_1056[] = { + { 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 30720, 0 }, + { 1, 122880, ACPU_PLL_0, 4, 1, 61440, 1, 61440, 3 }, + { 0, 128000, ACPU_PLL_1, 1, 5, 64000, 1, 61440, 3 }, + { 0, 176000, ACPU_PLL_2, 2, 5, 88000, 1, 61440, 3 }, + { 1, 245760, ACPU_PLL_0, 4, 0, 81920, 2, 61440, 4 }, + { 1, 256000, ACPU_PLL_1, 1, 2, 128000, 1, 128000, 5 }, + { 0, 352000, ACPU_PLL_2, 2, 2, 88000, 3, 128000, 5 }, + { 1, 384000, ACPU_PLL_1, 1, 1, 128000, 2, 128000, 6 }, + { 1, 528000, ACPU_PLL_2, 2, 1, 132000, 3, 128000, 7 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, }; -#else /* Table of freq we currently use. */ -static struct clkctl_acpu_speed acpu_freq_tbl[] = { - { 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 0, 30720, 0, 0, 4 }, - { 1, 122880, ACPU_PLL_0, 4, 1, 61440, 1, 3, 61440, 0, 0, 4 }, - { 1, 128000, ACPU_PLL_1, 1, 5, 64000, 1, 3, 61440, 0, 0, 6 }, - { 0, 176000, ACPU_PLL_2, 2, 5, 88000, 1, 3, 61440, 0, 0, 5 }, - { 1, 245760, ACPU_PLL_0, 4, 0, 81920, 2, 4, 61440, 0, 0, 5 }, - { 0, 352000, ACPU_PLL_2, 2, 2, 88000, 3, 5, 128000, 0, 3, 7 }, - { 1, 384000, ACPU_PLL_1, 1, 1, 128000, 2, 6, 128000, 0, 2, -1 }, - { 1, 528000, ACPU_PLL_2, 2, 1, 132000, 3, 7, 128000, 0, 5, -1 }, + +/* 7x01/7x25 normal with CDMA-only modem */ +static struct clkctl_acpu_speed pll0_196_pll1_768_pll2_1056[] = { + { 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 24576, 0 }, + { 1, 98304, ACPU_PLL_0, 4, 1, 49152, 1, 24576, 3 }, + { 0, 128000, ACPU_PLL_1, 1, 5, 64000, 1, 24576, 3 }, + { 0, 176000, ACPU_PLL_2, 2, 5, 88000, 1, 24576, 3 }, + { 1, 196608, ACPU_PLL_0, 4, 0, 65536, 2, 24576, 4 }, + { 1, 256000, ACPU_PLL_1, 1, 2, 128000, 1, 128000, 5 }, + { 0, 352000, ACPU_PLL_2, 2, 2, 88000, 3, 128000, 5 }, + { 1, 384000, ACPU_PLL_1, 1, 1, 128000, 2, 128000, 6 }, + { 1, 528000, ACPU_PLL_2, 2, 1, 132000, 3, 128000, 7 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, }; -#endif + +/* 7x01/7x25 turbo with GSM capable modem */ +static struct clkctl_acpu_speed pll0_245_pll1_960_pll2_1056[] = { + { 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 30720, 0 }, + { 0, 120000, ACPU_PLL_1, 1, 7, 60000, 1, 61440, 3 }, + { 1, 122880, ACPU_PLL_0, 4, 1, 61440, 1, 61440, 3 }, + { 0, 176000, ACPU_PLL_2, 2, 5, 88000, 1, 61440, 3 }, + { 1, 245760, ACPU_PLL_0, 4, 0, 81920, 2, 61440, 4 }, + { 1, 320000, ACPU_PLL_1, 1, 2, 107000, 2, 120000, 5 }, + { 0, 352000, ACPU_PLL_2, 2, 2, 88000, 3, 120000, 5 }, + { 1, 480000, ACPU_PLL_1, 1, 1, 120000, 3, 120000, 6 }, + { 1, 528000, ACPU_PLL_2, 2, 1, 132000, 3, 122880, 7 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +}; + +/* 7x01/7x25 turbo with CDMA-only modem */ +static struct clkctl_acpu_speed pll0_196_pll1_960_pll2_1056[] = { + { 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 24576, 0 }, + { 1, 98304, ACPU_PLL_0, 4, 1, 49152, 1, 24576, 3 }, + { 0, 120000, ACPU_PLL_1, 1, 7, 60000, 1, 24576, 3 }, + { 0, 176000, ACPU_PLL_2, 2, 5, 88000, 1, 24576, 3 }, + { 1, 196608, ACPU_PLL_0, 4, 0, 65536, 2, 24576, 4 }, + { 1, 320000, ACPU_PLL_1, 1, 2, 107000, 2, 120000, 5 }, + { 0, 352000, ACPU_PLL_2, 2, 2, 88000, 3, 120000, 5 }, + { 1, 480000, ACPU_PLL_1, 1, 1, 120000, 3, 120000, 6 }, + { 1, 528000, ACPU_PLL_2, 2, 1, 132000, 3, 120000, 7 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +}; + +/* 7x27 normal with GSM capable modem */ +static struct clkctl_acpu_speed pll0_245_pll1_960_pll2_1200[] = { + { 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 30720, 0 }, + { 0, 120000, ACPU_PLL_1, 1, 7, 60000, 1, 61440, 3 }, + { 1, 122880, ACPU_PLL_0, 4, 1, 61440, 1, 61440, 3 }, + { 0, 200000, ACPU_PLL_2, 2, 5, 66667, 2, 61440, 4 }, + { 1, 245760, ACPU_PLL_0, 4, 0, 122880, 1, 122880, 4 }, + { 1, 320000, ACPU_PLL_1, 1, 2, 160000, 1, 122880, 5 }, + { 0, 400000, ACPU_PLL_2, 2, 2, 133333, 2, 122880, 5 }, + { 1, 480000, ACPU_PLL_1, 1, 1, 160000, 2, 122880, 6 }, + { 1, 600000, ACPU_PLL_2, 2, 1, 200000, 2, 122880, 7 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +}; + +/* 7x27 normal with CDMA-only modem */ +static struct clkctl_acpu_speed pll0_196_pll1_960_pll2_1200[] = { + { 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 24576, 0 }, + { 1, 98304, ACPU_PLL_0, 4, 1, 98304, 0, 49152, 3 }, + { 0, 120000, ACPU_PLL_1, 1, 7, 60000, 1, 49152, 3 }, + { 1, 196608, ACPU_PLL_0, 4, 0, 65536, 2, 98304, 4 }, + { 0, 200000, ACPU_PLL_2, 2, 5, 66667, 2, 98304, 4 }, + { 1, 320000, ACPU_PLL_1, 1, 2, 160000, 1, 120000, 5 }, + { 0, 400000, ACPU_PLL_2, 2, 2, 133333, 2, 120000, 5 }, + { 1, 480000, ACPU_PLL_1, 1, 1, 160000, 2, 120000, 6 }, + { 1, 600000, ACPU_PLL_2, 2, 1, 200000, 2, 120000, 7 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +}; + +/* 7x27 normal with GSM capable modem - PLL0 and PLL1 swapped */ +static struct clkctl_acpu_speed pll0_960_pll1_245_pll2_1200[] = { + { 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 30720, 0 }, + { 0, 120000, ACPU_PLL_0, 4, 7, 60000, 1, 61440, 3 }, + { 1, 122880, ACPU_PLL_1, 1, 1, 61440, 1, 61440, 3 }, + { 0, 200000, ACPU_PLL_2, 2, 5, 66667, 2, 61440, 4 }, + { 1, 245760, ACPU_PLL_1, 1, 0, 122880, 1, 122880, 4 }, + { 1, 320000, ACPU_PLL_0, 4, 2, 160000, 1, 122880, 5 }, + { 0, 400000, ACPU_PLL_2, 2, 2, 133333, 2, 122880, 5 }, + { 1, 480000, ACPU_PLL_0, 4, 1, 160000, 2, 122880, 6 }, + { 1, 600000, ACPU_PLL_2, 2, 1, 200000, 2, 122880, 7 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +}; + +/* 7x27 normal with CDMA-only modem - PLL0 and PLL1 swapped */ +static struct clkctl_acpu_speed pll0_960_pll1_196_pll2_1200[] = { + { 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 24576, 0 }, + { 1, 98304, ACPU_PLL_1, 1, 1, 98304, 0, 49152, 3 }, + { 0, 120000, ACPU_PLL_0, 4, 7, 60000, 1, 49152, 3 }, + { 1, 196608, ACPU_PLL_1, 1, 0, 65536, 2, 98304, 4 }, + { 0, 200000, ACPU_PLL_2, 2, 5, 66667, 2, 98304, 4 }, + { 1, 320000, ACPU_PLL_0, 4, 2, 160000, 1, 120000, 5 }, + { 0, 400000, ACPU_PLL_2, 2, 2, 133333, 2, 120000, 5 }, + { 1, 480000, ACPU_PLL_0, 4, 1, 160000, 2, 120000, 6 }, + { 1, 600000, ACPU_PLL_2, 2, 1, 200000, 2, 120000, 7 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +}; + +#define PLL_196_MHZ 10 +#define PLL_245_MHZ 12 +#define PLL_491_MHZ 25 +#define PLL_768_MHZ 40 +#define PLL_960_MHZ 50 +#define PLL_1056_MHZ 55 +#define PLL_1200_MHZ 62 + +#define PLL_CONFIG(m0, m1, m2) { \ + PLL_##m0##_MHZ, PLL_##m1##_MHZ, PLL_##m2##_MHZ, \ + pll0_##m0##_pll1_##m1##_pll2_##m2 \ +} + +struct pll_freq_tbl_map { + unsigned int pll0_l; + unsigned int pll1_l; + unsigned int pll2_l; + struct clkctl_acpu_speed *tbl; +}; + +static struct pll_freq_tbl_map acpu_freq_tbl_list[] = { + PLL_CONFIG(196, 768, 1056), + PLL_CONFIG(245, 768, 1056), + PLL_CONFIG(196, 960, 1056), + PLL_CONFIG(245, 960, 1056), + PLL_CONFIG(196, 960, 1200), + PLL_CONFIG(245, 960, 1200), + PLL_CONFIG(960, 196, 1200), + PLL_CONFIG(960, 245, 1200), + { 0, 0, 0, 0 } +}; #ifdef CONFIG_CPU_FREQ_MSM static struct cpufreq_frequency_table freq_table[20]; @@ -517,136 +626,17 @@ uint32_t acpuclk_get_switch_time(void) * Clock driver initialization *---------------------------------------------------------------------------*/ -static int __init cmp_acpu_speed(const void *a, const void *b) -{ - return ((struct clkctl_acpu_speed *)a)->a11clk_khz - - ((struct clkctl_acpu_speed *)b)->a11clk_khz; -} - #define DIV2REG(n) ((n)-1) #define REG2DIV(n) ((n)+1) #define SLOWER_BY(div, factor) div = DIV2REG(REG2DIV(div) * factor) -static void __init pll0_a11_ahb_fixup(unsigned long pll0_l, - struct clkctl_acpu_speed *t) -{ -#define PLL0_196608_KHZ 10 -#define PLL0_245760_KHZ 12 -#define PLL0_491520_KHZ 25 -#define PLL0_983000_KHZ 51 - - switch (pll0_l) { - case PLL0_983000_KHZ: - SLOWER_BY(t->a11clk_src_div, 4); - break; - case PLL0_491520_KHZ: - SLOWER_BY(t->a11clk_src_div, 2); - break; - case PLL0_245760_KHZ: - /* Initialization correct except for 7x27. */ - if (cpu_is_msm7x27() && t->a11clk_khz == 245760) { - t->ahbclk_div--; - t->ahbclk_khz = 122880; - } - break; - case PLL0_196608_KHZ: - t->a11clk_khz = 196608 / REG2DIV(t->a11clk_src_div); - switch (REG2DIV(t->a11clk_src_div)) { - case 4: /* 49.152 MHz */ - t->ahbclk_khz = t->a11clk_khz; - break; - case 3: /* 65.536 MHz */ - t->ahbclk_khz = t->a11clk_khz; - t->ahbclk_div = DIV2REG(1); - break; - case 2: /* 98.304 MHz */ - /* TODO: Increase AHB freq for sRoc - * and Roc 2.0 */ - t->ahbclk_khz = t->a11clk_khz >> 1; - break; - case 1: /* 196.608 MHz */ - /* TODO: Increase AHB freq for sRoc - * and Roc 2.0 */ - t->ahbclk_khz = t->a11clk_khz / 3; - break; - } - break; - default: - printk(KERN_CRIT "Unknown PLL0 speed.\n"); - BUG(); - break; - } -} - -static void __init pll1_a11_ahb_fixup(unsigned long pll1_l, - struct clkctl_acpu_speed *t) -{ -#define PLL1_768000_KHZ 40 -#define PLL1_960000_KHZ 50 - - switch (pll1_l) { - case PLL1_960000_KHZ: - t->a11clk_khz = 960000 / REG2DIV(t->a11clk_src_div); - /* XXX: Necessary for AHB freq of 128 MHz, but not - * necessary for lower AHB freqs. All ACPU freqs used - * for scaling have AHB of 128 MHz, so unconditional - * increment might be okay. - * - * 7x27 is an exception because running AHB at 160 MHz - * is meaningful (because it can run AXI at 160 MHz at - * lower CPU frequencies without impacting power - * consumption). - */ - if (!cpu_is_msm7x27()) - t->ahbclk_div++; - t->ahbclk_khz = t->a11clk_khz / REG2DIV(t->ahbclk_div); - break; - case PLL1_768000_KHZ: - /* Initialization correct. */ - break; - default: - printk(KERN_CRIT "Unknown PLL1 speed.\n"); - BUG(); - break; - } -} - -static void __init pll2_a11_ahb_fixup(unsigned long pll2_l, - struct clkctl_acpu_speed *t) -{ -#define PLL2_960000_KHZ 50 -#define PLL2_1056000_KHZ 55 -#define PLL2_1200000_KHZ 62 - - switch (pll2_l) { - case PLL2_1200000_KHZ: - t->a11clk_khz = 1200000 / REG2DIV(t->a11clk_src_div); - if (t->ahbclk_div > 2) - t->ahbclk_div--; - t->ahbclk_khz = t->a11clk_khz / REG2DIV(t->ahbclk_div); - break; - case PLL2_1056000_KHZ: - /* Initialization correct. */ - break; - case PLL2_960000_KHZ: - t->a11clk_khz = 960000 / REG2DIV(t->a11clk_src_div); - if (t->ahbclk_div > 1) - t->ahbclk_div--; - t->ahbclk_khz = t->a11clk_khz / REG2DIV(t->ahbclk_div); - break; - default: - printk(KERN_CRIT "Unknown PLL2 speed.\n"); - BUG(); - break; - } -} - static void __init acpu_freq_tbl_fixup(void) { unsigned long pll0_l, pll1_l, pll2_l; int axi_160mhz = 0, axi_200mhz = 0; + struct pll_freq_tbl_map *lst; struct clkctl_acpu_speed *t; - unsigned int n = 0; + unsigned int pll0_needs_fixup = 0; /* Wait for the PLLs to be initialized and then read their frequency. */ @@ -669,84 +659,53 @@ static void __init acpu_freq_tbl_fixup(void) printk(KERN_INFO "L val: PLL0: %d, PLL1: %d, PLL2: %d\n", (int)pll0_l, (int)pll1_l, (int)pll2_l); - /* No fix up needed. */ - if (pll0_l == PLL0_245760_KHZ && pll1_l == PLL1_768000_KHZ - && pll2_l == PLL2_1056000_KHZ) - goto print_info; - - /* The AXI bus frequency is also based off the PLL frequencies. For - * the AXI bus to be able to run at 160 MHz or 200 MHz, it needs a - * PLL that runs at an integer multiple of that frequency. - */ - axi_160mhz = (pll1_l == PLL1_960000_KHZ || pll2_l == PLL2_960000_KHZ); - axi_200mhz = (pll2_l == PLL2_1200000_KHZ); - - /* Fix the dividers and the allowed clock rates based on the PLL - * frequencies. - * - * The CPU freq is based off the PLL frequencies. So if the actual - * PLL freq is different from the PLL freq assumed in the default - * table, then the dividers are adjusted to run the CPU at - * frequencies closer to the ones in the default table. - * - * The AHB freq is based off the CPU freq. Attempt is made to - * generally keep the AHB freq as close as possible to the AXI bus - * freq. But for each VDD level there is an upper limit for the AHB - * bus freq. Apart from the per VDD upper limit the AHB also has an - * absolute upper limit of 160 MHz. In most cases, these limitations - * would explain why the AHB divider is changed when a PLL freq - * changes. + /* Some configurations run PLL0 twice as fast. Instead of having + * separate tables for this case, we simply fix up the ACPU clock + * source divider since it's a simple fix up. */ - for (t = &acpu_freq_tbl[0]; t->a11clk_khz != 0; t++) { - n++; + if (pll0_l == PLL_491_MHZ) { + pll0_l = PLL_245_MHZ; + pll0_needs_fixup = 1; + } - switch (t->pll) { - case ACPU_PLL_0: - pll0_a11_ahb_fixup(pll0_l, t); - break; - case ACPU_PLL_1: - pll1_a11_ahb_fixup(pll1_l, t); - break; - case ACPU_PLL_2: - pll2_a11_ahb_fixup(pll2_l, t); + /* Select the right table to use. */ + for (lst = acpu_freq_tbl_list; lst->tbl != 0; lst++) { + if (lst->pll0_l == pll0_l && lst->pll1_l == pll1_l + && lst->pll2_l == pll2_l) { + acpu_freq_tbl = lst->tbl; break; } + } - if (pll0_l == PLL0_196608_KHZ && t->a11clk_khz <= 196608) - t->axiclk_khz = 24576; + if (acpu_freq_tbl == NULL) { + pr_crit("Unknown PLL configuration!\n"); + BUG(); + } - if (cpu_is_msm7x27() && t->a11clk_khz == 245760) - t->axiclk_khz = 122880; + /* Fix up PLL0 source divider if necessary. Also, fix up the AXI to + * the max that's supported by the board (RAM used in board). + */ + axi_160mhz = (pll0_l == PLL_960_MHZ || pll1_l == PLL_960_MHZ); + axi_200mhz = (pll2_l == PLL_1200_MHZ); + for (t = &acpu_freq_tbl[0]; t->a11clk_khz != 0; t++) { + if (pll0_needs_fixup && t->pll == ACPU_PLL_0) + SLOWER_BY(t->a11clk_src_div, 2); if (axi_160mhz && drv_state.max_axi_khz >= 160000 && t->ahbclk_khz > 128000) t->axiclk_khz = 160000; if (axi_200mhz && drv_state.max_axi_khz >= 200000 && t->ahbclk_khz > 160000) t->axiclk_khz = 200000; - - /* 128 MHz is derived from PLL1 @ 768 MHz. If PLL1 @ 960 MHz - * then only 120 MHz can be derived from it. */ - if (pll1_l == PLL1_960000_KHZ && t->axiclk_khz == 128000) - t->axiclk_khz = 120000; } - /* The ACPU table is expected to be in ascending order by the rest - * of the code. This is the case after most fix ups. One example - * exception is when PLL1 runs at 960 MHz. In this case the entries - * corresponding to (256 and 264) need to be swapped. - */ - sort(acpu_freq_tbl, n, sizeof(struct clkctl_acpu_speed), - cmp_acpu_speed, NULL); - -print_info: /* The default 7x27 ACPU clock plan supports running the AXI bus at * 200 MHz. So we don't classify it as Turbo mode. */ if (cpu_is_msm7x27()) return; - t = acpu_freq_tbl + n - 1; + t--; if (!axi_160mhz) pr_info("Turbo mode not supported.\n"); else if (t->axiclk_khz == 160000) -- cgit v1.2.3 From 225e5b0a80944458118ad6f2834d3c5cd81aa23b Mon Sep 17 00:00:00 2001 From: "Pfeffer, Zach" Date: Tue, 12 May 2009 12:20:01 -0600 Subject: [ARM] msm: smem_log: Add power log debugfs node Add a debugfs node that dumps the separate logging area used on some modem builds to log power events. Output nothing if the power event logging area is not present. Two nodes are present a raw node and a symbol resolved node. This change necessitated a minor refactoring to allow an arbitrary number of logging areas to be added with ease. Signed-off-by: Zach Pfeffer --- arch/arm/mach-msm/smem_log.c | 301 ++++++++++++++++++++++--------------------- 1 file changed, 153 insertions(+), 148 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/smem_log.c b/arch/arm/mach-msm/smem_log.c index f263c1769a4b..def476ac5795 100644 --- a/arch/arm/mach-msm/smem_log.c +++ b/arch/arm/mach-msm/smem_log.c @@ -115,23 +115,34 @@ struct smem_log_item { #define SMEM_STATIC_LOG_EVENTS_SIZE (sizeof(struct smem_log_item) * \ SMEM_LOG_NUM_STATIC_ENTRIES) +#define SMEM_LOG_NUM_POWER_ENTRIES 2000 +#define SMEM_POWER_LOG_EVENTS_SIZE (sizeof(struct smem_log_item) * \ + SMEM_LOG_NUM_POWER_ENTRIES) + #define SMEM_SPINLOCK_SMEM_LOG 2 #define SMEM_SPINLOCK_STATIC_LOG 5 +/* POWER shares with SMEM_SPINLOCK_SMEM_LOG */ -static struct smem_log_item __iomem *smem_log_events; -static uint32_t __iomem *smem_log_idx; static remote_spinlock_t remote_spinlock; -static struct smem_log_item __iomem *smem_log_static_events; -static uint32_t __iomem *smem_log_static_idx; static remote_spinlock_t remote_spinlock_static; struct smem_log_inst { - struct smem_log_item __iomem *smem_log_cur_events; - uint32_t __iomem *smem_log_cur_idx; - int smem_log_cur_num; - remote_spinlock_t *cur_remote_spinlock; + int which_log; + struct smem_log_item __iomem *events; + uint32_t __iomem *idx; + int num; + remote_spinlock_t *remote_spinlock; +}; + +enum smem_logs { + GEN = 0, + STA, + POW, + NUM }; +static struct smem_log_inst inst[NUM]; + #if defined(CONFIG_DEBUG_FS) #define HSIZE 13 @@ -951,13 +962,13 @@ static void smem_log_event_from_user(struct smem_log_inst *inst, int first = 1; int ret; - remote_spin_lock_irqsave(inst->cur_remote_spinlock, flags); + remote_spin_lock_irqsave(inst->remote_spinlock, flags); while (num--) { - idx = *inst->smem_log_cur_idx; + idx = *inst->idx; - if (idx < inst->smem_log_cur_num) { - ret = copy_from_user(&inst->smem_log_cur_events[idx], + if (idx < inst->num) { + ret = copy_from_user(&inst->events[idx], buf, size); if (ret) { printk("ERROR %s:%i tried to write " @@ -969,29 +980,29 @@ static void smem_log_event_from_user(struct smem_log_inst *inst, if (first) { identifier = - inst->smem_log_cur_events[idx]. + inst->events[idx]. identifier; timetick = read_timestamp(); first = 0; } else { identifier |= SMEM_LOG_CONT; } - inst->smem_log_cur_events[idx].identifier = + inst->events[idx].identifier = identifier; - inst->smem_log_cur_events[idx].timetick = + inst->events[idx].timetick = timetick; } next_idx = idx + 1; - if (next_idx >= inst->smem_log_cur_num) + if (next_idx >= inst->num) next_idx = 0; - *inst->smem_log_cur_idx = next_idx; + *inst->idx = next_idx; buf += sizeof(struct smem_log_item); } out: - remote_spin_unlock_irqrestore(inst->cur_remote_spinlock, flags); + remote_spin_unlock_irqrestore(inst->remote_spinlock, flags); } static void _smem_log_event( @@ -1075,8 +1086,8 @@ static void _smem_log_event6( void smem_log_event(uint32_t id, uint32_t data1, uint32_t data2, uint32_t data3) { - _smem_log_event(smem_log_events, smem_log_idx, - &remote_spinlock, SMEM_LOG_NUM_ENTRIES, + _smem_log_event(inst[GEN].events, inst[GEN].idx, + inst[GEN].remote_spinlock, SMEM_LOG_NUM_ENTRIES, id, data1, data2, data3); } @@ -1084,16 +1095,16 @@ void smem_log_event6(uint32_t id, uint32_t data1, uint32_t data2, uint32_t data3, uint32_t data4, uint32_t data5, uint32_t data6) { - _smem_log_event6(smem_log_events, smem_log_idx, - &remote_spinlock, SMEM_LOG_NUM_ENTRIES, + _smem_log_event6(inst[GEN].events, inst[GEN].idx, + inst[GEN].remote_spinlock, SMEM_LOG_NUM_ENTRIES, id, data1, data2, data3, data4, data5, data6); } void smem_log_event_to_static(uint32_t id, uint32_t data1, uint32_t data2, uint32_t data3) { - _smem_log_event(smem_log_static_events, smem_log_static_idx, - &remote_spinlock_static, SMEM_LOG_NUM_STATIC_ENTRIES, + _smem_log_event(inst[STA].events, inst[STA].idx, + inst[STA].remote_spinlock, SMEM_LOG_NUM_STATIC_ENTRIES, id, data1, data2, data3); } @@ -1101,37 +1112,56 @@ void smem_log_event6_to_static(uint32_t id, uint32_t data1, uint32_t data2, uint32_t data3, uint32_t data4, uint32_t data5, uint32_t data6) { - _smem_log_event6(smem_log_static_events, smem_log_static_idx, - &remote_spinlock_static, SMEM_LOG_NUM_STATIC_ENTRIES, + _smem_log_event6(inst[STA].events, inst[STA].idx, + inst[STA].remote_spinlock, SMEM_LOG_NUM_STATIC_ENTRIES, id, data1, data2, data3, data4, data5, data6); } static int _smem_log_init(void) { - smem_log_events = + inst[GEN].which_log = GEN; + inst[GEN].events = (struct smem_log_item *)smem_alloc(SMEM_SMEM_LOG_EVENTS, SMEM_LOG_EVENTS_SIZE); - smem_log_idx = (uint32_t *)smem_alloc(SMEM_SMEM_LOG_IDX, + inst[GEN].idx = (uint32_t *)smem_alloc(SMEM_SMEM_LOG_IDX, sizeof(uint32_t)); - if (!smem_log_events || !smem_log_idx) { - printk(KERN_INFO "smem_log_init: no log or log_idx allocated, " + if (!inst[GEN].events || !inst[GEN].idx) { + printk(KERN_ERR "smem_log_init: no log or log_idx allocated, " "smem_log disabled"); - return -EIO; } + inst[GEN].num = SMEM_LOG_NUM_ENTRIES; + inst[GEN].remote_spinlock = &remote_spinlock; - smem_log_static_events = + inst[STA].which_log = STA; + inst[STA].events = (struct smem_log_item *) smem_alloc(SMEM_SMEM_STATIC_LOG_EVENTS, SMEM_STATIC_LOG_EVENTS_SIZE); - smem_log_static_idx = (uint32_t *)smem_alloc(SMEM_SMEM_STATIC_LOG_IDX, + inst[STA].idx = (uint32_t *)smem_alloc(SMEM_SMEM_STATIC_LOG_IDX, + sizeof(uint32_t)); + if (!inst[STA].events || !inst[STA].idx) { + printk(KERN_ERR "smem_log_init: no static log or log_idx " + "allocated, smem_log disabled"); + } + inst[STA].num = SMEM_LOG_NUM_STATIC_ENTRIES; + inst[STA].remote_spinlock = &remote_spinlock_static; + + inst[POW].which_log = POW; + inst[POW].events = + (struct smem_log_item *) + smem_alloc(SMEM_SMEM_LOG_POWER_EVENTS, + SMEM_POWER_LOG_EVENTS_SIZE); + inst[POW].idx = (uint32_t *)smem_alloc(SMEM_SMEM_LOG_POWER_IDX, sizeof(uint32_t)); - if (!smem_log_static_events || !smem_log_static_idx) { - printk(KERN_INFO "smem_log_init: no static log or log_idx " + if (!inst[POW].events || !inst[POW].idx) { + printk(KERN_ERR "smem_log_init: no power log or log_idx " "allocated, smem_log disabled"); - return -EIO; } + inst[POW].num = SMEM_LOG_NUM_POWER_ENTRIES; + inst[POW].remote_spinlock = &remote_spinlock; - remote_spin_lock_init(&remote_spinlock, SMEM_SPINLOCK_SMEM_LOG); + remote_spin_lock_init(&remote_spinlock, + SMEM_SPINLOCK_SMEM_LOG); remote_spin_lock_init(&remote_spinlock_static, SMEM_SPINLOCK_STATIC_LOG); @@ -1152,15 +1182,15 @@ static ssize_t smem_log_read_bin(struct file *fp, char __user *buf, inst = fp->private_data; - remote_spin_lock_irqsave(inst->cur_remote_spinlock, flags); + remote_spin_lock_irqsave(inst->remote_spinlock, flags); - orig_idx = *inst->smem_log_cur_idx; + orig_idx = *inst->idx; idx = orig_idx; while (1) { idx--; if (idx < 0) - idx = inst->smem_log_cur_num - 1; + idx = inst->num - 1; if (idx == orig_idx) { ret = tot_bytes; break; @@ -1171,7 +1201,7 @@ static ssize_t smem_log_read_bin(struct file *fp, char __user *buf, break; } - ret = copy_to_user(buf, &smem_log_events[idx], + ret = copy_to_user(buf, &inst[GEN].events[idx], sizeof(struct smem_log_item)); if (ret) { ret = -EIO; @@ -1183,7 +1213,7 @@ static ssize_t smem_log_read_bin(struct file *fp, char __user *buf, buf += sizeof(struct smem_log_item); } - remote_spin_unlock_irqrestore(inst->cur_remote_spinlock, flags); + remote_spin_unlock_irqrestore(inst->remote_spinlock, flags); return ret; } @@ -1202,15 +1232,15 @@ static ssize_t smem_log_read(struct file *fp, char __user *buf, inst = fp->private_data; - remote_spin_lock_irqsave(inst->cur_remote_spinlock, flags); + remote_spin_lock_irqsave(inst->remote_spinlock, flags); - orig_idx = *inst->smem_log_cur_idx; + orig_idx = *inst->idx; idx = orig_idx; while (1) { idx--; if (idx < 0) - idx = inst->smem_log_cur_num - 1; + idx = inst->num - 1; if (idx == orig_idx) { ret = tot_bytes; break; @@ -1218,11 +1248,11 @@ static ssize_t smem_log_read(struct file *fp, char __user *buf, i = scnprintf(loc_buf, 128, "0x%x 0x%x 0x%x 0x%x 0x%x\n", - smem_log_events[idx].identifier, - smem_log_events[idx].timetick, - smem_log_events[idx].data1, - smem_log_events[idx].data2, - smem_log_events[idx].data3); + inst->events[idx].identifier, + inst->events[idx].timetick, + inst->events[idx].data1, + inst->events[idx].data2, + inst->events[idx].data3); if (i == 0) { ret = -EIO; break; @@ -1244,7 +1274,7 @@ static ssize_t smem_log_read(struct file *fp, char __user *buf, buf += i; } - remote_spin_unlock_irqrestore(inst->cur_remote_spinlock, flags); + remote_spin_unlock_irqrestore(inst->remote_spinlock, flags); return ret; } @@ -1317,19 +1347,19 @@ static ssize_t smem_log_write(struct file *fp, const char __user *buf, } if (vals > 5) { - if (inst->smem_log_cur_events == smem_log_events) + if (inst->which_log == GEN) smem_log_event6(val[0], val[2], val[3], val[4], val[7], val[8], val[9]); - else if (inst->smem_log_cur_events == smem_log_static_events) + else if (inst->which_log == STA) smem_log_event6_to_static(val[0], val[2], val[3], val[4], val[7], val[8], val[9]); else return -1; } else { - if (inst->smem_log_cur_events == smem_log_events) + if (inst->which_log == GEN) smem_log_event(val[0], val[2], val[3], val[4]); - else if (inst->smem_log_cur_events == smem_log_static_events) + else if (inst->which_log == STA) smem_log_event_to_static(val[0], val[2], val[3], val[4]); else @@ -1341,24 +1371,7 @@ static ssize_t smem_log_write(struct file *fp, const char __user *buf, static int smem_log_open(struct inode *ip, struct file *fp) { - struct smem_log_inst *inst; - - inst = kzalloc(sizeof(struct smem_log_inst), GFP_KERNEL); - - if (IS_ERR(inst)) { - printk(KERN_ERR "ERROR:%s:%i:%s kmalloc() ENOMEM\n", - __FILE__, - __LINE__-5, - __func__); - return -ENOMEM; - } - - inst->smem_log_cur_idx = smem_log_idx; - inst->smem_log_cur_events = smem_log_events; - inst->smem_log_cur_num = SMEM_LOG_NUM_ENTRIES; - inst->cur_remote_spinlock = &remote_spinlock; - - fp->private_data = inst; + fp->private_data = &inst[GEN]; return 0; } @@ -1366,8 +1379,6 @@ static int smem_log_open(struct inode *ip, struct file *fp) static int smem_log_release(struct inode *ip, struct file *fp) { - kfree(fp->private_data); - return 0; } @@ -1415,19 +1426,12 @@ static int smem_log_ioctl(struct inode *ip, struct file *fp, } break; case SMIOC_SETLOG: - if (arg == SMIOC_LOG) { - inst->smem_log_cur_events = smem_log_events; - inst->smem_log_cur_idx = smem_log_idx; - inst->smem_log_cur_num = SMEM_LOG_NUM_ENTRIES; - inst->cur_remote_spinlock = &remote_spinlock; - } else if (arg == SMIOC_STATIC_LOG) { - inst->smem_log_cur_events = smem_log_static_events; - inst->smem_log_cur_idx = smem_log_static_idx; - inst->smem_log_cur_num = SMEM_LOG_NUM_STATIC_ENTRIES; - inst->cur_remote_spinlock = &remote_spinlock_static; - } else { + if (arg == SMIOC_LOG) + fp->private_data = &inst[GEN]; + else if (arg == SMIOC_STATIC_LOG) + fp->private_data = &inst[STA]; + else return -EINVAL; - } break; } @@ -1442,45 +1446,48 @@ static struct miscdevice smem_log_dev = { #if defined(CONFIG_DEBUG_FS) -static int debug_dump(char *buf, int max) +static int _debug_dump(int log, char *buf, int max) { unsigned int idx; int orig_idx; unsigned long flags; int i = 0; - remote_spin_lock_irqsave(&remote_spinlock, flags); + if (!inst[log].events) + return 0; + + remote_spin_lock_irqsave(inst[log].remote_spinlock, flags); - orig_idx = *smem_log_idx; + orig_idx = *inst[log].idx; idx = orig_idx; while (1) { idx++; - if (idx > SMEM_LOG_NUM_ENTRIES - 1) + if (idx > inst[log].num - 1) idx = 0; if (idx == orig_idx) break; - if (idx < SMEM_LOG_NUM_ENTRIES) { - if (!smem_log_events[idx].identifier) + if (idx < inst[log].num) { + if (!inst[log].events[idx].identifier) continue; i += scnprintf(buf + i, max - i, "%08x %08x %08x %08x %08x\n", - smem_log_events[idx].identifier, - smem_log_events[idx].timetick, - smem_log_events[idx].data1, - smem_log_events[idx].data2, - smem_log_events[idx].data3); + inst[log].events[idx].identifier, + inst[log].events[idx].timetick, + inst[log].events[idx].data1, + inst[log].events[idx].data2, + inst[log].events[idx].data3); } } - remote_spin_unlock_irqrestore(&remote_spinlock, flags); + remote_spin_unlock_irqrestore(inst[log].remote_spinlock, flags); return i; } -static int debug_dump_sym(char *buf, int max) +static int _debug_dump_sym(int log, char *buf, int max) { unsigned int idx; int orig_idx; @@ -1504,6 +1511,9 @@ static int debug_dump_sym(char *buf, int max) int k; + if (!inst[log].events) + return 0; + find_voters(); /* need to call each time in case voters come and go */ i += scnprintf(buf + i, max - i, "Voters:\n"); @@ -1517,30 +1527,30 @@ static int debug_dump_sym(char *buf, int max) voter_d2_syms[k].str); i += scnprintf(buf + i, max - i, "\n"); - remote_spin_lock_irqsave(&remote_spinlock, flags); + remote_spin_lock_irqsave(inst[log].remote_spinlock, flags); - orig_idx = *smem_log_idx; + orig_idx = *inst[log].idx; idx = orig_idx; while (1) { idx++; - if (idx > SMEM_LOG_NUM_ENTRIES - 1) + if (idx > inst[log].num - 1) idx = 0; if (idx == orig_idx) { i += scnprintf(buf + i, max - i, "\n"); break; } - if (idx < SMEM_LOG_NUM_ENTRIES) { - if (!smem_log_events[idx].identifier) + if (idx < inst[log].num) { + if (!inst[log].events[idx].identifier) continue; - proc_val = PROC & smem_log_events[idx].identifier; - sub_val = SUB & smem_log_events[idx].identifier; - id_val = (SUB | ID) & smem_log_events[idx].identifier; - id_only_val = ID & smem_log_events[idx].identifier; - data1 = smem_log_events[idx].data1; - data2 = smem_log_events[idx].data2; - data3 = smem_log_events[idx].data3; + proc_val = PROC & inst[log].events[idx].identifier; + sub_val = SUB & inst[log].events[idx].identifier; + id_val = (SUB | ID) & inst[log].events[idx].identifier; + id_only_val = ID & inst[log].events[idx].identifier; + data1 = inst[log].events[idx].data1; + data2 = inst[log].events[idx].data2; + data3 = inst[log].events[idx].data3; if (!(proc_val & SMEM_LOG_CONT)) { i += scnprintf(buf + i, max - i, "\n"); @@ -1555,12 +1565,12 @@ static int debug_dump_sym(char *buf, int max) i += scnprintf(buf + i, max - i, "%04x: ", PROC & - smem_log_events[idx]. + inst[log].events[idx]. identifier); i += scnprintf(buf + i, max - i, "%10u ", - smem_log_events[idx].timetick); + inst[log].events[idx].timetick); sub = find_sym(BASE_SYM, sub_val); @@ -1906,61 +1916,53 @@ static int debug_dump_sym(char *buf, int max) } } - remote_spin_unlock_irqrestore(&remote_spinlock, flags); + remote_spin_unlock_irqrestore(inst[log].remote_spinlock, flags); return i; } -static int debug_dump_static(char *buf, int max) +static int debug_dump(char *buf, int max) { - unsigned int idx; - int orig_idx; - unsigned long flags; - int i = 0; - - remote_spin_lock_irqsave(&remote_spinlock_static, flags); - - orig_idx = *smem_log_static_idx; - idx = orig_idx; + return _debug_dump(GEN, buf, max); +} - while (1) { - idx++; - if (idx > SMEM_LOG_NUM_ENTRIES - 1) - idx = 0; - if (idx == orig_idx) - break; +static int debug_dump_sym(char *buf, int max) +{ + return _debug_dump_sym(GEN, buf, max); +} - if (idx < SMEM_LOG_NUM_STATIC_ENTRIES) { - if (!smem_log_static_events[idx].identifier) - continue; +static int debug_dump_static(char *buf, int max) +{ + return _debug_dump(STA, buf, max); +} - i += scnprintf(buf + i, max - i, - "%08x %08x %08x %08x %08x\n", - smem_log_static_events[idx].identifier, - smem_log_static_events[idx].timetick, - smem_log_static_events[idx].data1, - smem_log_static_events[idx].data2, - smem_log_static_events[idx].data3); - } - } +static int debug_dump_static_sym(char *buf, int max) +{ + return _debug_dump_sym(STA, buf, max); +} - remote_spin_unlock_irqrestore(&remote_spinlock_static, flags); +static int debug_dump_power(char *buf, int max) +{ + return _debug_dump(POW, buf, max); +} - return i; +static int debug_dump_power_sym(char *buf, int max) +{ + return _debug_dump_sym(POW, buf, max); } #define SMEM_LOG_ITEM_PRINT_SIZE 160 -#define SMEM_LOG_CUR_EVENTS_PRINT_SIZE \ +#define EVENTS_PRINT_SIZE \ (SMEM_LOG_ITEM_PRINT_SIZE * SMEM_LOG_NUM_ENTRIES) -static char debug_buffer[SMEM_LOG_CUR_EVENTS_PRINT_SIZE]; +static char debug_buffer[EVENTS_PRINT_SIZE]; static ssize_t debug_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { int (*fill)(char *buf, int max) = file->private_data; - int bsize = fill(debug_buffer, SMEM_LOG_CUR_EVENTS_PRINT_SIZE); + int bsize = fill(debug_buffer, EVENTS_PRINT_SIZE); return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize); } @@ -1994,6 +1996,9 @@ static void smem_log_debugfs_init(void) debug_create("dump", 0444, dent, debug_dump); debug_create("dump_sym", 0444, dent, debug_dump_sym); debug_create("dump_static", 0444, dent, debug_dump_static); + debug_create("dump_static_sym", 0444, dent, debug_dump_static_sym); + debug_create("dump_power", 0444, dent, debug_dump_power); + debug_create("dump_power_sym", 0444, dent, debug_dump_power_sym); } #else static void smem_log_debugfs_init(void) {} -- cgit v1.2.3 From 0a48911ea68ae8a54a70cec53777e07127de08d1 Mon Sep 17 00:00:00 2001 From: "Vishwanathapura, Niranjana" Date: Mon, 11 May 2009 16:04:24 -0600 Subject: [ARM] msm: Add rpc client operation framework Add rpc client operation framework to smd_rpcrouter driver to abstract kernel smd rpc clients opertions into a common framework. Signed-off-by: Niranjana Vishwanathapura --- arch/arm/mach-msm/Makefile | 1 + arch/arm/mach-msm/include/mach/msm_rpcrouter.h | 51 ++++ arch/arm/mach-msm/smd_rpcrouter_clients.c | 370 +++++++++++++++++++++++++ 3 files changed, 422 insertions(+) create mode 100644 arch/arm/mach-msm/smd_rpcrouter_clients.c (limited to 'arch') diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 059da63bb9eb..201e96d4fb8d 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_MSM_RESET_MODEM) += reset_modem.o obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter.o obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_device.o obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_servers.o +obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_clients.o obj-$(CONFIG_MSM_RPCSERVERS) += rpc_server_dog_keepalive.o obj-$(CONFIG_MSM_RPCSERVERS) += rpc_server_time_remote.o obj-$(CONFIG_MSM_DALRPC) += dal.o diff --git a/arch/arm/mach-msm/include/mach/msm_rpcrouter.h b/arch/arm/mach-msm/include/mach/msm_rpcrouter.h index 86859941210d..0851a405da03 100644 --- a/arch/arm/mach-msm/include/mach/msm_rpcrouter.h +++ b/arch/arm/mach-msm/include/mach/msm_rpcrouter.h @@ -172,4 +172,55 @@ struct msm_rpc_server int msm_rpc_create_server(struct msm_rpc_server *server); +#define MSM_RPC_MSGSIZE_MAX 8192 + +struct msm_rpc_client; + +struct msm_rpc_client { + struct task_struct *read_thread; + struct task_struct *cb_thread; + + struct msm_rpc_endpoint *ept; + wait_queue_head_t reply_wait; + + uint32_t prog, ver; + + void *buf; + int read_avail; + + int (*cb_func)(struct msm_rpc_client *, void *, int); + void *cb_buf; + int cb_size; + + struct list_head cb_item_list; + struct mutex cb_item_list_lock; + + wait_queue_head_t cb_wait; + int cb_avail; + + uint32_t exit_flag; + struct completion complete; + struct completion cb_complete; + + struct mutex req_lock; + char req[MSM_RPC_MSGSIZE_MAX]; +}; + +struct msm_rpc_client *msm_rpc_register_client( + const char *name, + uint32_t prog, uint32_t ver, + uint32_t create_cb_thread, + int (*cb_func)(struct msm_rpc_client *, void *, int)); + +int msm_rpc_unregister_client(struct msm_rpc_client *client); + +int msm_rpc_client_req(struct msm_rpc_client *client, uint32_t proc, + int (*arg_func)(void *, void *), + int (*result_func)(void *, void *), + void *data); + +int msm_rpc_send_accepted_reply(struct msm_rpc_client *client, + uint32_t xid, uint32_t accept_status, + char *buf, uint32_t size); + #endif diff --git a/arch/arm/mach-msm/smd_rpcrouter_clients.c b/arch/arm/mach-msm/smd_rpcrouter_clients.c new file mode 100644 index 000000000000..01afe99a3628 --- /dev/null +++ b/arch/arm/mach-msm/smd_rpcrouter_clients.c @@ -0,0 +1,370 @@ +/* + * Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * SMD RPCROUTER CLIENTS module. + * + */ + +#include +#include + +#include +#include "smd_rpcrouter.h" + +struct msm_rpc_client_cb_item { + struct list_head list; + + void *buf; + int size; +}; + +static int rpc_clients_cb_thread(void *data) +{ + struct msm_rpc_client_cb_item *cb_item; + struct msm_rpc_client *client; + struct rpc_request_hdr *req; + + client = data; + for (;;) { + wait_event(client->cb_wait, client->cb_avail); + if (client->exit_flag) + break; + + client->cb_avail = 0; + mutex_lock(&client->cb_item_list_lock); + while (!list_empty(&client->cb_item_list)) { + cb_item = list_first_entry( + &client->cb_item_list, + struct msm_rpc_client_cb_item, + list); + list_del(&cb_item->list); + mutex_unlock(&client->cb_item_list_lock); + req = (struct rpc_request_hdr *)cb_item->buf; + + if (be32_to_cpu(req->type) != 0) + goto bad_rpc; + if (be32_to_cpu(req->rpc_vers) != 2) + goto bad_rpc; + if (be32_to_cpu(req->prog) != + (client->prog | 0x01000000)) + goto bad_rpc; + + client->cb_func(client, + cb_item->buf, cb_item->size); + bad_rpc: + kfree(cb_item->buf); + kfree(cb_item); + mutex_lock(&client->cb_item_list_lock); + } + mutex_unlock(&client->cb_item_list_lock); + } + complete_and_exit(&client->cb_complete, 0); +} + +static int rpc_clients_thread(void *data) +{ + void *buffer; + uint32_t type; + struct msm_rpc_client *client; + int rc = 0; + struct msm_rpc_client_cb_item *cb_item; + + client = data; + for (;;) { + rc = msm_rpc_read(client->ept, &buffer, -1, HZ); + if (client->exit_flag) + break; + if (rc < ((int)(sizeof(uint32_t) * 2))) + continue; + + type = be32_to_cpu(*((uint32_t *)buffer + 1)); + if (type == 1) { + client->buf = buffer; + client->read_avail = 1; + wake_up(&client->reply_wait); + } else if (type == 0) { + cb_item = kmalloc(sizeof(*cb_item), GFP_KERNEL); + if (!cb_item) { + pr_err("%s: no memory for cb item\n", + __func__); + continue; + } + + if (client->cb_thread == NULL) { + client->cb_func(client, buffer, rc); + kfree(buffer); + } else { + INIT_LIST_HEAD(&cb_item->list); + cb_item->buf = buffer; + cb_item->size = rc; + mutex_lock(&client->cb_item_list_lock); + list_add_tail(&cb_item->list, + &client->cb_item_list); + mutex_unlock(&client->cb_item_list_lock); + client->cb_avail = 1; + wake_up(&client->cb_wait); + } + } + } + complete_and_exit(&client->complete, 0); +} + +static struct msm_rpc_client *msm_rpc_create_client(void) +{ + struct msm_rpc_client *client; + + client = kmalloc(sizeof(struct msm_rpc_client), GFP_KERNEL); + if (!client) + return ERR_PTR(-ENOMEM); + + init_waitqueue_head(&client->reply_wait); + mutex_init(&client->req_lock); + client->buf = NULL; + client->read_avail = 0; + client->cb_buf = NULL; + client->cb_size = 0; + client->exit_flag = 0; + init_completion(&client->complete); + init_completion(&client->cb_complete); + INIT_LIST_HEAD(&client->cb_item_list); + mutex_init(&client->cb_item_list_lock); + client->cb_avail = 0; + init_waitqueue_head(&client->cb_wait); + + return client; +} + +/* + * Interface to be used to register the client. + * + * name: string representing the client + * + * prog: program number of the client + * + * ver: version number of the client + * + * create_cb_thread: if set calls the callback function from a seprate thread + * which helps the client requests to be processed without + * getting loaded by callback handling. + * + * cb_func: function to be called if callback request is received. + * unmarshaling should be handled by the user in callback function + * + * Return Value: + * Pointer to initialized client data sturcture + * Or, the error code if registration fails. + * + */ +struct msm_rpc_client *msm_rpc_register_client( + const char *name, + uint32_t prog, uint32_t ver, + uint32_t create_cb_thread, + int (*cb_func)(struct msm_rpc_client *, void *, int)) +{ + struct msm_rpc_client *client; + struct msm_rpc_endpoint *ept; + int rc; + + client = msm_rpc_create_client(); + if (IS_ERR(client)) + return client; + + ept = msm_rpc_connect_compatible(prog, ver, MSM_RPC_UNINTERRUPTIBLE); + if (IS_ERR(ept)) { + kfree(client); + return (struct msm_rpc_client *)ept; + } + + client->prog = prog; + client->ver = ver; + client->ept = ept; + client->cb_func = cb_func; + + /* start the read thread */ + client->read_thread = kthread_run(rpc_clients_thread, client, + "k%sclntd", name); + if (IS_ERR(client->read_thread)) { + rc = PTR_ERR(client->read_thread); + msm_rpc_close(client->ept); + kfree(client); + return ERR_PTR(rc); + } + + if (!create_cb_thread || (cb_func == NULL)) { + client->cb_thread = NULL; + return client; + } + + /* start the callback thread */ + client->cb_thread = kthread_run(rpc_clients_cb_thread, client, + "k%sclntcbd", name); + if (IS_ERR(client->cb_thread)) { + rc = PTR_ERR(client->cb_thread); + client->exit_flag = 1; + wait_for_completion(&client->complete); + msm_rpc_close(client->ept); + kfree(client); + return ERR_PTR(rc); + } + + return client; +} +EXPORT_SYMBOL(msm_rpc_register_client); + +/* + * Interface to be used to unregister the client + * No client operations should be done once the unregister function + * is called. + * + * client: pointer to client data structure. + * + * Return Value: + * Always returns 0 (success). + */ +int msm_rpc_unregister_client(struct msm_rpc_client *client) +{ + pr_info("%s: stopping client...\n", __func__); + client->exit_flag = 1; + if (client->cb_thread) { + client->cb_avail = 1; + wake_up(&client->cb_wait); + wait_for_completion(&client->cb_complete); + } + + wait_for_completion(&client->complete); + + msm_rpc_close(client->ept); + kfree(client); + return 0; +} +EXPORT_SYMBOL(msm_rpc_unregister_client); + +/* + * Interface to be used to send a client request. + * If the request takes any arguments or expects any results, the user + * should handle it in 'arg_func' and 'result_func' respectively. + * Marshaling and Unmarshaling should be handled by the user in argument + * and result functions. + * + * client: pointer to client data sturcture + * + * proc: procedure being requested + * + * arg_func: argument function pointer + * + * result_func: result function pointer + * + * data: passed as an input parameter to argument and result functions. + * + * Return Value: + * 0 on success, otherwise an error code is returned. + */ +int msm_rpc_client_req(struct msm_rpc_client *client, uint32_t proc, + int (*arg_func)(void *buf, void *data), + int (*result_func)(void *buf, void *data), + void *data) +{ + int size = 0; + struct rpc_reply_hdr *rpc_rsp; + int rc = 0; + + mutex_lock(&client->req_lock); + + msm_rpc_setup_req((struct rpc_request_hdr *)client->req, client->prog, + client->ver, proc); + size = sizeof(struct rpc_request_hdr); + + if (arg_func) + size += arg_func((void *)((struct rpc_request_hdr *) + client->req + 1), data); + + rc = msm_rpc_write(client->ept, client->req, size); + if (rc < 0) { + pr_err("%s: couldn't send RPC request:%d\n", __func__, rc); + goto release_locks; + } else + rc = 0; + + rc = wait_event_timeout(client->reply_wait, + client->read_avail, msecs_to_jiffies(10000)); + if (rc == 0) { + rc = -ETIMEDOUT; + goto release_locks; + } else + rc = 0; + + client->read_avail = 0; + + rpc_rsp = (struct rpc_reply_hdr *)client->buf; + if (be32_to_cpu(rpc_rsp->reply_stat) != RPCMSG_REPLYSTAT_ACCEPTED) { + pr_err("%s: RPC call was denied! %d\n", __func__, + be32_to_cpu(rpc_rsp->reply_stat)); + rc = -EPERM; + goto free_and_release; + } + + if (be32_to_cpu(rpc_rsp->data.acc_hdr.accept_stat) != + RPC_ACCEPTSTAT_SUCCESS) { + pr_err("%s: RPC call was not successful (%d)\n", __func__, + be32_to_cpu(rpc_rsp->data.acc_hdr.accept_stat)); + rc = -EINVAL; + goto free_and_release; + } + + if (result_func) + result_func((void *)(rpc_rsp + 1), data); + + free_and_release: + kfree(client->buf); + release_locks: + mutex_unlock(&client->req_lock); + return rc; +} +EXPORT_SYMBOL(msm_rpc_client_req); + +/* + * Interface to be used to send accepted reply required in callback handling. + * Additional payload may be passed in through the 'buf' and 'size'. + * Marshaling should be handled by user for the payload. + * + * client: pointer to client data structure + * + * xid: transaction id. Has to be same as the one in callback request. + * + * accept_status: acceptance status + * + * buf: additional payload + * + * size: additional payload size + * + * Return Value: + * 0 on success, otherwise returns an error code. + */ +int msm_rpc_send_accepted_reply(struct msm_rpc_client *client, + uint32_t xid, uint32_t accept_status, + char *buf, uint32_t size) +{ + int rc = 0; + struct rpc_reply_hdr *reply; + + reply = kmalloc(sizeof(struct rpc_reply_hdr) + size, GFP_KERNEL); + if (!reply) + return -ENOMEM; + + reply->xid = cpu_to_be32(xid); + reply->type = cpu_to_be32(1); /* reply */ + reply->reply_stat = cpu_to_be32(RPCMSG_REPLYSTAT_ACCEPTED); + + reply->data.acc_hdr.accept_stat = cpu_to_be32(accept_status); + reply->data.acc_hdr.verf_flavor = 0; + reply->data.acc_hdr.verf_length = 0; + + memcpy((char *)(reply + 1), buf, size); + size += sizeof(struct rpc_reply_hdr); + rc = msm_rpc_write(client->ept, reply, size); + if (rc > 0) + rc = 0; + + return rc; +} +EXPORT_SYMBOL(msm_rpc_send_accepted_reply); -- cgit v1.2.3 From e9232198da33bec51c01fe0f845a68b9da59d6a9 Mon Sep 17 00:00:00 2001 From: Kuogee Hsieh Date: Wed, 13 May 2009 08:24:01 -0700 Subject: [ARM] msm: pmic: prefix modem control APIs with pmic_ prefixed pmic_ to all modem control APIs to work with new modem control APIs prvoided by pmic Signed-off-by: Kuogee Hsieh --- arch/arm/mach-msm/board-qsd8x50.c | 2 +- arch/arm/mach-msm/include/mach/pmic.h | 32 ++++++------ arch/arm/mach-msm/pmic.c | 98 +++++++++++++++++------------------ 3 files changed, 67 insertions(+), 65 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/board-qsd8x50.c b/arch/arm/mach-msm/board-qsd8x50.c index 05c84ac5a4d5..6be98f92c19e 100644 --- a/arch/arm/mach-msm/board-qsd8x50.c +++ b/arch/arm/mach-msm/board-qsd8x50.c @@ -399,7 +399,7 @@ static int mddi_toshiba_pmic_bl(int level) int ret = -EPERM; if (machine_is_qsd8x50_ffa()) { - ret = set_led_intensity(LED_LCD, level); + ret = pmic_set_led_intensity(LED_LCD, level); if (ret) printk(KERN_WARNING "%s: can't set lcd backlight!\n", diff --git a/arch/arm/mach-msm/include/mach/pmic.h b/arch/arm/mach-msm/include/mach/pmic.h index 9a810246b6f8..71e23ab33263 100644 --- a/arch/arm/mach-msm/include/mach/pmic.h +++ b/arch/arm/mach-msm/include/mach/pmic.h @@ -117,24 +117,26 @@ enum ledtype { LED_TYPE_OUT_OF_RANGE }; -int spkr_en_right_chan(const unsigned char enable); -int spkr_is_right_chan_en(unsigned char *enabled); -int spkr_en_left_chan(const unsigned char enable); -int spkr_is_left_chan_en(unsigned char *enabled); -int spkr_is_en(const enum spkr_left_right left_right, unsigned char *enabled); -int spkr_get_gain(const enum spkr_left_right left_right, enum spkr_gain *gain); -int set_speaker_gain(const enum spkr_gain speaker_gain); -int speaker_cmd(const enum spkr_cmd cmd); -int set_spkr_configuration(const struct spkr_config_mode *t); -int get_spkr_configuration(struct spkr_config_mode *t); +int pmic_spkr_en_right_chan(const unsigned char enable); +int pmic_spkr_is_right_chan_en(unsigned char *enabled); +int pmic_spkr_en_left_chan(const unsigned char enable); +int pmic_spkr_is_left_chan_en(unsigned char *enabled); +int pmic_spkr_is_en(const enum spkr_left_right left_right, + unsigned char *enabled); +int pmic_spkr_get_gain(const enum spkr_left_right left_right, + enum spkr_gain *gain); +int pmic_set_speaker_gain(const enum spkr_gain speaker_gain); +int pmic_speaker_cmd(const enum spkr_cmd cmd); +int pmic_set_spkr_configuration(const struct spkr_config_mode *t); +int pmic_get_spkr_configuration(struct spkr_config_mode *t); -int mic_en(const unsigned char enable); -int mic_is_en(unsigned char *enabled); -int mic_set_volt(const enum mic_volt type); +int pmic_mic_en(const unsigned char enable); +int pmic_mic_is_en(unsigned char *enabled); +int pmic_mic_set_volt(const enum mic_volt type); /* Cannot use 'current' as the parameter name because 'current' is defined as * a macro to get a pointer to the current task. */ -int flash_led_set_current(const uint16_t milliamps); +int pmic_flash_led_set_current(const uint16_t milliamps); -int set_led_intensity(const enum ledtype type, int val); +int pmic_set_led_intensity(const enum ledtype type, int val); diff --git a/arch/arm/mach-msm/pmic.c b/arch/arm/mach-msm/pmic.c index e096b908b212..6b04ee1426c0 100644 --- a/arch/arm/mach-msm/pmic.c +++ b/arch/arm/mach-msm/pmic.c @@ -225,13 +225,13 @@ static int do_remote_value(const uint32_t set_value, return rc; } -int spkr_en_right_chan(const unsigned char enable) +int pmic_spkr_en_right_chan(const unsigned char enable) { return do_remote_value(enable, NULL, SPKR_EN_RIGHT_CHAN_PROC); } -EXPORT_SYMBOL(spkr_en_right_chan); +EXPORT_SYMBOL(pmic_spkr_en_right_chan); -int spkr_is_right_chan_en(unsigned char * const enabled) +int pmic_spkr_is_right_chan_en(unsigned char * const enabled) { uint32_t word_enabled; int rc; @@ -244,15 +244,15 @@ int spkr_is_right_chan_en(unsigned char * const enabled) *enabled = (unsigned char)word_enabled; return rc; } -EXPORT_SYMBOL(spkr_is_right_chan_en); +EXPORT_SYMBOL(pmic_spkr_is_right_chan_en); -int spkr_en_left_chan(const unsigned char enable) +int pmic_spkr_en_left_chan(const unsigned char enable) { return do_remote_value(enable, NULL, SPKR_EN_LEFT_CHAN_PROC); } -EXPORT_SYMBOL(spkr_en_left_chan); +EXPORT_SYMBOL(pmic_spkr_en_left_chan); -int spkr_is_left_chan_en(unsigned char * const enabled) +int pmic_spkr_is_left_chan_en(unsigned char * const enabled) { uint32_t word_enabled; int rc; @@ -265,19 +265,19 @@ int spkr_is_left_chan_en(unsigned char * const enabled) *enabled = (unsigned char)word_enabled; return rc; } -EXPORT_SYMBOL(spkr_is_left_chan_en); +EXPORT_SYMBOL(pmic_spkr_is_left_chan_en); -int spkr_is_en(const enum spkr_left_right left_right, +int pmic_spkr_is_en(const enum spkr_left_right left_right, unsigned char * const enabled) { if (left_right >= SPKR_OUT_OF_RANGE) return -EINVAL; return left_right == LEFT_SPKR ? - spkr_is_left_chan_en(enabled) : - spkr_is_right_chan_en(enabled); + pmic_spkr_is_left_chan_en(enabled) : + pmic_spkr_is_right_chan_en(enabled); } -EXPORT_SYMBOL(spkr_is_en); +EXPORT_SYMBOL(pmic_spkr_is_en); static int do_std_rpc_req2(struct get_value_rep *rep, uint32_t proc, uint32_t value1, uint32_t value2) @@ -308,7 +308,7 @@ static int do_std_rpc_req2(struct get_value_rep *rep, uint32_t proc, return modem_to_linux_err(rep->reply_hdr.result); } -int spkr_get_gain(const enum spkr_left_right left_right, +int pmic_spkr_get_gain(const enum spkr_left_right left_right, enum spkr_gain * const gain) { struct get_value_rep rep; @@ -331,27 +331,27 @@ int spkr_get_gain(const enum spkr_left_right left_right, return rc; } -EXPORT_SYMBOL(spkr_get_gain); +EXPORT_SYMBOL(pmic_spkr_get_gain); -int set_speaker_gain(const enum spkr_gain speaker_gain) +int pmic_set_speaker_gain(const enum spkr_gain speaker_gain) { if (speaker_gain >= SPKR_GAIN_OUT_OF_RANGE) return -EINVAL; return do_remote_value(speaker_gain, NULL, SET_SPEAKER_GAIN_PROC); } -EXPORT_SYMBOL(set_speaker_gain); +EXPORT_SYMBOL(pmic_set_speaker_gain); -int speaker_cmd(const enum spkr_cmd cmd) +int pmic_speaker_cmd(const enum spkr_cmd cmd) { if (cmd >= SPKR_CMD_OUT_OF_RANGE) return -EINVAL; return do_remote_value(cmd, NULL, SPEAKER_CMD_PROC); } -EXPORT_SYMBOL(speaker_cmd); +EXPORT_SYMBOL(pmic_speaker_cmd); -int set_spkr_configuration(const struct spkr_config_mode * const t) +int pmic_set_spkr_configuration(const struct spkr_config_mode * const t) { struct set_spkr_configuration_req req; struct std_rpc_reply rep; @@ -377,9 +377,9 @@ int set_spkr_configuration(const struct spkr_config_mode * const t) return modem_to_linux_err(rep.result); } -EXPORT_SYMBOL(set_spkr_configuration); +EXPORT_SYMBOL(pmic_set_spkr_configuration); -int get_spkr_configuration(struct spkr_config_mode * const t) +int pmic_get_spkr_configuration(struct spkr_config_mode * const t) { struct std_rpc_req req; struct get_spkr_configuration_rep rep; @@ -413,15 +413,15 @@ int get_spkr_configuration(struct spkr_config_mode * const t) return modem_to_linux_err(rep.reply_hdr.result); } -EXPORT_SYMBOL(get_spkr_configuration); +EXPORT_SYMBOL(pmic_get_spkr_configuration); -int mic_en(const unsigned char enable) +int pmic_mic_en(const unsigned char enable) { return do_remote_value(enable, NULL, MIC_EN_PROC); } -EXPORT_SYMBOL(mic_en); +EXPORT_SYMBOL(pmic_mic_en); -int mic_is_en(unsigned char * const enabled) +int pmic_mic_is_en(unsigned char * const enabled) { uint32_t word_enabled; int rc; @@ -435,36 +435,36 @@ int mic_is_en(unsigned char * const enabled) return rc; } -EXPORT_SYMBOL(mic_is_en); +EXPORT_SYMBOL(pmic_mic_is_en); -int mic_set_volt(const enum mic_volt type) +int pmic_mic_set_volt(const enum mic_volt type) { if (type >= MIC_VOLT_OUT_OF_RANGE) return -EINVAL; return do_remote_value(type, NULL, MIC_SET_VOLT_PROC); } -EXPORT_SYMBOL(mic_set_volt); +EXPORT_SYMBOL(pmic_mic_set_volt); -int mic_get_volt(enum mic_volt * const voltage) +int pmic_mic_get_volt(enum mic_volt * const voltage) { if (voltage == NULL) return modem_to_linux_err(PM_ERR_FLAG__PAR1_OUT_OF_RANGE); return do_remote_value(0, voltage, MIC_GET_VOLT_PROC); } -EXPORT_SYMBOL(mic_get_volt); +EXPORT_SYMBOL(pmic_mic_get_volt); /* Cannot use 'current' as the parameter name because 'current' is defined as * a macro to get a pointer to the current task. */ -int flash_led_set_current(const uint16_t milliamps) +int pmic_flash_led_set_current(const uint16_t milliamps) { return do_remote_value(milliamps, NULL, FLASH_LED_SET_CURRENT_PROC); } -EXPORT_SYMBOL(flash_led_set_current); +EXPORT_SYMBOL(pmic_flash_led_set_current); -int set_led_intensity(const enum ledtype type, int level) +int pmic_set_led_intensity(const enum ledtype type, int level) { struct get_value_rep rep; @@ -474,7 +474,7 @@ int set_led_intensity(const enum ledtype type, int level) return do_std_rpc_req2(&rep, SET_LED_INTENSITY_PROC, (uint32_t)type, level); } -EXPORT_SYMBOL(set_led_intensity); +EXPORT_SYMBOL(pmic_set_led_intensity); #if defined(CONFIG_DEBUG_FS) static void debugfs_log_return_status(const int caller_rc, @@ -492,8 +492,8 @@ static void debugfs_log_return_status(const int caller_rc, static int debugfs_spkr_en_chan(void *data, u64 val) { int rc = ((enum spkr_left_right)data) == LEFT_SPKR ? - spkr_en_left_chan((const unsigned char)val) : - spkr_en_right_chan((const unsigned char)val); + pmic_spkr_en_left_chan((const unsigned char)val) : + pmic_spkr_en_right_chan((const unsigned char)val); debugfs_log_return_status(rc, __func__, val); return rc; @@ -503,8 +503,8 @@ static int debugfs_spkr_is_chan_en(void *data, u64 *val) { unsigned char enabled; int rc = ((enum spkr_left_right)data) == LEFT_SPKR ? - spkr_is_left_chan_en(&enabled) : - spkr_is_right_chan_en(&enabled); + pmic_spkr_is_left_chan_en(&enabled) : + pmic_spkr_is_right_chan_en(&enabled); if (!rc) *val = (u64)enabled; @@ -520,7 +520,7 @@ DEFINE_SIMPLE_ATTRIBUTE(debugfs_spkr_en_chan_fops, static int debugfs_spkr_get_gain(void *data, u64 *val) { enum spkr_gain gain; - int rc = spkr_get_gain((enum spkr_left_right)data, &gain); + int rc = pmic_spkr_get_gain((enum spkr_left_right)data, &gain); if (!rc) *val = (u64)gain; @@ -531,7 +531,7 @@ static int debugfs_spkr_get_gain(void *data, u64 *val) static int debugfs_set_speaker_gain(void *data, u64 val) { - int rc = set_speaker_gain((enum spkr_gain)val); + int rc = pmic_set_speaker_gain((enum spkr_gain)val); debugfs_log_return_status(rc, __func__, val); return rc; @@ -543,7 +543,7 @@ DEFINE_SIMPLE_ATTRIBUTE(debugfs_spkr_gain_fops, static int debugfs_speaker_cmd(void *data, u64 val) { - int rc = speaker_cmd((const enum spkr_cmd)val); + int rc = pmic_speaker_cmd((const enum spkr_cmd)val); debugfs_log_return_status(rc, __func__, val); return rc; @@ -576,7 +576,7 @@ static ssize_t debugfs_spkr_get_configuration(struct file *filp, size_t cnt, loff_t *ppos) { struct spkr_config_mode type; - int rc = get_spkr_configuration(&type); + int rc = pmic_get_spkr_configuration(&type); if (!rc) { /* Hopefully, 100 additional chars is enough. The number is @@ -662,7 +662,7 @@ static ssize_t debugfs_spkr_set_configuration(struct file *filp, return -EINVAL; } - rc = set_spkr_configuration(&t); + rc = pmic_set_spkr_configuration(&t); if (!rc) printk(KERN_INFO "%s: succeeded, %s\n", __func__, buf); else @@ -681,7 +681,7 @@ static const struct file_operations debugfs_spkr_configuration_fops = { static int debugfs_mic_en(void *data, u64 val) { - int rc = mic_en((const unsigned char)val); + int rc = pmic_mic_en((const unsigned char)val); debugfs_log_return_status(rc, __func__, val); return rc; @@ -690,7 +690,7 @@ static int debugfs_mic_en(void *data, u64 val) static int debugfs_mic_is_en(void *data, u64 *val) { unsigned char enabled; - int rc = mic_is_en(&enabled); + int rc = pmic_mic_is_en(&enabled); if (!rc) *val = (u64)enabled; @@ -705,7 +705,7 @@ DEFINE_SIMPLE_ATTRIBUTE(debugfs_mic_en_fops, static int debugfs_mic_set_volt(void *data, u64 val) { - int rc = mic_set_volt((const enum mic_volt)val); + int rc = pmic_mic_set_volt((const enum mic_volt)val); debugfs_log_return_status(rc, __func__, val); return rc; @@ -714,7 +714,7 @@ static int debugfs_mic_set_volt(void *data, u64 val) static int debugfs_mic_get_volt(void *data, u64 *val) { enum mic_volt voltage; - int rc = mic_get_volt(&voltage); + int rc = pmic_mic_get_volt(&voltage); if (!rc) *val = (u64)voltage; @@ -730,7 +730,7 @@ DEFINE_SIMPLE_ATTRIBUTE(debugfs_mic_volt_fops, static uint16_t debugfs_flash_led_milliamps; static int debugfs_flash_led_set_current_execute(void *data, u64 val) { - int rc = flash_led_set_current((const uint16_t)val); + int rc = pmic_flash_led_set_current((const uint16_t)val); if (!rc) debugfs_flash_led_milliamps = (const uint16_t)val; @@ -754,7 +754,7 @@ DEFINE_SIMPLE_ATTRIBUTE(debugfs_flash_led_current_fops, static uint16_t debugfs_lcd_intensity; static int debugfs_set_lcd_intensity(void *data, u64 val) { - int rc = set_led_intensity(LED_LCD, (const uint16_t)val); + int rc = pmic_set_led_intensity(LED_LCD, (const uint16_t)val); if (!rc) debugfs_lcd_intensity = (const uint16_t)val; -- cgit v1.2.3 From 818b8617c1130ede2c913db962b9d51bef8d903d Mon Sep 17 00:00:00 2001 From: Saravana Kannan Date: Wed, 13 May 2009 16:38:16 -0700 Subject: [ARM] msm: acpuclock-8x50: Fix typo in efuse magic values. Signed-off-by: Saravana Kannan --- arch/arm/mach-msm/acpuclock-8x50.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/acpuclock-8x50.c b/arch/arm/mach-msm/acpuclock-8x50.c index c7dbc910c3cf..fd2400dedd53 100644 --- a/arch/arm/mach-msm/acpuclock-8x50.c +++ b/arch/arm/mach-msm/acpuclock-8x50.c @@ -512,16 +512,17 @@ static void __init acpu_freq_tbl_fixup(void) tcsr_spare2 = readl(TCSR_SPARE2_ADDR); /* Check if the register is supported and meaningful. */ - if ((tcsr_spare2 & 0xFF00) != 0xA500) { + if ((tcsr_spare2 & 0xFF00) != 0xA500 + && (tcsr_spare2 & 0xFF00) != 0xA000) { pr_info("Efuse data on Max ACPU freq not present.\n"); goto skip_efuse_fixup; } switch (tcsr_spare2 & 0xF0) { - case 0x30: + case 0x70: max_acpu_khz = 768000; break; - case 0x20: + case 0x30: case 0x00: max_acpu_khz = 998400; break; -- cgit v1.2.3 From 18e2ee7c8bf55df431cc1e7ff33ed7e550976643 Mon Sep 17 00:00:00 2001 From: Kuogee Hsieh Date: Fri, 15 May 2009 15:12:52 -0700 Subject: [ARM] msm: pmic: add new modem control APIs Implement pmic modem control APIs to provide modem control path to others Signed-off-by: Kuogee Hsieh --- arch/arm/mach-msm/Makefile | 4 +- arch/arm/mach-msm/include/mach/pmic.h | 470 ++++++++++-- arch/arm/mach-msm/pmic.c | 1263 +++++++++++++++++++-------------- arch/arm/mach-msm/pmic_debugfs.c | 1179 ++++++++++++++++++++++++++++++ 4 files changed, 2330 insertions(+), 586 deletions(-) create mode 100644 arch/arm/mach-msm/pmic_debugfs.c (limited to 'arch') diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 201e96d4fb8d..bd683a62883d 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -11,9 +11,8 @@ obj-y += rpc_hsusb.o obj-y += socinfo.o obj-y += cpufreq.o obj-y += nohlt.o +obj-y += pmic.o -obj-$(CONFIG_ARCH_MSM) += pmic.o -obj-$(CONFIG_ARCH_QSD) += pmic.o obj-$(CONFIG_ARCH_MSM_ARM11) += acpuclock.o obj-$(CONFIG_ARCH_MSM_SCORPION) += acpuclock-8x50.o sirc.o obj-$(CONFIG_CPU_V6) += idle-v6.o @@ -23,6 +22,7 @@ obj-$(CONFIG_MSM_FIQ_SUPPORT) += fiq_glue.o obj-$(CONFIG_MACH_TROUT) += board-trout-rfkill.o obj-$(CONFIG_MSM_SMD) += smd.o smd_tty.o smd_qmi.o smem_log.o obj-$(CONFIG_MSM_SMD) += smd_ctl2.o smd_loopback.o smd_nmea.o +obj-$(CONFIG_DEBUG_FS) += pmic_debugfs.o obj-$(CONFIG_MSM_RESET_MODEM) += reset_modem.o obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter.o obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_device.o diff --git a/arch/arm/mach-msm/include/mach/pmic.h b/arch/arm/mach-msm/include/mach/pmic.h index 71e23ab33263..4722f108d46d 100644 --- a/arch/arm/mach-msm/include/mach/pmic.h +++ b/arch/arm/mach-msm/include/mach/pmic.h @@ -55,88 +55,432 @@ * */ +#ifndef __ARCH_ARM_MACH_PMIC_H +#define __ARCH_ARM_MACH_PMIC_H + + enum spkr_left_right { - LEFT_SPKR, - RIGHT_SPKR, - SPKR_OUT_OF_RANGE /* Not valid */ + LEFT_SPKR, + RIGHT_SPKR, }; enum spkr_gain { - SPKR_GAIN_MINUS16DB, /* -16 db */ - SPKR_GAIN_MINUS12DB, /* -12 db */ - SPKR_GAIN_MINUS08DB, /* -08 db */ - SPKR_GAIN_MINUS04DB, /* -04 db */ - SPKR_GAIN_00DB, /* 00 db */ - SPKR_GAIN_PLUS04DB, /* +04 db */ - SPKR_GAIN_PLUS08DB, /* +08 db */ - SPKR_GAIN_PLUS12DB, /* +12 db */ - SPKR_GAIN_OUT_OF_RANGE /* Not valid */ + SPKR_GAIN_MINUS16DB, /* -16 db */ + SPKR_GAIN_MINUS12DB, /* -12 db */ + SPKR_GAIN_MINUS08DB, /* -08 db */ + SPKR_GAIN_MINUS04DB, /* -04 db */ + SPKR_GAIN_00DB, /* 00 db */ + SPKR_GAIN_PLUS04DB, /* +04 db */ + SPKR_GAIN_PLUS08DB, /* +08 db */ + SPKR_GAIN_PLUS12DB, /* +12 db */ +}; + +enum spkr_dly { + SPKR_DLY_10MS, /* ~10 ms delay */ + SPKR_DLY_100MS, /* ~100 ms delay */ +}; + +enum spkr_hpf_corner_freq { + SPKR_FREQ_1_39KHZ, /* 1.39 kHz */ + SPKR_FREQ_0_64KHZ, /* 0.64 kHz */ + SPKR_FREQ_0_86KHZ, /* 0.86 kHz */ + SPKR_FREQ_0_51KHZ, /* 0.51 kHz */ + SPKR_FREQ_1_06KHZ, /* 1.06 kHz */ + SPKR_FREQ_0_57KHZ, /* 0.57 kHz */ + SPKR_FREQ_0_73KHZ, /* 0.73 kHz */ + SPKR_FREQ_0_47KHZ, /* 0.47 kHz */ + SPKR_FREQ_1_20KHZ, /* 1.20 kHz */ + SPKR_FREQ_0_60KHZ, /* 0.60 kHz */ + SPKR_FREQ_0_76KHZ, /* 0.76 kHz */ + SPKR_FREQ_0_49KHZ, /* 0.49 kHz */ + SPKR_FREQ_0_95KHZ, /* 0.95 kHz */ + SPKR_FREQ_0_54KHZ, /* 0.54 kHz */ + SPKR_FREQ_0_68KHZ, /* 0.68 kHz */ + SPKR_FREQ_0_45KHZ, /* 0.45 kHz */ }; /* Turn the speaker on or off and enables or disables mute.*/ enum spkr_cmd { - SPKR_DISABLE, /* Enable Speaker */ - SPKR_ENABLE, /* Disable Speaker */ - SPKR_MUTE_OFF, /* turn speaker mute off, SOUND ON */ - SPKR_MUTE_ON, /* turn speaker mute on, SOUND OFF */ - SPKR_OFF, /* turn speaker OFF (speaker disable and mute on) */ - SPKR_ON, /* turn speaker ON (speaker enable and mute off) */ - SPKR_SET_FREQ_CMD, /* set speaker frequency */ - SPKR_GET_FREQ_CMD, /* get speaker frequency */ - SPKR_SET_GAIN_CMD, /* set speaker gain */ - SPKR_GET_GAIN_CMD, /* get speaker gain */ - SPKR_SET_DELAY_CMD, /* set speaker delay */ - SPKR_GET_DELAY_CMD, /* get speaker delay */ - SPKR_SET_PDM_MODE, - SPKR_SET_PWM_MODE, - SPKR_CMD_OUT_OF_RANGE /* Not valid */ + SPKR_DISABLE, /* Enable Speaker */ + SPKR_ENABLE, /* Disable Speaker */ + SPKR_MUTE_OFF, /* turn speaker mute off, SOUND ON */ + SPKR_MUTE_ON, /* turn speaker mute on, SOUND OFF */ + SPKR_OFF, /* turn speaker OFF (speaker disable and mute on) */ + SPKR_ON, /* turn speaker ON (speaker enable and mute off) */ + SPKR_SET_FREQ_CMD, /* set speaker frequency */ + SPKR_GET_FREQ_CMD, /* get speaker frequency */ + SPKR_SET_GAIN_CMD, /* set speaker gain */ + SPKR_GET_GAIN_CMD, /* get speaker gain */ + SPKR_SET_DELAY_CMD, /* set speaker delay */ + SPKR_GET_DELAY_CMD, /* get speaker delay */ + SPKR_SET_PDM_MODE, + SPKR_SET_PWM_MODE, }; struct spkr_config_mode { - uint32_t is_right_chan_en; - uint32_t is_left_chan_en; - uint32_t is_right_left_chan_added; - uint32_t is_stereo_en; - uint32_t is_usb_with_hpf_20hz; - uint32_t is_mux_bypassed; - uint32_t is_hpf_en; - uint32_t is_sink_curr_from_ref_volt_cir_en; + uint32_t is_right_chan_en; + uint32_t is_left_chan_en; + uint32_t is_right_left_chan_added; + uint32_t is_stereo_en; + uint32_t is_usb_with_hpf_20hz; + uint32_t is_mux_bypassed; + uint32_t is_hpf_en; + uint32_t is_sink_curr_from_ref_volt_cir_en; }; enum mic_volt { - MIC_VOLT_2_00V, /* 2.00 V */ - MIC_VOLT_1_93V, /* 1.93 V */ - MIC_VOLT_1_80V, /* 1.80 V */ - MIC_VOLT_1_73V, /* 1.73 V */ - MIC_VOLT_OUT_OF_RANGE /* Not valid */ + MIC_VOLT_2_00V, /* 2.00 V */ + MIC_VOLT_1_93V, /* 1.93 V */ + MIC_VOLT_1_80V, /* 1.80 V */ + MIC_VOLT_1_73V, /* 1.73 V */ }; enum ledtype { LED_LCD, LED_KEYPAD, - LED_TYPE_OUT_OF_RANGE -}; - -int pmic_spkr_en_right_chan(const unsigned char enable); -int pmic_spkr_is_right_chan_en(unsigned char *enabled); -int pmic_spkr_en_left_chan(const unsigned char enable); -int pmic_spkr_is_left_chan_en(unsigned char *enabled); -int pmic_spkr_is_en(const enum spkr_left_right left_right, - unsigned char *enabled); -int pmic_spkr_get_gain(const enum spkr_left_right left_right, - enum spkr_gain *gain); -int pmic_set_speaker_gain(const enum spkr_gain speaker_gain); -int pmic_speaker_cmd(const enum spkr_cmd cmd); -int pmic_set_spkr_configuration(const struct spkr_config_mode *t); -int pmic_get_spkr_configuration(struct spkr_config_mode *t); +}; + +enum flash_led_mode { + FLASH_LED_MODE__MANUAL, + FLASH_LED_MODE__DBUS1, + FLASH_LED_MODE__DBUS2, + FLASH_LED_MODE__DBUS3, +}; -int pmic_mic_en(const unsigned char enable); -int pmic_mic_is_en(unsigned char *enabled); -int pmic_mic_set_volt(const enum mic_volt type); +enum flash_led_pol { + FLASH_LED_POL__ACTIVE_HIGH, + FLASH_LED_POL__ACTIVE_LOW, +}; -/* Cannot use 'current' as the parameter name because 'current' is defined as - * a macro to get a pointer to the current task. - */ -int pmic_flash_led_set_current(const uint16_t milliamps); +enum switch_cmd { + OFF_CMD, + ON_CMD +}; + +enum vreg_lp_id { + PM_VREG_LP_MSMA_ID, + PM_VREG_LP_MSMP_ID, + PM_VREG_LP_MSME1_ID, + PM_VREG_LP_GP3_ID, + PM_VREG_LP_MSMC_ID, + PM_VREG_LP_MSME2_ID, + PM_VREG_LP_GP4_ID, + PM_VREG_LP_GP1_ID, + PM_VREG_LP_RFTX_ID, + PM_VREG_LP_RFRX1_ID, + PM_VREG_LP_RFRX2_ID, + PM_VREG_LP_WLAN_ID, + PM_VREG_LP_MMC_ID, + PM_VREG_LP_RUIM_ID, + PM_VREG_LP_MSMC0_ID, + PM_VREG_LP_GP2_ID, + PM_VREG_LP_GP5_ID, + PM_VREG_LP_GP6_ID, + PM_VREG_LP_MPLL_ID, + PM_VREG_LP_RFUBM_ID, + PM_VREG_LP_RFA_ID, + PM_VREG_LP_CDC2_ID, + PM_VREG_LP_RFTX2_ID, + PM_VREG_LP_USIM_ID, + PM_VREG_LP_USB2P6_ID, + PM_VREG_LP_TCXO_ID, + PM_VREG_LP_USB3P3_ID, + + PM_VREG_LP_MSME_ID = PM_VREG_LP_MSME1_ID, + /* backward compatible enums only */ + PM_VREG_LP_CAM_ID = PM_VREG_LP_GP1_ID, + PM_VREG_LP_MDDI_ID = PM_VREG_LP_GP2_ID, + PM_VREG_LP_RUIM2_ID = PM_VREG_LP_GP3_ID, + PM_VREG_LP_AUX_ID = PM_VREG_LP_GP4_ID, + PM_VREG_LP_AUX2_ID = PM_VREG_LP_GP5_ID, + PM_VREG_LP_BT_ID = PM_VREG_LP_GP6_ID, + PM_VREG_LP_MSMC_LDO_ID = PM_VREG_LP_MSMC_ID, + PM_VREG_LP_MSME1_LDO_ID = PM_VREG_LP_MSME1_ID, + PM_VREG_LP_MSME2_LDO_ID = PM_VREG_LP_MSME2_ID, + PM_VREG_LP_RFA1_ID = PM_VREG_LP_RFRX2_ID, + PM_VREG_LP_RFA2_ID = PM_VREG_LP_RFTX2_ID, + PM_VREG_LP_XO_ID = PM_VREG_LP_TCXO_ID +}; + +enum vreg_id { + PM_VREG_MSMA_ID = 0, + PM_VREG_MSMP_ID, + PM_VREG_MSME1_ID, + PM_VREG_MSMC1_ID, + PM_VREG_MSMC2_ID, + PM_VREG_GP3_ID, + PM_VREG_MSME2_ID, + PM_VREG_GP4_ID, + PM_VREG_GP1_ID, + PM_VREG_TCXO_ID, + PM_VREG_PA_ID, + PM_VREG_RFTX_ID, + PM_VREG_RFRX1_ID, + PM_VREG_RFRX2_ID, + PM_VREG_SYNT_ID, + PM_VREG_WLAN_ID, + PM_VREG_USB_ID, + PM_VREG_BOOST_ID, + PM_VREG_MMC_ID, + PM_VREG_RUIM_ID, + PM_VREG_MSMC0_ID, + PM_VREG_GP2_ID, + PM_VREG_GP5_ID, + PM_VREG_GP6_ID, + PM_VREG_RF_ID, + PM_VREG_RF_VCO_ID, + PM_VREG_MPLL_ID, + PM_VREG_S2_ID, + PM_VREG_S3_ID, + PM_VREG_RFUBM_ID, + PM_VREG_NCP_ID, + PM_VREG_RF2_ID, + PM_VREG_RFA_ID, + PM_VREG_CDC2_ID, + PM_VREG_RFTX2_ID, + PM_VREG_USIM_ID, + PM_VREG_USB2P6_ID, + PM_VREG_USB3P3_ID, + PM_VREG_EXTCDC1_ID, + PM_VREG_EXTCDC2_ID, + + /* backward compatible enums only */ + PM_VREG_MSME_ID = PM_VREG_MSME1_ID, + PM_VREG_MSME_BUCK_SMPS_ID = PM_VREG_MSME1_ID, + PM_VREG_MSME1_LDO_ID = PM_VREG_MSME1_ID, + PM_VREG_MSMC_ID = PM_VREG_MSMC1_ID, + PM_VREG_MSMC_LDO_ID = PM_VREG_MSMC1_ID, + PM_VREG_MSMC1_BUCK_SMPS_ID = PM_VREG_MSMC1_ID, + PM_VREG_MSME2_LDO_ID = PM_VREG_MSME2_ID, + PM_VREG_CAM_ID = PM_VREG_GP1_ID, + PM_VREG_MDDI_ID = PM_VREG_GP2_ID, + PM_VREG_RUIM2_ID = PM_VREG_GP3_ID, + PM_VREG_AUX_ID = PM_VREG_GP4_ID, + PM_VREG_AUX2_ID = PM_VREG_GP5_ID, + PM_VREG_BT_ID = PM_VREG_GP6_ID, + PM_VREG_RF1_ID = PM_VREG_RF_ID, + PM_VREG_S1_ID = PM_VREG_RF1_ID, + PM_VREG_5V_ID = PM_VREG_BOOST_ID, + PM_VREG_RFA1_ID = PM_VREG_RFRX2_ID, + PM_VREG_RFA2_ID = PM_VREG_RFTX2_ID, + PM_VREG_XO_ID = PM_VREG_TCXO_ID +}; + +enum vreg_pdown_id { + PM_VREG_PDOWN_MSMA_ID, + PM_VREG_PDOWN_MSMP_ID, + PM_VREG_PDOWN_MSME1_ID, + PM_VREG_PDOWN_MSMC1_ID, + PM_VREG_PDOWN_MSMC2_ID, + PM_VREG_PDOWN_GP3_ID, + PM_VREG_PDOWN_MSME2_ID, + PM_VREG_PDOWN_GP4_ID, + PM_VREG_PDOWN_GP1_ID, + PM_VREG_PDOWN_TCXO_ID, + PM_VREG_PDOWN_PA_ID, + PM_VREG_PDOWN_RFTX_ID, + PM_VREG_PDOWN_RFRX1_ID, + PM_VREG_PDOWN_RFRX2_ID, + PM_VREG_PDOWN_SYNT_ID, + PM_VREG_PDOWN_WLAN_ID, + PM_VREG_PDOWN_USB_ID, + PM_VREG_PDOWN_MMC_ID, + PM_VREG_PDOWN_RUIM_ID, + PM_VREG_PDOWN_MSMC0_ID, + PM_VREG_PDOWN_GP2_ID, + PM_VREG_PDOWN_GP5_ID, + PM_VREG_PDOWN_GP6_ID, + PM_VREG_PDOWN_RF_ID, + PM_VREG_PDOWN_RF_VCO_ID, + PM_VREG_PDOWN_MPLL_ID, + PM_VREG_PDOWN_S2_ID, + PM_VREG_PDOWN_S3_ID, + PM_VREG_PDOWN_RFUBM_ID, + /* new for HAN */ + PM_VREG_PDOWN_RF1_ID, + PM_VREG_PDOWN_RF2_ID, + PM_VREG_PDOWN_RFA_ID, + PM_VREG_PDOWN_CDC2_ID, + PM_VREG_PDOWN_RFTX2_ID, + PM_VREG_PDOWN_USIM_ID, + PM_VREG_PDOWN_USB2P6_ID, + PM_VREG_PDOWN_USB3P3_ID, + + /* backward compatible enums only */ + PM_VREG_PDOWN_CAM_ID = PM_VREG_PDOWN_GP1_ID, + PM_VREG_PDOWN_MDDI_ID = PM_VREG_PDOWN_GP2_ID, + PM_VREG_PDOWN_RUIM2_ID = PM_VREG_PDOWN_GP3_ID, + PM_VREG_PDOWN_AUX_ID = PM_VREG_PDOWN_GP4_ID, + PM_VREG_PDOWN_AUX2_ID = PM_VREG_PDOWN_GP5_ID, + PM_VREG_PDOWN_BT_ID = PM_VREG_PDOWN_GP6_ID, + PM_VREG_PDOWN_MSME_ID = PM_VREG_PDOWN_MSME1_ID, + PM_VREG_PDOWN_MSMC_ID = PM_VREG_PDOWN_MSMC1_ID, + PM_VREG_PDOWN_RFA1_ID = PM_VREG_PDOWN_RFRX2_ID, + PM_VREG_PDOWN_RFA2_ID = PM_VREG_PDOWN_RFTX2_ID, + PM_VREG_PDOWN_XO_ID = PM_VREG_PDOWN_TCXO_ID +}; + +enum mpp_which { + PM_MPP_1, + PM_MPP_2, + PM_MPP_3, + PM_MPP_4, + PM_MPP_5, + PM_MPP_6, + PM_MPP_7, + PM_MPP_8, + PM_MPP_9, + PM_MPP_10, + PM_MPP_11, + PM_MPP_12, + PM_MPP_13, + PM_MPP_14, + PM_MPP_15, + PM_MPP_16, + PM_MPP_17, + PM_MPP_18, + PM_MPP_19, + PM_MPP_20, + PM_MPP_21, + PM_MPP_22, + + PM_NUM_MPP_HAN = PM_MPP_4 + 1, + PM_NUM_MPP_KIP = PM_MPP_4 + 1, + PM_NUM_MPP_EPIC = PM_MPP_4 + 1, + PM_NUM_MPP_PM7500 = PM_MPP_22 + 1, + PM_NUM_MPP_PM6650 = PM_MPP_12 + 1, + PM_NUM_MPP_PM6658 = PM_MPP_12 + 1, + PM_NUM_MPP_PANORAMIX = PM_MPP_2 + 1, + PM_NUM_MPP_PM6640 = PM_NUM_MPP_PANORAMIX, + PM_NUM_MPP_PM6620 = PM_NUM_MPP_PANORAMIX +}; + +enum mpp_dlogic_level { + PM_MPP__DLOGIC__LVL_MSME, + PM_MPP__DLOGIC__LVL_MSMP, + PM_MPP__DLOGIC__LVL_RUIM, + PM_MPP__DLOGIC__LVL_MMC, + PM_MPP__DLOGIC__LVL_VDD, +}; + +enum mpp_dlogic_in_dbus { + PM_MPP__DLOGIC_IN__DBUS_NONE, + PM_MPP__DLOGIC_IN__DBUS1, + PM_MPP__DLOGIC_IN__DBUS2, + PM_MPP__DLOGIC_IN__DBUS3, +}; + +enum mpp_dlogic_out_ctrl { + PM_MPP__DLOGIC_OUT__CTRL_LOW, + PM_MPP__DLOGIC_OUT__CTRL_HIGH, + PM_MPP__DLOGIC_OUT__CTRL_MPP, + PM_MPP__DLOGIC_OUT__CTRL_NOT_MPP, +}; + +enum mpp_i_sink_level { + PM_MPP__I_SINK__LEVEL_5mA, + PM_MPP__I_SINK__LEVEL_10mA, + PM_MPP__I_SINK__LEVEL_15mA, + PM_MPP__I_SINK__LEVEL_20mA, + PM_MPP__I_SINK__LEVEL_25mA, + PM_MPP__I_SINK__LEVEL_30mA, + PM_MPP__I_SINK__LEVEL_35mA, + PM_MPP__I_SINK__LEVEL_40mA, +}; + +enum mpp_i_sink_switch { + PM_MPP__I_SINK__SWITCH_DIS, + PM_MPP__I_SINK__SWITCH_ENA, + PM_MPP__I_SINK__SWITCH_ENA_IF_MPP_HIGH, + PM_MPP__I_SINK__SWITCH_ENA_IF_MPP_LOW, +}; + +enum pm_vib_mot_mode { + PM_VIB_MOT_MODE__MANUAL, + PM_VIB_MOT_MODE__DBUS1, + PM_VIB_MOT_MODE__DBUS2, + PM_VIB_MOT_MODE__DBUS3, +}; + +enum pm_vib_mot_pol { + PM_VIB_MOT_POL__ACTIVE_HIGH, + PM_VIB_MOT_POL__ACTIVE_LOW, +}; + +struct rtc_time { + uint sec; +}; + +enum rtc_alarm { + PM_RTC_ALARM_1, +}; + + +int pmic_lp_mode_control(enum switch_cmd cmd, enum vreg_lp_id id); +int pmic_vreg_set_level(enum vreg_id vreg, int level); +int pmic_vreg_pull_down_switch(enum switch_cmd cmd, enum vreg_pdown_id id); +int pmic_secure_mpp_control_digital_output(enum mpp_which which, + enum mpp_dlogic_level level, enum mpp_dlogic_out_ctrl out); +int pmic_secure_mpp_config_i_sink(enum mpp_which which, + enum mpp_i_sink_level level, enum mpp_i_sink_switch onoff); +int pmic_secure_mpp_config_digital_input(enum mpp_which which, + enum mpp_dlogic_level level, enum mpp_dlogic_in_dbus dbus); +int pmic_rtc_start(struct rtc_time *time); +int pmic_rtc_stop(void); +int pmic_rtc_get_time(struct rtc_time *time); +int pmic_rtc_enable_alarm(enum rtc_alarm alarm, + struct rtc_time *time); +int pmic_rtc_disable_alarm(enum rtc_alarm alarm); +int pmic_rtc_get_alarm_time(enum rtc_alarm alarm, + struct rtc_time *time); +int pmic_rtc_get_alarm_status(uint *status); +int pmic_rtc_set_time_adjust(uint adjust); +int pmic_rtc_get_time_adjust(uint *adjust); +int pmic_speaker_cmd(const enum spkr_cmd cmd); +int pmic_set_spkr_configuration(struct spkr_config_mode *cfg); +int pmic_get_spkr_configuration(struct spkr_config_mode *cfg); +int pmic_spkr_en_right_chan(uint enable); +int pmic_spkr_is_right_chan_en(uint *enabled); +int pmic_spkr_en_left_chan(uint enable); +int pmic_spkr_is_left_chan_en(uint *enabled); +int pmic_spkr_en(enum spkr_left_right left_right, uint enabled); +int pmic_spkr_is_en(enum spkr_left_right left_right, uint *enabled); +int pmic_spkr_set_gain(enum spkr_left_right left_right, enum spkr_gain gain); +int pmic_spkr_get_gain(enum spkr_left_right left_right, enum spkr_gain *gain); +int pmic_set_speaker_gain(enum spkr_gain gain); +int pmic_set_speaker_delay(enum spkr_dly delay); +int pmic_speaker_1k6_zin_enable(uint enable); +int pmic_spkr_set_mux_hpf_corner_freq(enum spkr_hpf_corner_freq freq); +int pmic_spkr_get_mux_hpf_corner_freq(enum spkr_hpf_corner_freq *freq); +int pmic_spkr_select_usb_with_hpf_20hz(uint enable); +int pmic_spkr_is_usb_with_hpf_20hz(uint *enabled); +int pmic_spkr_bypass_mux(uint enable); +int pmic_spkr_is_mux_bypassed(uint *enabled); +int pmic_spkr_en_hpf(uint enable); +int pmic_spkr_is_hpf_en(uint *enabled); +int pmic_spkr_en_sink_curr_from_ref_volt_cir(uint enable); +int pmic_spkr_is_sink_curr_from_ref_volt_cir_en(uint *enabled); +int pmic_spkr_set_delay(enum spkr_left_right left_right, enum spkr_dly delay); +int pmic_spkr_get_delay(enum spkr_left_right left_right, enum spkr_dly *delay); +int pmic_spkr_en_mute(enum spkr_left_right left_right, uint enabled); +int pmic_spkr_is_mute_en(enum spkr_left_right left_right, uint *enabled); +int pmic_mic_en(uint enable); +int pmic_mic_is_en(uint *enabled); +int pmic_mic_set_volt(enum mic_volt vol); +int pmic_mic_get_volt(enum mic_volt *voltage); +int pmic_set_led_intensity(enum ledtype type, int level); +int pmic_flash_led_set_current(uint16_t milliamps); +int pmic_flash_led_set_mode(enum flash_led_mode mode); +int pmic_flash_led_set_polarity(enum flash_led_pol pol); +int pmic_spkr_add_right_left_chan(uint enable); +int pmic_spkr_is_right_left_chan_added(uint *enabled); +int pmic_spkr_en_stereo(uint enable); +int pmic_spkr_is_stereo_en(uint *enabled); +int pmic_vib_mot_set_volt(uint vol); +int pmic_vib_mot_set_mode(enum pm_vib_mot_mode mode); +int pmic_vib_mot_set_polarity(enum pm_vib_mot_pol pol); +int pmic_vid_en(uint enable); +int pmic_vid_is_en(uint *enabled); +int pmic_vid_load_detect_en(uint enable); -int pmic_set_led_intensity(const enum ledtype type, int val); +#endif diff --git a/arch/arm/mach-msm/pmic.c b/arch/arm/mach-msm/pmic.c index 6b04ee1426c0..19800ed7c9cb 100644 --- a/arch/arm/mach-msm/pmic.c +++ b/arch/arm/mach-msm/pmic.c @@ -55,35 +55,53 @@ * */ #include +#include #include #include #include +#include #include #include "smd_rpcrouter.h" -#define TRACE_SPEAKER 0 +#define TRACE_PMIC 0 -#if TRACE_SPEAKER -#define SPEAKER(x...) printk(KERN_INFO "[SPEAKER] " x) +#if TRACE_PMIC +#define PMIC(x...) printk(KERN_INFO "[PMIC] " x) #else -#define SPEAKER(x...) do {} while (0) +#define PMIC(x...) do {} while (0) #endif -/* rpc related */ -#define PMIC_RPC_TIMEOUT (5*HZ) - -#define SPEAKER_PDEV_NAME "rs00010001:00000000" -#define SPEAKER_RPC_PROG 0x30000061 -#define SPEAKER_RPC_VER 0x00010001 +#define LIB_NULL_PROC 0 +#define LIB_RPC_GLUE_CODE_INFO_REMOTE_PROC 1 +#define LP_MODE_CONTROL_PROC 2 +#define VREG_SET_LEVEL_PROC 3 +#define VREG_PULL_DOWN_SWITCH_PROC 4 +#define SECURE_MPP_CONFIG_DIGITAL_OUTPUT_PROC 5 +#define SECURE_MPP_CONFIG_I_SINK_PROC 6 +#define RTC_START_PROC 7 +#define RTC_STOP_PROC 8 +#define RTC_GET_TIME_PROC 9 +#define RTC_ENABLE_ALARM_PROC 10 +#define RTC_DISABLE_ALARM_PROC 11 +#define RTC_GET_ALARM_TIME_PROC 12 +#define RTC_GET_ALARM_STATUS_PROC 13 +#define RTC_SET_TIME_ADJUST_PROC 14 +#define RTC_GET_TIME_ADJUST_PROC 15 #define SET_LED_INTENSITY_PROC 16 #define FLASH_LED_SET_CURRENT_PROC 17 - +#define FLASH_LED_SET_MODE_PROC 18 +#define FLASH_LED_SET_POLARITY_PROC 19 #define SPEAKER_CMD_PROC 20 #define SET_SPEAKER_GAIN_PROC 21 - +#define VIB_MOT_SET_VOLT_PROC 22 +#define VIB_MOT_SET_MODE_PROC 23 +#define VIB_MOT_SET_POLARITY_PROC 24 +#define VID_EN_PROC 25 +#define VID_IS_EN_PROC 26 +#define VID_LOAD_DETECT_EN_PROC 27 #define MIC_EN_PROC 28 #define MIC_IS_EN_PROC 29 #define MIC_SET_VOLT_PROC 30 @@ -96,6 +114,37 @@ #define GET_SPKR_CONFIGURATION_PROC 37 #define SPKR_GET_GAIN_PROC 38 #define SPKR_IS_EN_PROC 39 +#define SPKR_EN_MUTE_PROC 40 +#define SPKR_IS_MUTE_EN_PROC 41 +#define SPKR_SET_DELAY_PROC 42 +#define SPKR_GET_DELAY_PROC 43 +#define SECURE_MPP_CONFIG_DIGITAL_INPUT_PROC 44 +#define SET_SPEAKER_DELAY_PROC 45 +#define SPEAKER_1K6_ZIN_ENABLE_PROC 46 +#define SPKR_SET_MUX_HPF_CORNER_FREQ_PROC 47 +#define SPKR_GET_MUX_HPF_CORNER_FREQ_PROC 48 +#define SPKR_IS_RIGHT_LEFT_CHAN_ADDED_PROC 49 +#define SPKR_EN_STEREO_PROC 50 +#define SPKR_IS_STEREO_EN_PROC 51 +#define SPKR_SELECT_USB_WITH_HPF_20HZ_PROC 52 +#define SPKR_IS_USB_WITH_HPF_20HZ_PROC 53 +#define SPKR_BYPASS_MUX_PROC 54 +#define SPKR_IS_MUX_BYPASSED_PROC 55 +#define SPKR_EN_HPF_PROC 56 +#define SPKR_IS_HPF_EN_PROC 57 +#define SPKR_EN_SINK_CURR_FROM_REF_VOLT_CIR_PROC 58 +#define SPKR_IS_SINK_CURR_FROM_REF_VOLT_CIR_EN_PROC 59 +#define SPKR_ADD_RIGHT_LEFT_CHAN_PROC 60 +#define SPKR_SET_GAIN_PROC 61 +#define SPKR_EN_PROC 62 + + +/* rpc related */ +#define PMIC_RPC_TIMEOUT (5*HZ) + +#define PMIC_PDEV_NAME "rs00010001:00000000" +#define PMIC_RPC_PROG 0x30000061 +#define PMIC_RPC_VER 0x00010001 /* error bit flags defined by modem side */ #define PM_ERR_FLAG__PAR1_OUT_OF_RANGE (0x0001) @@ -109,67 +158,86 @@ #define PM_ERR_FLAG__SBI_OPT_ERR (0x0080) #define PM_ERR_FLAG__FEATURE_NOT_SUPPORTED (0x0100) -struct std_rpc_req { - struct rpc_request_hdr req; - uint32_t value; -}; +#define PMIC_BUFF_SIZE 256 -struct std_rpc_reply { - struct rpc_reply_hdr hdr; - uint32_t result; +struct pmic_buf { + char *start; /* buffer start addr */ + char *end; /* buffer end addr */ + int size; /* buffer size */ + char *data; /* payload begin addr */ + int len; /* payload len */ }; -struct get_value_rep { - struct std_rpc_reply reply_hdr; - uint32_t MoreData; - uint32_t value; -}; +static DEFINE_MUTEX(pmic_mtx); -struct std_rpc_req2 { - struct rpc_request_hdr hdr; - uint32_t value1; - uint32_t value2; +struct pmic_ctrl { + int inited; + struct pmic_buf tbuf; + struct pmic_buf rbuf; + struct msm_rpc_endpoint *endpoint; }; -struct set_spkr_configuration_req { - struct rpc_request_hdr hdr; - uint32_t MoreData; - struct spkr_config_mode type; +static struct pmic_ctrl pmic_ctrl = { + .inited = -1, }; -struct get_spkr_configuration_rep { - struct std_rpc_reply reply_hdr; - uint32_t MoreData; - struct spkr_config_mode type; -}; - -static struct msm_rpc_endpoint *endpoint; +static int pmic_rpc_req_reply(struct pmic_buf *tbuf, + struct pmic_buf *rbuf, int proc); +static int pmic_rpc_set_only(uint data0, uint data1, uint data2, + uint data3, int num, int proc); +static int pmic_rpc_set_struct(int, uint, uint *data, uint size, int proc); +static int pmic_rpc_set_get(uint setdata, uint *getdata, int size, int proc); +static int pmic_rpc_get_only(uint *getdata, int size, int proc); -static int check_and_connect(void) +static int pmic_buf_init(void) { - if (endpoint != NULL) - return 0; + struct pmic_ctrl *pm = &pmic_ctrl; - endpoint = msm_rpc_connect(SPEAKER_RPC_PROG, SPEAKER_RPC_VER, 0); - if (endpoint == NULL) { - return -ENODEV; - } else if (IS_ERR(endpoint)) { - int rc = PTR_ERR(endpoint); - printk(KERN_ERR "%s: init rpc failed! rc = %d\n", - __func__, rc); - endpoint = NULL; - return rc; + memset(&pmic_ctrl, 0, sizeof(pmic_ctrl)); + + pm->tbuf.start = kmalloc(PMIC_BUFF_SIZE, GFP_KERNEL); + if (pm->tbuf.start == NULL) { + printk(KERN_ERR "%s:%u\n", __func__, __LINE__); + return -ENOMEM; + } + + pm->tbuf.data = pm->tbuf.start; + pm->tbuf.size = PMIC_BUFF_SIZE; + pm->tbuf.end = pm->tbuf.start + PMIC_BUFF_SIZE; + pm->tbuf.len = 0; + + pm->rbuf.start = kmalloc(PMIC_BUFF_SIZE, GFP_KERNEL); + if (pm->rbuf.start == NULL) { + kfree(pm->tbuf.start); + printk(KERN_ERR "%s:%u\n", __func__, __LINE__); + return -ENOMEM; } + pm->rbuf.data = pm->rbuf.start; + pm->rbuf.size = PMIC_BUFF_SIZE; + pm->rbuf.end = pm->rbuf.start + PMIC_BUFF_SIZE; + pm->rbuf.len = 0; + + pm->inited = 1; + return 0; } -static int modem_to_linux_err(u16 err_netendian) +static inline void pmic_buf_reserve(struct pmic_buf *bp, int len) +{ + bp->data += len; +} + +static inline void pmic_buf_reset(struct pmic_buf *bp) { - u32 err; - if (!err_netendian) + bp->data = bp->start; + bp->len = 0; +} + +static int modem_to_linux_err(uint err) +{ + if (err == 0) return 0; - err = be32_to_cpu(err_netendian); if (err & PM_ERR_FLAG__ALL_PARMS_OUT_OF_RANGE) return -EINVAL; /* PM_ERR_FLAG__PAR[1..5]_OUT_OF_RANGE */ @@ -182,639 +250,792 @@ static int modem_to_linux_err(u16 err_netendian) return -EPERM; } -static int do_remote_value(const uint32_t set_value, - uint32_t * const get_value, - const uint32_t proc) +static int pmic_put_tx_data(struct pmic_buf *tp, uint datav) { - struct std_rpc_req req; - struct std_rpc_reply std_rep; - struct get_value_rep rep; - void *rep_ptr; - int rep_size, rc = check_and_connect(); - - if (rc) /* connect problem */ - return rc; + uint *lp; - if (get_value != NULL) { /* get value */ - req.value = cpu_to_be32(1); /* output_pointer_not_null */ - rep_size = sizeof(rep); - rep_ptr = &rep; - } else { /* set value */ - req.value = cpu_to_be32(set_value); - rep_size = sizeof(std_rep); - rep_ptr = &std_rep; + if ((tp->size - tp->len) < sizeof(datav)) { + printk(KERN_ERR "%s: OVERFLOW size=%d len=%d\n", + __func__, tp->size, tp->len); + return -1; } - rc = msm_rpc_call_reply(endpoint, proc, - &req, sizeof(req), - rep_ptr, rep_size, - PMIC_RPC_TIMEOUT); - if (rc < 0) - return rc; - if (get_value != NULL) { /* get value */ - if (!rep.reply_hdr.result) { - if (!rep.MoreData) - return -ENOMSG; + lp = (uint *)tp->data; + *lp = cpu_to_be32(datav); + tp->data += sizeof(datav); + tp->len += sizeof(datav); - *get_value = be32_to_cpu(rep.value); - } - rc = modem_to_linux_err(rep.reply_hdr.result); - } else { - rc = modem_to_linux_err(std_rep.result); - } - return rc; -} - -int pmic_spkr_en_right_chan(const unsigned char enable) -{ - return do_remote_value(enable, NULL, SPKR_EN_RIGHT_CHAN_PROC); + return sizeof(datav); } -EXPORT_SYMBOL(pmic_spkr_en_right_chan); -int pmic_spkr_is_right_chan_en(unsigned char * const enabled) +static int pmic_pull_rx_data(struct pmic_buf *rp, uint *datap) { - uint32_t word_enabled; - int rc; + uint *lp; - if (enabled == NULL) - return modem_to_linux_err(PM_ERR_FLAG__PAR1_OUT_OF_RANGE); + if (rp->len < sizeof(*datap)) { + printk(KERN_ERR "%s: UNDERRUN len=%d\n", __func__, rp->len); + return -1; + } + lp = (uint *)rp->data; + *datap = be32_to_cpu(*lp); + rp->data += sizeof(*datap); + rp->len -= sizeof(*datap); - rc = do_remote_value(0, &word_enabled, SPKR_IS_RIGHT_CHAN_EN_PROC); - if (!rc) - *enabled = (unsigned char)word_enabled; - return rc; + return sizeof(*datap); } -EXPORT_SYMBOL(pmic_spkr_is_right_chan_en); -int pmic_spkr_en_left_chan(const unsigned char enable) -{ - return do_remote_value(enable, NULL, SPKR_EN_LEFT_CHAN_PROC); -} -EXPORT_SYMBOL(pmic_spkr_en_left_chan); -int pmic_spkr_is_left_chan_en(unsigned char * const enabled) +/* + * + * +-------------------+ + * | PROC cmd layer | + * +-------------------+ + * | RPC layer | + * +-------------------+ + * + * 1) network byte order + * 2) RPC request header(40 bytes) and RPC reply header (24 bytes) + * 3) each transaction consists of a request and reply + * 3) PROC (comamnd) layer has its own sub-protocol defined + * 4) sub-protocol can be grouped to follwoing 7 cases: + * a) set one argument, no get + * b) set two argument, no get + * c) set three argument, no get + * d) set a struct, no get + * e) set a argument followed by a struct, no get + * f) set a argument, get a argument + * g) no set, get either a argument or a struct + */ + +/** + * pmic_rpc_req_reply() - send request and wait for reply + * @tbuf: buffer contains arguments + * @rbuf: buffer to be filled with arguments at reply + * @proc: command/request id + * + * This function send request to modem and wait until reply received + */ +static int pmic_rpc_req_reply(struct pmic_buf *tbuf, struct pmic_buf *rbuf, + int proc) { - uint32_t word_enabled; - int rc; + struct pmic_ctrl *pm = &pmic_ctrl; + int ans, len; + + + if (pm->endpoint == NULL) { + pm->endpoint = msm_rpc_connect(PMIC_RPC_PROG, + PMIC_RPC_VER, 0); + if (pm->endpoint == NULL) { + return -ENODEV; + } else if (IS_ERR(pm->endpoint)) { + ans = PTR_ERR(pm->endpoint); + printk(KERN_ERR "%s: init rpc failed! ans = %d\n", + __func__, ans); + pm->endpoint = NULL; + return ans; + } + } - if (enabled == NULL) - return modem_to_linux_err(PM_ERR_FLAG__PAR1_OUT_OF_RANGE); + /* + * data is point to next available space at this moment, + * move it back to beginning of request header and increase + * the length + */ + tbuf->data = tbuf->start; + tbuf->len += sizeof(struct rpc_request_hdr); + + len = msm_rpc_call_reply(pm->endpoint, proc, + tbuf->data, tbuf->len, + rbuf->data, rbuf->size, + PMIC_RPC_TIMEOUT); - rc = do_remote_value(0, &word_enabled, SPKR_IS_LEFT_CHAN_EN_PROC); - if (!rc) - *enabled = (unsigned char)word_enabled; - return rc; -} -EXPORT_SYMBOL(pmic_spkr_is_left_chan_en); + if (len <= 0) { + printk(KERN_ERR "%s: rpc failed! len = %d\n", __func__, len); + pm->endpoint = NULL; /* re-connect later ? */ + return len; + } -int pmic_spkr_is_en(const enum spkr_left_right left_right, - unsigned char * const enabled) -{ - if (left_right >= SPKR_OUT_OF_RANGE) - return -EINVAL; + rbuf->len = len; + /* strip off rpc_reply_hdr */ + rbuf->data += sizeof(struct rpc_reply_hdr); + rbuf->len -= sizeof(struct rpc_reply_hdr); - return left_right == LEFT_SPKR ? - pmic_spkr_is_left_chan_en(enabled) : - pmic_spkr_is_right_chan_en(enabled); + return rbuf->len; } -EXPORT_SYMBOL(pmic_spkr_is_en); -static int do_std_rpc_req2(struct get_value_rep *rep, uint32_t proc, - uint32_t value1, uint32_t value2) +/** + * pmic_rpc_set_only() - set arguments and no get + * @data0: first argumrnt + * @data1: second argument + * @data2: third argument + * @data3: fourth argument + * @num: number of argument + * @proc: command/request id + * + * This function covers case a, b, and c + */ +static int pmic_rpc_set_only(uint data0, uint data1, uint data2, uint data3, + int num, int proc) { - struct std_rpc_req2 req; - int rc; + struct pmic_ctrl *pm = &pmic_ctrl; + struct pmic_buf *tp; + struct pmic_buf *rp; + int stat; - rc = check_and_connect(); - if (rc) { - printk(KERN_ERR "%s: can't make rpc connection!\n", __func__); - return rc; - } - req.value1 = cpu_to_be32(value1); - req.value2 = cpu_to_be32(value2); - - rc = msm_rpc_call_reply(endpoint, proc, - &req, sizeof(req), - rep, sizeof(*rep), - PMIC_RPC_TIMEOUT); - if (rc < 0) { - printk(KERN_ERR - "%s: msm_rpc_call_reply failed! proc=%d rc=%d\n", - __func__, proc, rc); - return rc; + if (mutex_lock_interruptible(&pmic_mtx)) + return -ERESTARTSYS; + + if (pm->inited <= 0) { + stat = pmic_buf_init(); + if (stat < 0) { + mutex_unlock(&pmic_mtx); + return stat; + } } - return modem_to_linux_err(rep->reply_hdr.result); -} + tp = &pm->tbuf; + rp = &pm->rbuf; -int pmic_spkr_get_gain(const enum spkr_left_right left_right, - enum spkr_gain * const gain) -{ - struct get_value_rep rep; - int rc; + pmic_buf_reset(tp); + pmic_buf_reserve(tp, sizeof(struct rpc_request_hdr)); + pmic_buf_reset(rp); - if (left_right >= SPKR_OUT_OF_RANGE) - return -EINVAL; + if (num > 0) + pmic_put_tx_data(tp, data0); - if (gain == NULL) - return modem_to_linux_err(PM_ERR_FLAG__PAR1_OUT_OF_RANGE); + if (num > 1) + pmic_put_tx_data(tp, data1); - rc = do_std_rpc_req2(&rep, SPKR_GET_GAIN_PROC, (uint32_t)left_right, 1); + if (num > 2) + pmic_put_tx_data(tp, data2); - if (!rc && !rep.reply_hdr.result) { - if (!rep.MoreData) - return -ENOMSG; + if (num > 3) + pmic_put_tx_data(tp, data3); - *gain = (enum spkr_gain)be32_to_cpu(rep.value); + stat = pmic_rpc_req_reply(tp, rp, proc); + if (stat < 0) { + mutex_unlock(&pmic_mtx); + return stat; } - return rc; -} -EXPORT_SYMBOL(pmic_spkr_get_gain); + pmic_pull_rx_data(rp, &stat); /* result from server */ -int pmic_set_speaker_gain(const enum spkr_gain speaker_gain) -{ - if (speaker_gain >= SPKR_GAIN_OUT_OF_RANGE) - return -EINVAL; + mutex_unlock(&pmic_mtx); - return do_remote_value(speaker_gain, NULL, SET_SPEAKER_GAIN_PROC); + return modem_to_linux_err(stat); } -EXPORT_SYMBOL(pmic_set_speaker_gain); -int pmic_speaker_cmd(const enum spkr_cmd cmd) +/** + * pmic_rpc_set_struct() - set the whole struct + * @xflag: indicates an extra argument + * @xdata: the extra argument + * @*data: starting address of struct + * @size: size of struct + * @proc: command/request id + * + * This fucntion covers case d and e + */ +static int pmic_rpc_set_struct(int xflag, uint xdata, uint *data, uint size, + int proc) { - if (cmd >= SPKR_CMD_OUT_OF_RANGE) - return -EINVAL; + struct pmic_ctrl *pm = &pmic_ctrl; + struct pmic_buf *tp; + struct pmic_buf *rp; + int i, stat, more_data; - return do_remote_value(cmd, NULL, SPEAKER_CMD_PROC); -} -EXPORT_SYMBOL(pmic_speaker_cmd); -int pmic_set_spkr_configuration(const struct spkr_config_mode * const t) -{ - struct set_spkr_configuration_req req; - struct std_rpc_reply rep; - int i, rc; + if (mutex_lock_interruptible(&pmic_mtx)) + return -ERESTARTSYS; - if (t == NULL) - return modem_to_linux_err(PM_ERR_FLAG__PAR1_OUT_OF_RANGE); + if (pm->inited <= 0) { + stat = pmic_buf_init(); + if (stat < 0) { + mutex_unlock(&pmic_mtx); + return stat; + } + } - rc = check_and_connect(); - if (rc) - return rc; + tp = &pm->tbuf; + rp = &pm->rbuf; - for (i = 0; i < sizeof(*t)/sizeof(uint32_t); i++) - ((uint32_t *)&req.type)[i] = cpu_to_be32(((uint32_t *)t)[i]); + pmic_buf_reset(tp); + pmic_buf_reserve(tp, sizeof(struct rpc_request_hdr)); + pmic_buf_reset(rp); - req.MoreData = cpu_to_be32(1); - rc = msm_rpc_call_reply(endpoint, SET_SPKR_CONFIGURATION_PROC, - &req, sizeof(req), - &rep, sizeof(rep), - PMIC_RPC_TIMEOUT); - if (rc < 0) - return rc; + if (xflag) + pmic_put_tx_data(tp, xdata); + + more_data = 1; /* tell server there have more data followed */ + pmic_put_tx_data(tp, more_data); + + size >>= 2; + for (i = 0; i < size; i++) { + pmic_put_tx_data(tp, *data); + data++; + } + + stat = pmic_rpc_req_reply(tp, rp, proc); + if (stat < 0) { + mutex_unlock(&pmic_mtx); + return stat; + } + + pmic_pull_rx_data(rp, &stat); /* result from server */ - return modem_to_linux_err(rep.result); + mutex_unlock(&pmic_mtx); + + return modem_to_linux_err(stat); } -EXPORT_SYMBOL(pmic_set_spkr_configuration); -int pmic_get_spkr_configuration(struct spkr_config_mode * const t) +/** + * pmic_rpc_set_get() - set one argument and get one argument + * @setdata: set argument + * @*getdata: memory to store argumnet + * @size: size of memory + * @proc: command/request id + * + * This function covers case f + */ +static int pmic_rpc_set_get(uint setdata, uint *getdata, int size, int proc) { - struct std_rpc_req req; - struct get_spkr_configuration_rep rep; - int rc; + struct pmic_ctrl *pm = &pmic_ctrl; + struct pmic_buf *tp; + struct pmic_buf *rp; + unsigned int *lp; + int i, stat, more_data; - if (t == NULL) - return modem_to_linux_err(PM_ERR_FLAG__PAR1_OUT_OF_RANGE); - rc = check_and_connect(); - if (rc) - return rc; + if (mutex_lock_interruptible(&pmic_mtx)) + return -ERESTARTSYS; + + if (pm->inited <= 0) { + stat = pmic_buf_init(); + if (stat < 0) { + mutex_unlock(&pmic_mtx); + return stat; + } + } - req.value = cpu_to_be32(1); /* output_pointer_not_null */ - rc = msm_rpc_call_reply(endpoint, GET_SPKR_CONFIGURATION_PROC, - &req, sizeof(req), - &rep, sizeof(rep), - PMIC_RPC_TIMEOUT); - if (rc < 0) - return rc; + tp = &pm->tbuf; + rp = &pm->rbuf; - if (!rep.reply_hdr.result) { - int i; + pmic_buf_reset(tp); + pmic_buf_reserve(tp, sizeof(struct rpc_request_hdr)); + pmic_buf_reset(rp); - if (!rep.MoreData) - return -ENOMSG; + pmic_put_tx_data(tp, setdata); - for (i = 0; i < sizeof(*t)/sizeof(uint32_t); i++) - ((uint32_t *)t)[i] = - be32_to_cpu(((uint32_t *)&rep.type)[i]); + /* + * more_data = TRUE to ask server reply with requested datum + * otherwise, server will reply without datum + */ + more_data = (getdata != NULL); + pmic_put_tx_data(tp, more_data); + + stat = pmic_rpc_req_reply(tp, rp, proc); + if (stat < 0) { + mutex_unlock(&pmic_mtx); + return stat; } - return modem_to_linux_err(rep.reply_hdr.result); -} -EXPORT_SYMBOL(pmic_get_spkr_configuration); + pmic_pull_rx_data(rp, &stat); /* result from server */ + pmic_pull_rx_data(rp, &more_data); -int pmic_mic_en(const unsigned char enable) -{ - return do_remote_value(enable, NULL, MIC_EN_PROC); + if (more_data) { /* more data followed */ + size >>= 2; + lp = getdata; + for (i = 0; i < size; i++) { + if (pmic_pull_rx_data(rp, lp++) < 0) + break; /* not supposed to happen */ + } + } + + mutex_unlock(&pmic_mtx); + + return modem_to_linux_err(stat); } -EXPORT_SYMBOL(pmic_mic_en); -int pmic_mic_is_en(unsigned char * const enabled) +/** + * pmic_rpc_get_only() - get one or more than one arguments + * @*getdata: memory to store arguments + * @size: size of mmory + * @proc: command/request id + * + * This function covers case g + */ +static int pmic_rpc_get_only(uint *getdata, int size, int proc) { - uint32_t word_enabled; - int rc; + struct pmic_ctrl *pm = &pmic_ctrl; + struct pmic_buf *tp; + struct pmic_buf *rp; + unsigned int *lp; + int i, stat, more_data; + + + if (mutex_lock_interruptible(&pmic_mtx)) + return -ERESTARTSYS; + + if (pm->inited <= 0) { + stat = pmic_buf_init(); + if (stat < 0) { + mutex_unlock(&pmic_mtx); + return stat; + } + } + + tp = &pm->tbuf; + rp = &pm->rbuf; + + pmic_buf_reset(tp); + pmic_buf_reserve(tp, sizeof(struct rpc_request_hdr)); + pmic_buf_reset(rp); + + /* + * more_data = TRUE to ask server reply with requested datum + * otherwise, server will reply without datum + */ + more_data = (getdata != NULL); + pmic_put_tx_data(tp, more_data); + + stat = pmic_rpc_req_reply(tp, rp, proc); + if (stat < 0) { + mutex_unlock(&pmic_mtx); + return stat; + } - if (enabled == NULL) - return modem_to_linux_err(PM_ERR_FLAG__PAR1_OUT_OF_RANGE); + pmic_pull_rx_data(rp, &stat); /* result from server */ + pmic_pull_rx_data(rp, &more_data); - rc = do_remote_value(0, &word_enabled, MIC_IS_EN_PROC); - if (!rc) - *enabled = (unsigned char)word_enabled; + if (more_data) { /* more data followed */ + size >>= 2; + lp = getdata; + for (i = 0; i < size; i++) { + if (pmic_pull_rx_data(rp, lp++) < 0) + break; /* not supposed to happen */ + } + } - return rc; + mutex_unlock(&pmic_mtx); + + return modem_to_linux_err(stat); } -EXPORT_SYMBOL(pmic_mic_is_en); -int pmic_mic_set_volt(const enum mic_volt type) -{ - if (type >= MIC_VOLT_OUT_OF_RANGE) - return -EINVAL; - return do_remote_value(type, NULL, MIC_SET_VOLT_PROC); +int pmic_lp_mode_control(enum switch_cmd cmd, enum vreg_lp_id id) +{ + return pmic_rpc_set_only(cmd, id, 0, 0, 2, LP_MODE_CONTROL_PROC); } -EXPORT_SYMBOL(pmic_mic_set_volt); +EXPORT_SYMBOL(pmic_lp_mode_control); -int pmic_mic_get_volt(enum mic_volt * const voltage) +int pmic_vreg_set_level(enum vreg_id vreg, int level) { - if (voltage == NULL) - return modem_to_linux_err(PM_ERR_FLAG__PAR1_OUT_OF_RANGE); + return pmic_rpc_set_only(vreg, level, 0, 0, 2, VREG_SET_LEVEL_PROC); +} +EXPORT_SYMBOL(pmic_vreg_set_level); - return do_remote_value(0, voltage, MIC_GET_VOLT_PROC); +int pmic_vreg_pull_down_switch(enum switch_cmd cmd, enum vreg_pdown_id id) +{ + return pmic_rpc_set_only(cmd, id, 0, 0, 2, VREG_PULL_DOWN_SWITCH_PROC); } -EXPORT_SYMBOL(pmic_mic_get_volt); +EXPORT_SYMBOL(pmic_vreg_pull_down_switch); -/* Cannot use 'current' as the parameter name because 'current' is defined as - * a macro to get a pointer to the current task. - */ -int pmic_flash_led_set_current(const uint16_t milliamps) +int pmic_secure_mpp_control_digital_output(enum mpp_which which, + enum mpp_dlogic_level level, + enum mpp_dlogic_out_ctrl out) { - return do_remote_value(milliamps, NULL, FLASH_LED_SET_CURRENT_PROC); + return pmic_rpc_set_only(which, level, out, 0, 3, + SECURE_MPP_CONFIG_DIGITAL_OUTPUT_PROC); } -EXPORT_SYMBOL(pmic_flash_led_set_current); +EXPORT_SYMBOL(pmic_secure_mpp_control_digital_output); -int pmic_set_led_intensity(const enum ledtype type, int level) +int pmic_secure_mpp_config_i_sink(enum mpp_which which, + enum mpp_i_sink_level level, + enum mpp_i_sink_switch onoff) { - struct get_value_rep rep; + return pmic_rpc_set_only(which, level, onoff, 0, 3, + SECURE_MPP_CONFIG_I_SINK_PROC); +} +EXPORT_SYMBOL(pmic_secure_mpp_config_i_sink); - if (type >= LED_TYPE_OUT_OF_RANGE) - return -EINVAL; +int pmic_secure_mpp_config_digital_input(enum mpp_which which, + enum mpp_dlogic_level level, + enum mpp_dlogic_in_dbus dbus) +{ + return pmic_rpc_set_only(which, level, dbus, 0, 3, + SECURE_MPP_CONFIG_DIGITAL_INPUT_PROC); +} +EXPORT_SYMBOL(pmic_secure_mpp_config_digital_input); - return do_std_rpc_req2(&rep, SET_LED_INTENSITY_PROC, - (uint32_t)type, level); +int pmic_rtc_start(struct rtc_time *time) +{ + return pmic_rpc_set_struct(0, 0, (uint *)time, sizeof(*time), + RTC_START_PROC); } -EXPORT_SYMBOL(pmic_set_led_intensity); +EXPORT_SYMBOL(pmic_rtc_start); -#if defined(CONFIG_DEBUG_FS) -static void debugfs_log_return_status(const int caller_rc, - const char * const caller__func__, - const u64 caller_val) +int pmic_rtc_stop(void) { - if (!caller_rc) - printk(KERN_INFO "%s: succeeded, val %llu\n", - caller__func__, caller_val); - else - printk(KERN_ERR "%s: ERROR! val %llu, rc:%d(%#x)\n", - caller__func__, caller_val, caller_rc, caller_rc); + return pmic_rpc_set_only(0, 0, 0, 0, 0, RTC_STOP_PROC); } +EXPORT_SYMBOL(pmic_rtc_stop); -static int debugfs_spkr_en_chan(void *data, u64 val) +int pmic_rtc_get_time(struct rtc_time *time) { - int rc = ((enum spkr_left_right)data) == LEFT_SPKR ? - pmic_spkr_en_left_chan((const unsigned char)val) : - pmic_spkr_en_right_chan((const unsigned char)val); + return pmic_rpc_get_only((uint *)time, sizeof(*time), + RTC_GET_TIME_PROC); +} +EXPORT_SYMBOL(pmic_rtc_get_time); - debugfs_log_return_status(rc, __func__, val); - return rc; +int pmic_rtc_enable_alarm(enum rtc_alarm alarm, + struct rtc_time *time) +{ + return pmic_rpc_set_struct(1, alarm, (uint *)time, sizeof(*time), + RTC_ENABLE_ALARM_PROC); } +EXPORT_SYMBOL(pmic_rtc_enable_alarm); -static int debugfs_spkr_is_chan_en(void *data, u64 *val) +int pmic_rtc_disable_alarm(enum rtc_alarm alarm) { - unsigned char enabled; - int rc = ((enum spkr_left_right)data) == LEFT_SPKR ? - pmic_spkr_is_left_chan_en(&enabled) : - pmic_spkr_is_right_chan_en(&enabled); + return pmic_rpc_set_only(alarm, 0, 0, 0, 1, RTC_DISABLE_ALARM_PROC); +} +EXPORT_SYMBOL(pmic_rtc_disable_alarm); - if (!rc) - *val = (u64)enabled; +int pmic_rtc_get_alarm_time(enum rtc_alarm alarm, + struct rtc_time *time) +{ + return pmic_rpc_set_get(alarm, (uint *)time, sizeof(*time), + RTC_GET_ALARM_TIME_PROC); +} +EXPORT_SYMBOL(pmic_rtc_get_alarm_time); - debugfs_log_return_status(rc, __func__, *val); - return rc; +int pmic_rtc_get_alarm_status(uint *status) +{ + return pmic_rpc_get_only(status, sizeof(*status), + RTC_GET_ALARM_STATUS_PROC); } -DEFINE_SIMPLE_ATTRIBUTE(debugfs_spkr_en_chan_fops, - debugfs_spkr_is_chan_en, - debugfs_spkr_en_chan, - "%llu\n"); +EXPORT_SYMBOL(pmic_rtc_get_alarm_status); -static int debugfs_spkr_get_gain(void *data, u64 *val) +int pmic_rtc_set_time_adjust(uint adjust) { - enum spkr_gain gain; - int rc = pmic_spkr_get_gain((enum spkr_left_right)data, &gain); + return pmic_rpc_set_only(adjust, 0, 0, 0, 1, + RTC_SET_TIME_ADJUST_PROC); +} +EXPORT_SYMBOL(pmic_rtc_set_time_adjust); - if (!rc) - *val = (u64)gain; +int pmic_rtc_get_time_adjust(uint *adjust) +{ + return pmic_rpc_get_only(adjust, sizeof(*adjust), + RTC_GET_TIME_ADJUST_PROC); +} +EXPORT_SYMBOL(pmic_rtc_get_time_adjust); - debugfs_log_return_status(rc, __func__, *val); - return rc; +/* + * generic speaker + */ +int pmic_speaker_cmd(const enum spkr_cmd cmd) +{ + return pmic_rpc_set_only(cmd, 0, 0, 0, 1, SPEAKER_CMD_PROC); } +EXPORT_SYMBOL(pmic_speaker_cmd); -static int debugfs_set_speaker_gain(void *data, u64 val) +int pmic_set_spkr_configuration(struct spkr_config_mode *cfg) { - int rc = pmic_set_speaker_gain((enum spkr_gain)val); + return pmic_rpc_set_struct(0, 0, (uint *)cfg, sizeof(*cfg), + SET_SPKR_CONFIGURATION_PROC); +} +EXPORT_SYMBOL(pmic_set_spkr_configuration); - debugfs_log_return_status(rc, __func__, val); - return rc; +int pmic_get_spkr_configuration(struct spkr_config_mode *cfg) +{ + return pmic_rpc_get_only((uint *)cfg, sizeof(*cfg), + GET_SPKR_CONFIGURATION_PROC); } -DEFINE_SIMPLE_ATTRIBUTE(debugfs_spkr_gain_fops, - debugfs_spkr_get_gain, - debugfs_set_speaker_gain, - "%llu\n"); +EXPORT_SYMBOL(pmic_get_spkr_configuration); -static int debugfs_speaker_cmd(void *data, u64 val) +int pmic_spkr_en_right_chan(uint enable) { - int rc = pmic_speaker_cmd((const enum spkr_cmd)val); + return pmic_rpc_set_only(enable, 0, 0, 0, 1, SPKR_EN_RIGHT_CHAN_PROC); +} +EXPORT_SYMBOL(pmic_spkr_en_right_chan); - debugfs_log_return_status(rc, __func__, val); - return rc; +int pmic_spkr_is_right_chan_en(uint *enabled) +{ + return pmic_rpc_get_only(enabled, sizeof(*enabled), + SPKR_IS_RIGHT_CHAN_EN_PROC); } -DEFINE_SIMPLE_ATTRIBUTE(debugfs_speaker_cmd_fops, - NULL, - debugfs_speaker_cmd, - "%llu\n"); +EXPORT_SYMBOL(pmic_spkr_is_right_chan_en); -static int debugfs_spkr_configuration_open(struct inode *inode, - struct file *filp) +int pmic_spkr_en_left_chan(uint enable) { - filp->private_data = inode->i_private; - return 0; + return pmic_rpc_set_only(enable, 0, 0, 0, 1, SPKR_EN_LEFT_CHAN_PROC); } +EXPORT_SYMBOL(pmic_spkr_en_left_chan); -#define debugfs_speaker_configuration_format_str \ - "%u,%u,%u,%u,%u,%u,%u,%u\n" \ - "is_right_chan_en: %u\n" \ - "is_left_chan_en: %u\n" \ - "is_right_left_chan_added: %u\n" \ - "is_stereo_en: %u\n" \ - "is_usb_with_hpf_20hz: %u\n" \ - "is_mux_bypassed: %u\n" \ - "is_hpf_en: %u\n" \ - "is_sink_curr_from_ref_volt_cir_en: %u\n" - -static ssize_t debugfs_spkr_get_configuration(struct file *filp, - char __user *ubuf, - size_t cnt, loff_t *ppos) -{ - struct spkr_config_mode type; - int rc = pmic_get_spkr_configuration(&type); - - if (!rc) { - /* Hopefully, 100 additional chars is enough. The number is - * calculated by having 16 elements with up to 5 digits each - * and then doubling it for paranoia's sake. In any case, - * snprintf will truncate, so no danger of oops or panic. - */ - char speaker_configuration_dump_buf[ - sizeof(debugfs_speaker_configuration_format_str) + 200]; - int bytes_copied = snprintf(speaker_configuration_dump_buf, - sizeof(speaker_configuration_dump_buf), - debugfs_speaker_configuration_format_str, - type.is_right_chan_en, - type.is_left_chan_en, - type.is_right_left_chan_added, - type.is_stereo_en, - type.is_usb_with_hpf_20hz, - type.is_mux_bypassed, - type.is_hpf_en, - type.is_sink_curr_from_ref_volt_cir_en, - type.is_right_chan_en, - type.is_left_chan_en, - type.is_right_left_chan_added, - type.is_stereo_en, - type.is_usb_with_hpf_20hz, - type.is_mux_bypassed, - type.is_hpf_en, - type.is_sink_curr_from_ref_volt_cir_en); - - if (bytes_copied > cnt) { - rc = -EINVAL; - goto out_err; - } +int pmic_spkr_is_left_chan_en(uint *enabled) +{ + return pmic_rpc_get_only(enabled, sizeof(*enabled), + SPKR_IS_LEFT_CHAN_EN_PROC); +} +EXPORT_SYMBOL(pmic_spkr_is_left_chan_en); - rc = (int)simple_read_from_buffer(ubuf, cnt, ppos, - speaker_configuration_dump_buf, bytes_copied); - if (rc < 0) - goto out_err; +int pmic_set_speaker_gain(enum spkr_gain gain) +{ + return pmic_rpc_set_only(gain, 0, 0, 0, 1, SET_SPEAKER_GAIN_PROC); +} +EXPORT_SYMBOL(pmic_set_speaker_gain); - printk(KERN_INFO "%s: succeeded, (%d)%d bytes copied\n%s", - __func__, rc, bytes_copied, - speaker_configuration_dump_buf); - } -out_err: - if (rc < 0) - printk(KERN_ERR "%s: ERROR! rc: %d(%#x)\n", __func__, rc, rc); +int pmic_set_speaker_delay(enum spkr_dly delay) +{ + return pmic_rpc_set_only(delay, 0, 0, 0, 1, SET_SPEAKER_DELAY_PROC); +} +EXPORT_SYMBOL(pmic_set_speaker_delay); - return rc; +int pmic_speaker_1k6_zin_enable(uint enable) +{ + return pmic_rpc_set_only(enable, 0, 0, 0, 1, + SPEAKER_1K6_ZIN_ENABLE_PROC); } +EXPORT_SYMBOL(pmic_speaker_1k6_zin_enable); -#define debugfs_spkr_set_configuration_format_str "%u,%u,%u,%u,%u,%u,%u,%u" +int pmic_spkr_set_mux_hpf_corner_freq(enum spkr_hpf_corner_freq freq) +{ + return pmic_rpc_set_only(freq, 0, 0, 0, 1, + SPKR_SET_MUX_HPF_CORNER_FREQ_PROC); +} +EXPORT_SYMBOL(pmic_spkr_set_mux_hpf_corner_freq); -static ssize_t debugfs_spkr_set_configuration(struct file *filp, - const char __user *ubuf, - size_t cnt, loff_t *ppos) +int pmic_spkr_get_mux_hpf_corner_freq(enum spkr_hpf_corner_freq *freq) { - char buf[100]; /* 8 unsigned ints + paranoia */ - struct spkr_config_mode t; - int rc; + return pmic_rpc_get_only(freq, sizeof(*freq), + SPKR_GET_MUX_HPF_CORNER_FREQ_PROC); +} +EXPORT_SYMBOL(pmic_spkr_get_mux_hpf_corner_freq); - if (cnt >= sizeof(buf)) - return -EINVAL; +int pmic_spkr_select_usb_with_hpf_20hz(uint enable) +{ + return pmic_rpc_set_only(enable, 0, 0, 0, 1, + SPKR_SELECT_USB_WITH_HPF_20HZ_PROC); +} +EXPORT_SYMBOL(pmic_spkr_select_usb_with_hpf_20hz); - if (copy_from_user(&buf, ubuf, cnt)) - return -EFAULT; +int pmic_spkr_is_usb_with_hpf_20hz(uint *enabled) +{ + return pmic_rpc_get_only(enabled, sizeof(*enabled), + SPKR_IS_USB_WITH_HPF_20HZ_PROC); +} +EXPORT_SYMBOL(pmic_spkr_is_usb_with_hpf_20hz); - buf[cnt] = 0; +int pmic_spkr_bypass_mux(uint enable) +{ + return pmic_rpc_set_only(enable, 0, 0, 0, 1, SPKR_BYPASS_MUX_PROC); +} +EXPORT_SYMBOL(pmic_spkr_bypass_mux); - rc = sscanf(buf, debugfs_spkr_set_configuration_format_str, - &t.is_right_chan_en, - &t.is_left_chan_en, - &t.is_right_left_chan_added, - &t.is_stereo_en, - &t.is_usb_with_hpf_20hz, - &t.is_mux_bypassed, - &t.is_hpf_en, - &t.is_sink_curr_from_ref_volt_cir_en); +int pmic_spkr_is_mux_bypassed(uint *enabled) +{ + return pmic_rpc_get_only(enabled, sizeof(*enabled), + SPKR_IS_MUX_BYPASSED_PROC); +} +EXPORT_SYMBOL(pmic_spkr_is_mux_bypassed); - if (rc < 8) { - printk(KERN_ERR "%s: snprintf failed arg convert" - " after arg #%d on buf %s\n", - __func__, rc, buf); - return -EINVAL; - } +int pmic_spkr_en_hpf(uint enable) +{ + return pmic_rpc_set_only(enable, 0, 0, 0, 1, SPKR_EN_HPF_PROC); +} +EXPORT_SYMBOL(pmic_spkr_en_hpf); - rc = pmic_set_spkr_configuration(&t); - if (!rc) - printk(KERN_INFO "%s: succeeded, %s\n", __func__, buf); - else - printk(KERN_ERR - "%s: set_spkr_configuration error %d(%#x), buf: %s\n", - __func__, rc, rc, buf); +int pmic_spkr_is_hpf_en(uint *enabled) +{ + return pmic_rpc_get_only(enabled, sizeof(*enabled), + SPKR_IS_HPF_EN_PROC); +} +EXPORT_SYMBOL(pmic_spkr_is_hpf_en); - return rc < 0 ? rc : cnt; +int pmic_spkr_en_sink_curr_from_ref_volt_cir(uint enable) +{ + return pmic_rpc_set_only(enable, 0, 0, 0, 1, + SPKR_EN_SINK_CURR_FROM_REF_VOLT_CIR_PROC); } +EXPORT_SYMBOL(pmic_spkr_en_sink_curr_from_ref_volt_cir); -static const struct file_operations debugfs_spkr_configuration_fops = { - .open = debugfs_spkr_configuration_open, - .read = debugfs_spkr_get_configuration, - .write = debugfs_spkr_set_configuration, -}; +int pmic_spkr_is_sink_curr_from_ref_volt_cir_en(uint *enabled) +{ + return pmic_rpc_get_only(enabled, sizeof(*enabled), + SPKR_IS_SINK_CURR_FROM_REF_VOLT_CIR_EN_PROC); +} +EXPORT_SYMBOL(pmic_spkr_is_sink_curr_from_ref_volt_cir_en); -static int debugfs_mic_en(void *data, u64 val) +/* + * speaker indexed by left_right + */ +int pmic_spkr_en(enum spkr_left_right left_right, uint enable) { - int rc = pmic_mic_en((const unsigned char)val); + return pmic_rpc_set_only(left_right, enable, 0, 0, 2, SPKR_EN_PROC); +} +EXPORT_SYMBOL(pmic_spkr_en); - debugfs_log_return_status(rc, __func__, val); - return rc; +int pmic_spkr_is_en(enum spkr_left_right left_right, uint *enabled) +{ + return pmic_rpc_set_get(left_right, enabled, sizeof(*enabled), + SPKR_IS_EN_PROC); } +EXPORT_SYMBOL(pmic_spkr_is_en); -static int debugfs_mic_is_en(void *data, u64 *val) +int pmic_spkr_set_gain(enum spkr_left_right left_right, enum spkr_gain gain) { - unsigned char enabled; - int rc = pmic_mic_is_en(&enabled); + return pmic_rpc_set_only(left_right, gain, 0, 0, 2, SPKR_SET_GAIN_PROC); +} +EXPORT_SYMBOL(pmic_spkr_set_gain); - if (!rc) - *val = (u64)enabled; +int pmic_spkr_get_gain(enum spkr_left_right left_right, enum spkr_gain *gain) +{ + return pmic_rpc_set_get(left_right, gain, sizeof(*gain), + SPKR_GET_GAIN_PROC); +} +EXPORT_SYMBOL(pmic_spkr_get_gain); - debugfs_log_return_status(rc, __func__, *val); - return rc; +int pmic_spkr_set_delay(enum spkr_left_right left_right, enum spkr_dly delay) +{ + return pmic_rpc_set_only(left_right, delay, 0, 0, 2, + SPKR_SET_DELAY_PROC); } -DEFINE_SIMPLE_ATTRIBUTE(debugfs_mic_en_fops, - debugfs_mic_is_en, - debugfs_mic_en, - "%llu\n"); +EXPORT_SYMBOL(pmic_spkr_set_delay); -static int debugfs_mic_set_volt(void *data, u64 val) +int pmic_spkr_get_delay(enum spkr_left_right left_right, enum spkr_dly *delay) { - int rc = pmic_mic_set_volt((const enum mic_volt)val); + return pmic_rpc_set_get(left_right, delay, sizeof(*delay), + SPKR_GET_DELAY_PROC); +} +EXPORT_SYMBOL(pmic_spkr_get_delay); - debugfs_log_return_status(rc, __func__, val); - return rc; +int pmic_spkr_en_mute(enum spkr_left_right left_right, uint enabled) +{ + return pmic_rpc_set_only(left_right, enabled, 0, 0, 2, + SPKR_EN_MUTE_PROC); } +EXPORT_SYMBOL(pmic_spkr_en_mute); -static int debugfs_mic_get_volt(void *data, u64 *val) +int pmic_spkr_is_mute_en(enum spkr_left_right left_right, uint *enabled) { - enum mic_volt voltage; - int rc = pmic_mic_get_volt(&voltage); + return pmic_rpc_set_get(left_right, enabled, sizeof(*enabled), + SPKR_IS_MUTE_EN_PROC); +} +EXPORT_SYMBOL(pmic_spkr_is_mute_en); - if (!rc) - *val = (u64)voltage; +/* + * mic + */ +int pmic_mic_en(uint enable) +{ + return pmic_rpc_set_only(enable, 0, 0, 0, 1, MIC_EN_PROC); +} +EXPORT_SYMBOL(pmic_mic_en); - debugfs_log_return_status(rc, __func__, *val); - return rc; +int pmic_mic_is_en(uint *enabled) +{ + return pmic_rpc_get_only(enabled, sizeof(*enabled), MIC_IS_EN_PROC); } -DEFINE_SIMPLE_ATTRIBUTE(debugfs_mic_volt_fops, - debugfs_mic_get_volt, - debugfs_mic_set_volt, - "%llu\n"); +EXPORT_SYMBOL(pmic_mic_is_en); -static uint16_t debugfs_flash_led_milliamps; -static int debugfs_flash_led_set_current_execute(void *data, u64 val) +int pmic_mic_set_volt(enum mic_volt vol) { - int rc = pmic_flash_led_set_current((const uint16_t)val); + return pmic_rpc_set_only(vol, 0, 0, 0, 1, MIC_SET_VOLT_PROC); +} +EXPORT_SYMBOL(pmic_mic_set_volt); - if (!rc) - debugfs_flash_led_milliamps = (const uint16_t)val; +int pmic_mic_get_volt(enum mic_volt *voltage) +{ + return pmic_rpc_get_only(voltage, sizeof(*voltage), MIC_GET_VOLT_PROC); +} +EXPORT_SYMBOL(pmic_mic_get_volt); - debugfs_log_return_status(rc, __func__, val); - return rc; +int pmic_vib_mot_set_volt(uint vol) +{ + return pmic_rpc_set_only(vol, 0, 0, 0, 1, VIB_MOT_SET_VOLT_PROC); } +EXPORT_SYMBOL(pmic_vib_mot_set_volt); -static int debugfs_flash_led_set_current_get_cached(void *data, u64 *val) +int pmic_vib_mot_set_mode(enum pm_vib_mot_mode mode) { - *val = (u64)debugfs_flash_led_milliamps; + return pmic_rpc_set_only(mode, 0, 0, 0, 1, VIB_MOT_SET_MODE_PROC); +} +EXPORT_SYMBOL(pmic_vib_mot_set_mode); - debugfs_log_return_status(0, __func__, *val); - return 0; +int pmic_vib_mot_set_polarity(enum pm_vib_mot_pol pol) +{ + return pmic_rpc_set_only(pol, 0, 0, 0, 1, VIB_MOT_SET_POLARITY_PROC); } -DEFINE_SIMPLE_ATTRIBUTE(debugfs_flash_led_current_fops, - debugfs_flash_led_set_current_get_cached, - debugfs_flash_led_set_current_execute, - "%llu\n"); +EXPORT_SYMBOL(pmic_vib_mot_set_polarity); -static uint16_t debugfs_lcd_intensity; -static int debugfs_set_lcd_intensity(void *data, u64 val) +int pmic_vid_en(uint enable) { - int rc = pmic_set_led_intensity(LED_LCD, (const uint16_t)val); + return pmic_rpc_set_only(enable, 0, 0, 0, 1, VID_EN_PROC); +} +EXPORT_SYMBOL(pmic_vid_en); - if (!rc) - debugfs_lcd_intensity = (const uint16_t)val; +int pmic_vid_is_en(uint *enabled) +{ + return pmic_rpc_get_only(enabled, sizeof(*enabled), VID_IS_EN_PROC); +} +EXPORT_SYMBOL(pmic_vid_is_en); - debugfs_log_return_status(rc, __func__, val); - return rc; +int pmic_vid_load_detect_en(uint enable) +{ + return pmic_rpc_set_only(enable, 0, 0, 0, 1, VID_LOAD_DETECT_EN_PROC); } +EXPORT_SYMBOL(pmic_vid_load_detect_en); -static int debugfs_set_lcd_intensity_get_cached(void *data, u64 *val) +int pmic_set_led_intensity(enum ledtype type, int level) { - *val = (u64)debugfs_lcd_intensity; + return pmic_rpc_set_only(type, level, 0, 0, 2, SET_LED_INTENSITY_PROC); +} +EXPORT_SYMBOL(pmic_set_led_intensity); - debugfs_log_return_status(0, __func__, *val); - return 0; +int pmic_flash_led_set_current(const uint16_t milliamps) +{ + return pmic_rpc_set_only(milliamps, 0, 0, 0, 1, + FLASH_LED_SET_CURRENT_PROC); } +EXPORT_SYMBOL(pmic_flash_led_set_current); -DEFINE_SIMPLE_ATTRIBUTE(debugfs_set_lcd_intensity_fops, - debugfs_set_lcd_intensity_get_cached, - debugfs_set_lcd_intensity, - "%llu\n"); +int pmic_flash_led_set_mode(enum flash_led_mode mode) +{ + return pmic_rpc_set_only((int)mode, 0, 0, 0, 1, + FLASH_LED_SET_MODE_PROC); +} +EXPORT_SYMBOL(pmic_flash_led_set_mode); -static int __init debugfs_speaker_init(void) +int pmic_flash_led_set_polarity(enum flash_led_pol pol) { - struct dentry *dent = debugfs_create_dir("pmic", NULL); + return pmic_rpc_set_only((int)pol, 0, 0, 0, 1, + FLASH_LED_SET_POLARITY_PROC); +} +EXPORT_SYMBOL(pmic_flash_led_set_polarity); - if (IS_ERR(dent)) { - printk(KERN_ERR "%s: debugfs_create_dir fail, error %ld\n", - __func__, PTR_ERR(dent)); - return (int)PTR_ERR(dent); - } - debugfs_create_file("spkr_left_en", 0644, dent, (void *)LEFT_SPKR, - &debugfs_spkr_en_chan_fops); - debugfs_create_file("spkr_right_en", 0644, dent, (void *)RIGHT_SPKR, - &debugfs_spkr_en_chan_fops); - debugfs_create_file("spkr_left_gain", 0644, dent, (void *)LEFT_SPKR, - &debugfs_spkr_gain_fops); - debugfs_create_file("spkr_right_gain", 0644, dent, (void *)RIGHT_SPKR, - &debugfs_spkr_gain_fops); - debugfs_create_file("spkr_cmd", 0644, dent, NULL, - &debugfs_speaker_cmd_fops); - debugfs_create_file("spkr_config", 0644, dent, NULL, - &debugfs_spkr_configuration_fops); - debugfs_create_file("mic_en", 0644, dent, NULL, &debugfs_mic_en_fops); - debugfs_create_file("mic_volt", 0644, dent, NULL, - &debugfs_mic_volt_fops); - debugfs_create_file("flash_led_current", 0644, dent, NULL, - &debugfs_flash_led_current_fops); - debugfs_create_file("set_lcd_intensity", 0644, dent, NULL, - &debugfs_set_lcd_intensity_fops); - return 0; +int pmic_spkr_add_right_left_chan(uint enable) +{ + return pmic_rpc_set_only(enable, 0, 0, 0, 1, + SPKR_ADD_RIGHT_LEFT_CHAN_PROC); } +EXPORT_SYMBOL(pmic_spkr_add_right_left_chan); -late_initcall(debugfs_speaker_init); +int pmic_spkr_is_right_left_chan_added(uint *enabled) +{ + return pmic_rpc_get_only(enabled, sizeof(*enabled), + SPKR_IS_RIGHT_LEFT_CHAN_ADDED_PROC); +} +EXPORT_SYMBOL(pmic_spkr_is_right_left_chan_added); -static int __init speaker_init(void) +int pmic_spkr_en_stereo(uint enable) { - /* try to connect initially, ignore any errors for now */ - check_and_connect(); - return 0; + return pmic_rpc_set_only(enable, 0, 0, 0, 1, SPKR_EN_STEREO_PROC); } +EXPORT_SYMBOL(pmic_spkr_en_stereo); -device_initcall(speaker_init); -#endif +int pmic_spkr_is_stereo_en(uint *enabled) +{ + return pmic_rpc_get_only(enabled, sizeof(*enabled), + SPKR_IS_STEREO_EN_PROC); +} +EXPORT_SYMBOL(pmic_spkr_is_stereo_en); diff --git a/arch/arm/mach-msm/pmic_debugfs.c b/arch/arm/mach-msm/pmic_debugfs.c new file mode 100644 index 000000000000..8d872c90cbcd --- /dev/null +++ b/arch/arm/mach-msm/pmic_debugfs.c @@ -0,0 +1,1179 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +#include +#include +#include +#include +#include + +#include + + +static int debug_lp_mode_control(char *buf, int size) +{ + enum switch_cmd cmd; + enum vreg_lp_id id; + int cnt; + + + cnt = sscanf(buf, "%u %u", &cmd, &id); + if (cnt < 2) { + printk(KERN_ERR "%s: sscanf failed cnt=%d", __func__, cnt); + return -EINVAL; + } + + if (pmic_lp_mode_control(cmd, id) < 0) + return -EFAULT; + + return size; +} + +static int debug_vreg_set_level(char *buf, int size) +{ + enum vreg_id vreg; + int level; + int cnt; + + cnt = sscanf(buf, "%u %u", &vreg, &level); + if (cnt < 2) { + printk(KERN_ERR "%s: sscanf failed cnt=%d", __func__, cnt); + return -EINVAL; + } + if (pmic_vreg_set_level(vreg, level) < 0) + return -EFAULT; + + return size; +} + +static int debug_vreg_pull_down_switch(char *buf, int size) +{ + enum switch_cmd cmd; + enum vreg_pdown_id id; + int cnt; + + cnt = sscanf(buf, "%u %u", &cmd, &id); + if (cnt < 2) { + printk(KERN_ERR "%s: sscanf failed cnt=%d", __func__, cnt); + return -EINVAL; + } + if (pmic_vreg_pull_down_switch(cmd, id) < 0) + return -EFAULT; + + return size; +} + +static int debug_secure_mpp_control_digital_output(char *buf, int size) +{ + enum mpp_which which; + enum mpp_dlogic_level level; + enum mpp_dlogic_out_ctrl out; + int cnt; + + cnt = sscanf(buf, "%u %u %u", &which, &level, &out); + if (cnt < 3) { + printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt); + return -EINVAL; + } + + if (pmic_secure_mpp_control_digital_output(which, level, out) < 0) + return -EFAULT; + + return size; +} + +static int debug_secure_mpp_config_i_sink(char *buf, int size) +{ + enum mpp_which which; + enum mpp_i_sink_level level; + enum mpp_i_sink_switch onoff; + int cnt; + + cnt = sscanf(buf, "%u %u %u", &which, &level, &onoff); + if (cnt < 3) { + printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt); + return -EINVAL; + } + + if (pmic_secure_mpp_config_i_sink(which, level, onoff) < 0) + return -EFAULT; + + return size; +} + +static int debug_secure_mpp_config_digital_input(char *buf, int size) +{ + enum mpp_which which; + enum mpp_dlogic_level level; + enum mpp_dlogic_in_dbus dbus; + int cnt; + + cnt = sscanf(buf, "%u %u %u", &which, &level, &dbus); + if (cnt < 3) { + printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt); + return -EINVAL; + } + if (pmic_secure_mpp_config_digital_input(which, level, dbus) < 0) + return -EFAULT; + + return size; +} + +static int debug_rtc_start(char *buf, int size) +{ + uint time; + struct rtc_time *hal; + int cnt; + + cnt = sscanf(buf, "%d", &time); + if (cnt < 1) { + printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt); + return -EINVAL; + } + hal = (struct rtc_time *)&time; + if (pmic_rtc_start(hal) < 0) + return -EFAULT; + + return size; +} + +static int debug_rtc_stop(char *buf, int size) +{ + if (pmic_rtc_stop() < 0) + return -EFAULT; + + return size; +} + +static int debug_rtc_get_time(char *buf, int size) +{ + uint time; + struct rtc_time *hal; + + hal = (struct rtc_time *)&time; + if (pmic_rtc_get_time(hal) < 0) + return -EFAULT; + + return snprintf(buf, size, "%d\n", time); +} + +static int debug_rtc_alarm_ndx; + +int debug_rtc_enable_alarm(char *buf, int size) +{ + enum rtc_alarm alarm; + struct rtc_time *hal; + uint time; + int cnt; + + + cnt = sscanf(buf, "%u %u", &alarm, &time); + if (cnt < 2) { + printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt); + return -EINVAL; + } + hal = (struct rtc_time *)&time; + + if (pmic_rtc_enable_alarm(alarm, hal) < 0) + return -EFAULT; + + debug_rtc_alarm_ndx = alarm; + return size; +} + +static int debug_rtc_disable_alarm(char *buf, int size) +{ + + enum rtc_alarm alarm; + int cnt; + + cnt = sscanf(buf, "%u", &alarm); + if (cnt < 1) { + printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt); + return -EINVAL; + } + if (pmic_rtc_disable_alarm(alarm) < 0) + return -EFAULT; + + return size; +} + +static int debug_rtc_get_alarm_time(char *buf, int size) +{ + uint time; + struct rtc_time *hal; + + hal = (struct rtc_time *)&time; + if (pmic_rtc_get_alarm_time(debug_rtc_alarm_ndx, hal) < 0) + return -EFAULT; + + return snprintf(buf, size, "%d\n", time); +} +static int debug_rtc_get_alarm_status(char *buf, int size) +{ + int status;; + + if (pmic_rtc_get_alarm_status(&status) < 0) + return -EFAULT; + + return snprintf(buf, size, "%d\n", status); + +} + +static int debug_rtc_set_time_adjust(char *buf, int size) +{ + uint adjust; + int cnt; + + cnt = sscanf(buf, "%d", &adjust); + if (cnt < 1) { + printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt); + return -EINVAL; + } + if (pmic_rtc_set_time_adjust(adjust) < 0) + return -EFAULT; + + return size; +} + +static int debug_rtc_get_time_adjust(char *buf, int size) +{ + int adjust;; + + if (pmic_rtc_get_time_adjust(&adjust) < 0) + return -EFAULT; + + return snprintf(buf, size, "%d\n", adjust); +} + +static int debug_set_led_intensity(char *buf, int size) +{ + enum ledtype type; + int level; + int cnt; + + cnt = sscanf(buf, "%u %d", &type, &level); + if (cnt < 2) { + printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt); + return -EINVAL; + } + if (pmic_set_led_intensity(type, level) < 0) + return -EFAULT; + + return size; +} + +static int debug_flash_led_set_current(char *buf, int size) +{ + int milliamps; + int cnt; + + cnt = sscanf(buf, "%d", &milliamps); + if (cnt < 1) { + printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt); + return -EINVAL; + } + if (pmic_flash_led_set_current(milliamps) < 0) + return -EFAULT; + + return size; +} +static int debug_flash_led_set_mode(char *buf, int size) +{ + + uint mode; + int cnt; + + cnt = sscanf(buf, "%d", &mode); + if (cnt < 1) { + printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt); + return -EINVAL; + } + if (pmic_flash_led_set_mode(mode) < 0) + return -EFAULT; + + return size; +} + +static int debug_flash_led_set_polarity(char *buf, int size) +{ + int pol; + int cnt; + + cnt = sscanf(buf, "%d", &pol); + if (cnt < 1) { + printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt); + return -EINVAL; + } + if (pmic_flash_led_set_polarity(pol) < 0) + return -EFAULT; + + return size; +} + +static int debug_speaker_cmd(char *buf, int size) +{ + int cmd; + int cnt; + + cnt = sscanf(buf, "%d", &cmd); + if (cnt < 1) { + printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt); + return -EINVAL; + } + if (pmic_speaker_cmd(cmd) < 0) + return -EFAULT; + + return size; +} +static int debug_set_speaker_gain(char *buf, int size) +{ + int gain; + int cnt; + + cnt = sscanf(buf, "%d", &gain); + if (cnt < 1) { + printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt); + return -EINVAL; + } + if (pmic_set_speaker_gain(gain) < 0) + return -EFAULT; + + return size; +} + +static int debug_mic_en(char *buf, int size) +{ + int enable; + int cnt; + + cnt = sscanf(buf, "%d", &enable); + if (cnt < 1) { + printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt); + return -EINVAL; + } + if (pmic_mic_en(enable) < 0) + return -EFAULT; + + return size; +} + +static int debug_mic_is_en(char *buf, int size) +{ + int enabled; + + if (pmic_mic_is_en(&enabled) < 0) + return -EFAULT; + + return snprintf(buf, size, "%d\n", enabled); +} + +static int debug_mic_set_volt(char *buf, int size) +{ + int vol; + int cnt; + + cnt = sscanf(buf, "%d", &vol); + if (cnt < 1) { + printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt); + return -EINVAL; + } + if (pmic_mic_set_volt(vol) < 0) + return -EFAULT; + + return size; +} + +static int debug_mic_get_volt(char *buf, int size) +{ + uint vol; + + if (pmic_mic_get_volt(&vol) < 0) + return -EFAULT; + + return snprintf(buf, size, "%d\n", vol); +} + +static int debug_spkr_en_right_chan(char *buf, int size) +{ + int enable; + int cnt; + + cnt = sscanf(buf, "%d", &enable); + if (cnt < 1) { + printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt); + return -EINVAL; + } + if (pmic_spkr_en_right_chan(enable) < 0) + return -EFAULT; + + return size; +} + +static int debug_spkr_is_right_chan_en(char *buf, int size) +{ + int enabled; + + if (pmic_spkr_is_right_chan_en(&enabled) < 0) + return -EFAULT; + + return snprintf(buf, size, "%d\n", enabled); +} +static int debug_spkr_en_left_chan(char *buf, int size) +{ + int enable; + int cnt; + + cnt = sscanf(buf, "%d", &enable); + if (cnt < 1) { + printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt); + return -EINVAL; + } + if (pmic_spkr_en_left_chan(enable) < 0) + return -EFAULT; + + return size; +} + +static int debug_spkr_is_left_chan_en(char *buf, int size) +{ + int enabled; + + if (pmic_spkr_is_left_chan_en(&enabled) < 0) + return -EFAULT; + + return snprintf(buf, size, "%d\n", enabled); +} + +static int debug_set_spkr_configuration(char *buf, int size) +{ + + struct spkr_config_mode cfg; + int cnt; + + cnt = sscanf(buf, "%d %d %d %d %d %d %d %d", + &cfg.is_right_chan_en, + &cfg.is_left_chan_en, + &cfg.is_right_left_chan_added, + &cfg.is_stereo_en, + &cfg.is_usb_with_hpf_20hz, + &cfg.is_mux_bypassed, + &cfg.is_hpf_en, + &cfg.is_sink_curr_from_ref_volt_cir_en); + + if (cnt < 8) { + printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt); + return -EINVAL; + } + + if (pmic_set_spkr_configuration(&cfg) < 0) + return -EFAULT; + + return size; +} + +static int debug_get_spkr_configuration(char *buf, int size) +{ + struct spkr_config_mode cfg; + + if (pmic_get_spkr_configuration(&cfg) < 0) + return -EFAULT; + + return snprintf(buf, size, "%d %d %d %d %d %d %d %d\n", + cfg.is_right_chan_en, + cfg.is_left_chan_en, + cfg.is_right_left_chan_added, + cfg.is_stereo_en, + cfg.is_usb_with_hpf_20hz, + cfg.is_mux_bypassed, + cfg.is_hpf_en, + cfg.is_sink_curr_from_ref_volt_cir_en); + +} + +static int debug_set_speaker_delay(char *buf, int size) +{ + int delay; + int cnt; + + cnt = sscanf(buf, "%d", &delay); + if (cnt < 1) { + printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt); + return -EINVAL; + } + if (pmic_set_speaker_delay(delay) < 0) + return -EFAULT; + + return size; +} + +static int debug_speaker_1k6_zin_enable(char *buf, int size) +{ + uint enable; + int cnt; + + cnt = sscanf(buf, "%u", &enable); + if (cnt < 1) { + printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt); + return -EINVAL; + } + if (pmic_speaker_1k6_zin_enable(enable) < 0) + return -EFAULT; + + return size; +} + +static int debug_spkr_set_mux_hpf_corner_freq(char *buf, int size) +{ + int freq; + int cnt; + + cnt = sscanf(buf, "%d", &freq); + if (cnt < 1) { + printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt); + return -EINVAL; + } + if (pmic_spkr_set_mux_hpf_corner_freq(freq) < 0) + return -EFAULT; + + return size; +} + +static int debug_spkr_get_mux_hpf_corner_freq(char *buf, int size) +{ + uint freq; + + if (pmic_spkr_get_mux_hpf_corner_freq(&freq) < 0) + return -EFAULT; + + return snprintf(buf, size, "%d\n", freq); +} + +static int debug_spkr_add_right_left_chan(char *buf, int size) +{ + int enable; + int cnt; + + cnt = sscanf(buf, "%d", &enable); + if (cnt < 1) { + printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt); + return -EINVAL; + } + if (pmic_spkr_add_right_left_chan(enable) < 0) + return -EFAULT; + + return size; +} + +static int debug_spkr_is_right_left_chan_added(char *buf, int size) +{ + int enabled; + + if (pmic_spkr_is_right_left_chan_added(&enabled) < 0) + return -EFAULT; + + return snprintf(buf, size, "%d\n", enabled); +} + +static int debug_spkr_en_stereo(char *buf, int size) +{ + int enable; + int cnt; + + cnt = sscanf(buf, "%d", &enable); + if (cnt < 1) { + printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt); + return -EINVAL; + } + if (pmic_spkr_en_stereo(enable) < 0) + return -EFAULT; + + return size; +} +static int debug_spkr_is_stereo_en(char *buf, int size) +{ + int enabled; + + if (pmic_spkr_is_stereo_en(&enabled) < 0) + return -EFAULT; + + return snprintf(buf, size, "%d\n", enabled); +} + +static int debug_spkr_select_usb_with_hpf_20hz(char *buf, int size) +{ + int enable; + int cnt; + + cnt = sscanf(buf, "%d", &enable); + if (cnt < 1) { + printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt); + return -EINVAL; + } + if (pmic_spkr_select_usb_with_hpf_20hz(enable) < 0) + return -EFAULT; + + return size; +} +static int debug_spkr_is_usb_with_hpf_20hz(char *buf, int size) +{ + int enabled; + + if (pmic_spkr_is_usb_with_hpf_20hz(&enabled) < 0) + return -EFAULT; + + return snprintf(buf, size, "%d\n", enabled); +} + +static int debug_spkr_bypass_mux(char *buf, int size) +{ + int enable; + int cnt; + + cnt = sscanf(buf, "%d", &enable); + if (cnt < 1) { + printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt); + return -EINVAL; + } + if (pmic_spkr_bypass_mux(enable) < 0) + return -EFAULT; + + return size; +} +static int debug_spkr_is_mux_bypassed(char *buf, int size) +{ + int enabled; + + if (pmic_spkr_is_mux_bypassed(&enabled) < 0) + return -EFAULT; + + return snprintf(buf, size, "%d\n", enabled); +} + +static int debug_spkr_en_hpf(char *buf, int size) +{ + int enable; + int cnt; + + cnt = sscanf(buf, "%d", &enable); + if (cnt < 1) { + printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt); + return -EINVAL; + } + if (pmic_spkr_en_hpf(enable) < 0) + return -EFAULT; + + return size; +} +static int debug_spkr_is_hpf_en(char *buf, int size) +{ + int enabled; + + if (pmic_spkr_is_hpf_en(&enabled) < 0) + return -EFAULT; + + return snprintf(buf, size, "%d\n", enabled); +} + +static int debug_spkr_en_sink_curr_from_ref_volt_cir(char *buf, int size) +{ + int enable; + int cnt; + + cnt = sscanf(buf, "%d", &enable); + if (cnt < 1) { + printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt); + return -EINVAL; + } + if (pmic_spkr_en_sink_curr_from_ref_volt_cir(enable) < 0) + return -EFAULT; + + return size; +} + +static int debug_spkr_is_sink_curr_from_ref_volt_cir_en(char *buf, int size) +{ + int enabled; + + if (pmic_spkr_is_sink_curr_from_ref_volt_cir_en(&enabled) < 0) + return -EFAULT; + + return snprintf(buf, size, "%d\n", enabled); +} + +static int debug_vib_mot_set_volt(char *buf, int size) +{ + int vol; + int cnt; + + cnt = sscanf(buf, "%d", &vol); + if (cnt < 1) { + printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt); + return -EINVAL; + } + if (pmic_vib_mot_set_volt(vol) < 0) + return -EFAULT; + + return size; +} +static int debug_vib_mot_set_mode(char *buf, int size) +{ + int mode; + int cnt; + + cnt = sscanf(buf, "%d", &mode); + if (cnt < 1) { + printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt); + return -EINVAL; + } + if (pmic_vib_mot_set_mode(mode) < 0) + return -EFAULT; + + return size; +} + +static int debug_vib_mot_set_polarity(char *buf, int size) +{ + int pol; + int cnt; + + cnt = sscanf(buf, "%d", &pol); + if (cnt < 1) { + printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt); + return -EINVAL; + } + if (pmic_vib_mot_set_polarity(pol) < 0) + return -EFAULT; + + return size; +} +static int debug_vid_en(char *buf, int size) +{ + int enable; + int cnt; + + cnt = sscanf(buf, "%d", &enable); + if (cnt < 1) { + printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt); + return -EINVAL; + } + if (pmic_vid_en(enable) < 0) + return -EFAULT; + + return size; +} +static int debug_vid_is_en(char *buf, int size) +{ + int enabled; + + if (pmic_vid_is_en(&enabled) < 0) + return -EFAULT; + + return snprintf(buf, size, "%d\n", enabled); +} + +static int debug_vid_load_detect_en(char *buf, int size) +{ + int enable; + int cnt; + + cnt = sscanf(buf, "%d", &enable); + if (cnt < 1) { + printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt); + return -EINVAL; + } + if (pmic_vid_load_detect_en(enable) < 0) + return -EFAULT; + + return size; +} + +/************************************************** + * speaker indexed by left_right +**************************************************/ +static enum spkr_left_right debug_spkr_left_right = LEFT_SPKR; + +static int debug_spkr_en(char *buf, int size) +{ + int left_right; + int enable; + int cnt; + + cnt = sscanf(buf, "%d %d", &left_right, &enable); + if (cnt < 2) { + printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt); + return -EINVAL; + } + if (pmic_spkr_en(left_right, enable) >= 0) { + debug_spkr_left_right = left_right; + return size; + } + return -EFAULT; +} + +static int debug_spkr_is_en(char *buf, int size) +{ + int enabled; + + if (pmic_spkr_is_en(debug_spkr_left_right, &enabled) < 0) + return -EFAULT; + + return snprintf(buf, size, "%d\n", enabled); +} + +static int debug_spkr_set_gain(char *buf, int size) +{ + int left_right; + int enable; + int cnt; + + cnt = sscanf(buf, "%d %d", &left_right, &enable); + if (cnt < 2) { + printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt); + return -EINVAL; + } + if (pmic_spkr_set_gain(left_right, enable) >= 0) { + debug_spkr_left_right = left_right; + return size; + } + return -EFAULT; +} + +static int debug_spkr_get_gain(char *buf, int size) +{ + uint gain; + + if (pmic_spkr_get_gain(debug_spkr_left_right, &gain) < 0) + return -EFAULT; + + return snprintf(buf, size, "%d\n", gain); +} +static int debug_spkr_set_delay(char *buf, int size) +{ + int left_right; + int delay; + int cnt; + + cnt = sscanf(buf, "%d %d", &left_right, &delay); + if (cnt < 2) { + printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt); + return -EINVAL; + } + if (pmic_spkr_set_delay(left_right, delay) >= 0) { + debug_spkr_left_right = left_right; + return size; + } + return -EFAULT; +} + +static int debug_spkr_get_delay(char *buf, int size) +{ + uint delay; + + if (pmic_spkr_get_delay(debug_spkr_left_right, &delay) < 0) + return -EFAULT; + + return snprintf(buf, size, "%d\n", delay); +} + +static int debug_spkr_en_mute(char *buf, int size) +{ + int left_right; + int enable; + int cnt; + + cnt = sscanf(buf, "%d %d", &left_right, &enable); + if (cnt < 2) { + printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt); + return -EINVAL; + } + if (pmic_spkr_en_mute(left_right, enable) >= 0) { + debug_spkr_left_right = left_right; + return size; + } + return -EFAULT; +} + +static int debug_spkr_is_mute_en(char *buf, int size) +{ + int enabled; + + if (pmic_spkr_is_mute_en(debug_spkr_left_right, &enabled) < 0) + return -EFAULT; + + return snprintf(buf, size, "%d\n", enabled); +} + +/******************************************************************* + * debug function table +*******************************************************************/ + +struct pmic_debug_desc { + int (*get) (char *, int); + int (*set) (char *, int); +}; + +struct pmic_debug_desc pmic_debug[] = { + {NULL, NULL}, /*LIB_NULL_PROC */ + {NULL, NULL}, /* LIB_RPC_GLUE_CODE_INFO_REMOTE_PROC */ + {NULL, debug_lp_mode_control}, /* LP_MODE_CONTROL_PROC */ + {NULL, debug_vreg_set_level}, /*VREG_SET_LEVEL_PROC */ + {NULL, debug_vreg_pull_down_switch}, /*VREG_PULL_DOWN_SWITCH_PROC */ + {NULL, debug_secure_mpp_control_digital_output}, + /* SECURE_MPP_CONFIG_DIGITAL_OUTPUT_PROC */ + /*SECURE_MPP_CONFIG_I_SINK_PROC */ + {NULL, debug_secure_mpp_config_i_sink}, + {NULL, debug_rtc_start}, /*RTC_START_PROC */ + {NULL, debug_rtc_stop}, /* RTC_STOP_PROC */ + {debug_rtc_get_time, NULL}, /* RTC_GET_TIME_PROC */ + {NULL, debug_rtc_enable_alarm}, /* RTC_ENABLE_ALARM_PROC */ + {NULL , debug_rtc_disable_alarm}, /*RTC_DISABLE_ALARM_PROC */ + {debug_rtc_get_alarm_time, NULL}, /* RTC_GET_ALARM_TIME_PROC */ + {debug_rtc_get_alarm_status, NULL}, /* RTC_GET_ALARM_STATUS_PROC */ + {NULL, debug_rtc_set_time_adjust}, /* RTC_SET_TIME_ADJUST_PROC */ + {debug_rtc_get_time_adjust, NULL}, /* RTC_GET_TIME_ADJUST_PROC */ + {NULL, debug_set_led_intensity}, /* SET_LED_INTENSITY_PROC */ + {NULL, debug_flash_led_set_current}, /* FLASH_LED_SET_CURRENT_PROC */ + {NULL, debug_flash_led_set_mode}, /* FLASH_LED_SET_MODE_PROC */ + {NULL, debug_flash_led_set_polarity}, /* FLASH_LED_SET_POLARITY_PROC */ + {NULL, debug_speaker_cmd}, /* SPEAKER_CMD_PROC */ + {NULL, debug_set_speaker_gain}, /* SET_SPEAKER_GAIN_PROC */ + {NULL, debug_vib_mot_set_volt}, /* VIB_MOT_SET_VOLT_PROC */ + {NULL, debug_vib_mot_set_mode}, /* VIB_MOT_SET_MODE_PROC */ + {NULL, debug_vib_mot_set_polarity}, /* VIB_MOT_SET_POLARITY_PROC */ + {NULL, debug_vid_en}, /* VID_EN_PROC */ + {debug_vid_is_en, NULL}, /* VID_IS_EN_PROC */ + {NULL, debug_vid_load_detect_en}, /* VID_LOAD_DETECT_EN_PROC */ + {NULL, debug_mic_en}, /* MIC_EN_PROC */ + {debug_mic_is_en, NULL}, /* MIC_IS_EN_PROC */ + {NULL, debug_mic_set_volt}, /* MIC_SET_VOLT_PROC */ + {debug_mic_get_volt, NULL}, /* MIC_GET_VOLT_PROC */ + {NULL, debug_spkr_en_right_chan}, /* SPKR_EN_RIGHT_CHAN_PROC */ + {debug_spkr_is_right_chan_en, NULL}, /* SPKR_IS_RIGHT_CHAN_EN_PROC */ + {NULL, debug_spkr_en_left_chan}, /* SPKR_EN_LEFT_CHAN_PROC */ + {debug_spkr_is_left_chan_en, NULL}, /* SPKR_IS_LEFT_CHAN_EN_PROC */ + {NULL, debug_set_spkr_configuration}, /* SET_SPKR_CONFIGURATION_PROC */ + {debug_get_spkr_configuration, NULL}, /* GET_SPKR_CONFIGURATION_PROC */ + {debug_spkr_get_gain, NULL}, /* SPKR_GET_GAIN_PROC */ + {debug_spkr_is_en, NULL}, /* SPKR_IS_EN_PROC */ + {debug_spkr_en_mute, NULL}, /* SPKR_EN_MUTE_PROC */ + {debug_spkr_is_mute_en, NULL}, /* SPKR_IS_MUTE_EN_PROC */ + {NULL, debug_spkr_set_delay}, /* SPKR_SET_DELAY_PROC */ + {debug_spkr_get_delay, NULL}, /* SPKR_GET_DELAY_PROC */ + /* SECURE_MPP_CONFIG_DIGITAL_INPUT_PROC */ + {NULL, debug_secure_mpp_config_digital_input}, + {NULL, debug_set_speaker_delay}, /* SET_SPEAKER_DELAY_PROC */ + {NULL, debug_speaker_1k6_zin_enable}, /* SPEAKER_1K6_ZIN_ENABLE_PROC */ + /* SPKR_SET_MUX_HPF_CORNER_FREQ_PROC */ + {NULL, debug_spkr_set_mux_hpf_corner_freq}, + /* SPKR_GET_MUX_HPF_CORNER_FREQ_PROC */ + {debug_spkr_get_mux_hpf_corner_freq, NULL}, + /* SPKR_IS_RIGHT_LEFT_CHAN_ADDED_PROC */ + {debug_spkr_is_right_left_chan_added, NULL}, + {NULL, debug_spkr_en_stereo}, /* SPKR_EN_STEREO_PROC */ + {debug_spkr_is_stereo_en, NULL}, /* SPKR_IS_STEREO_EN_PROC */ + /* SPKR_SELECT_USB_WITH_HPF_20HZ_PROC */ + {NULL, debug_spkr_select_usb_with_hpf_20hz}, + /* SPKR_IS_USB_WITH_HPF_20HZ_PROC */ + {debug_spkr_is_usb_with_hpf_20hz, NULL}, + {NULL, debug_spkr_bypass_mux}, /* SPKR_BYPASS_MUX_PROC */ + {debug_spkr_is_mux_bypassed, NULL}, /* SPKR_IS_MUX_BYPASSED_PROC */ + {NULL, debug_spkr_en_hpf}, /* SPKR_EN_HPF_PROC */ + { debug_spkr_is_hpf_en, NULL}, /* SPKR_IS_HPF_EN_PROC */ + /* SPKR_EN_SINK_CURR_FROM_REF_VOLT_CIR_PROC */ + {NULL, debug_spkr_en_sink_curr_from_ref_volt_cir}, + /* SPKR_IS_SINK_CURR_FROM_REF_VOLT_CIR_EN_PROC */ + {debug_spkr_is_sink_curr_from_ref_volt_cir_en, NULL}, + /* SPKR_ADD_RIGHT_LEFT_CHAN_PROC */ + {NULL, debug_spkr_add_right_left_chan}, + {NULL, debug_spkr_set_gain}, /* SPKR_SET_GAIN_PROC */ + {NULL , debug_spkr_en}, /* SPKR_EN_PROC */ +}; + +/***********************************************************************/ + +#define PROC_END (sizeof(pmic_debug)/sizeof(struct pmic_debug_desc)) + + +#define PMIC_DEBUG_BUF 512 + +static int debug_proc; /* PROC's index */ + +static char debug_buf[PMIC_DEBUG_BUF]; + +static int proc_index_set(void *data, u64 val) +{ + int ndx; + + ndx = (int)val; + + if (ndx >= 0 && ndx <= PROC_END) + debug_proc = ndx; + + return 0; +} + +static int proc_index_get(void *data, u64 *val) +{ + *val = (u64)debug_proc; + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE( + proc_index_fops, + proc_index_get, + proc_index_set, + "%llu\n"); + + +static int pmic_debugfs_open(struct inode *inode, struct file *file) +{ + return 0; +} + +static int pmic_debugfs_release(struct inode *inode, struct file *file) +{ + return 0; +} + +static ssize_t pmic_debugfs_write( + struct file *file, + const char __user *buff, + size_t count, + loff_t *ppos) +{ + struct pmic_debug_desc *pd; + + if (count > sizeof(debug_buf)) + return -EFAULT; + + if (copy_from_user(debug_buf, buff, count)) + return -EFAULT; + + + debug_buf[count] = 0; /* end of string */ + + pd = &pmic_debug[debug_proc]; + + if (pd->set) + return pd->set(debug_buf, count); + + return 0; +} + +static ssize_t pmic_debugfs_read( + struct file *file, + char __user *buff, + size_t count, + loff_t *ppos) +{ + struct pmic_debug_desc *pd; + int len = 0; + + pd = &pmic_debug[debug_proc]; + + if (pd->get) { + len = pd->get(debug_buf, sizeof(debug_buf)); + if (len > 0) { + if (len > count) + len = count; + if (copy_to_user(buff, debug_buf, len)) + return -EFAULT; + } + } + + return len; +} + + +static const struct file_operations pmic_debugfs_fops = { + .open = pmic_debugfs_open, + .release = pmic_debugfs_release, + .read = pmic_debugfs_read, + .write = pmic_debugfs_write, +}; + +static int __init pmic_debugfs_init(void) +{ + struct dentry *dent = debugfs_create_dir("pmic", NULL); + + if (IS_ERR(dent)) { + printk(KERN_ERR "%s(%d): debugfs_create_dir fail, error %ld\n", + __FILE__, __LINE__, PTR_ERR(dent)); + return -1; + } + + if (debugfs_create_file("index", 0644, dent, 0, &proc_index_fops) + == NULL) { + printk(KERN_ERR "%s(%d): debugfs_create_file: index fail\n", + __FILE__, __LINE__); + return -1; + } + + if (debugfs_create_file("debug", 0644, dent, 0, &pmic_debugfs_fops) + == NULL) { + printk(KERN_ERR "%s(%d): debugfs_create_file: debug fail\n", + __FILE__, __LINE__); + return -1; + } + + debug_proc = 0; + debug_rtc_alarm_ndx = 0; + + return 0; +} + +late_initcall(pmic_debugfs_init); -- cgit v1.2.3 From 9e2dcc0c740a87621ec439d88fda473f5d5f9ad3 Mon Sep 17 00:00:00 2001 From: "Li, Ai" Date: Mon, 4 May 2009 16:51:50 -0600 Subject: [ARM] msm: timer: reduce rounding error in time sync calculation Because the frequency of the debug timer is not a multiple of that of the slow clock, the order of the calculation leads to a large rounding error. It, in turn, causes the system time to jump ahead intermittenly. The order of calculation is changed to minimizes the rounding error. Signed-off-by: Li, Ai --- arch/arm/mach-msm/timer.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c index a5cc69977384..341a4ecb08dc 100644 --- a/arch/arm/mach-msm/timer.c +++ b/arch/arm/mach-msm/timer.c @@ -417,7 +417,6 @@ static void msm_timer_sync_smem_clock_update( { struct msm_clock *clocks[2]; uint32_t timer_counts[2]; - uint32_t new_offset; int i; clocks[0] = data->clock; @@ -435,12 +434,18 @@ static void msm_timer_sync_smem_clock_update( } for (i = 0; i < ARRAY_SIZE(clocks); i++) { + uint32_t new_offset; + uint64_t temp; + if (clocks[i] == NULL) continue; - new_offset = clock_value * - ((clocks[i]->freq << clocks[i]->shift) / SCLK_HZ) - - timer_counts[i]; + /* separate multiplication and division steps to reduce + rounding error */ + temp = clock_value; + temp *= clocks[i]->freq << clocks[i]->shift; + temp /= SCLK_HZ; + new_offset = (uint32_t)(temp) - timer_counts[i]; if (clocks[i]->offset + clocks[i]->smem_offset != new_offset) { if (data->exit_sleep) -- cgit v1.2.3 From 090d9918666b66893b4ed20c4f6b4ea8e064096d Mon Sep 17 00:00:00 2001 From: "Wilson, Matt" Date: Thu, 14 May 2009 08:08:02 -0700 Subject: [ARM] msm: bluetooth: power switch hardware support Add power switch support on newer 8K FFA keypads with BT and WLAN. No change is needed for any 7k FFA or SURF. CRs-Fixed: 174505, 177193 Signed-off-by: Matthew Wilson --- arch/arm/mach-msm/board-qsd8x50.c | 106 ++++++++++++++++++++------------------ 1 file changed, 56 insertions(+), 50 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/board-qsd8x50.c b/arch/arm/mach-msm/board-qsd8x50.c index 6be98f92c19e..7997fdd54eb6 100644 --- a/arch/arm/mach-msm/board-qsd8x50.c +++ b/arch/arm/mach-msm/board-qsd8x50.c @@ -634,67 +634,43 @@ static unsigned bt_config_power_on[] = { GPIO_CFG(18, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* SYSRST */ GPIO_CFG(19, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* WAKE */ GPIO_CFG(21, 0, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), /* HOST_WAKE */ - GPIO_CFG(22, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* PWR_EN */ + GPIO_CFG(22, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* VDD_IO */ GPIO_CFG(43, 2, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* RFR */ GPIO_CFG(44, 2, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), /* CTS */ GPIO_CFG(45, 2, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), /* Rx */ GPIO_CFG(46, 2, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* Tx */ -}; -static unsigned bt_config_power_off[] = { - GPIO_CFG(18, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* SYSRST */ - GPIO_CFG(19, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* WAKE */ - GPIO_CFG(21, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* HOST_WAKE */ - GPIO_CFG(22, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* PWR_EN */ - GPIO_CFG(43, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* RFR */ - GPIO_CFG(44, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* CTS */ - GPIO_CFG(45, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* Rx */ - GPIO_CFG(46, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* Tx */ + GPIO_CFG(113, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* VDD_FREG */ }; static int bluetooth_power(int on) { - int pin, rc; - - printk(KERN_DEBUG "%s\n", __func__); - - if (on) { - for (pin = 0; pin < ARRAY_SIZE(bt_config_power_on); pin++) { - rc = gpio_tlmm_config(bt_config_power_on[pin], - GPIO_ENABLE); - if (rc) { - printk(KERN_ERR - "%s: gpio_tlmm_config(%#x)=%d\n", - __func__, bt_config_power_on[pin], rc); - return -EIO; - } - } - - gpio_set_value(22, on); /* PWR_EN */ - gpio_set_value(18, on); /* SYSRST */ - - } else { - gpio_set_value(18, on); /* SYSRST */ - gpio_set_value(22, on); /* PWR_EN */ - - for (pin = 0; pin < ARRAY_SIZE(bt_config_power_off); pin++) { - rc = gpio_tlmm_config(bt_config_power_off[pin], - GPIO_ENABLE); - if (rc) { - printk(KERN_ERR - "%s: gpio_tlmm_config(%#x)=%d\n", - __func__, bt_config_power_off[pin], rc); - return -EIO; - } - } + printk(KERN_DEBUG "Bluetooth power switch: %d\n", on); - } + gpio_set_value(18, on); /* SYSRST* */ return 0; } static void __init bt_power_init(void) { + int pin, rc; + + for (pin = 0; pin < ARRAY_SIZE(bt_config_power_on); pin++) { + rc = gpio_tlmm_config(bt_config_power_on[pin], + GPIO_ENABLE); + if (rc) { + printk(KERN_ERR + "%s: gpio_tlmm_config(%#x)=%d\n", + __func__, bt_config_power_on[pin], rc); + return; + } + } + + gpio_set_value(18, 0); /* SYSRST* */ + gpio_set_value(22, 1); /* VDD_IO */ + gpio_set_value(113, 1); /* VDD_FREG */ msm_bt_power_device.dev.platform_data = &bluetooth_power; + printk(KERN_DEBUG "Bluetooth power switch initialized\n"); } #else #define bt_power_init(x) do {} while (0) @@ -1240,7 +1216,7 @@ static uint32_t msm_sdcc_setup_power(struct device *dv, unsigned int vdd) clear_bit(pdev->id, &vreg_sts); - if (!vreg_sts) { + if (!vreg_sts && !machine_is_qsd8x50_ffa()) { rc = vreg_disable(vreg_mmc); if (rc) printk(KERN_ERR "%s: return val: %d \n", @@ -1249,7 +1225,7 @@ static uint32_t msm_sdcc_setup_power(struct device *dv, unsigned int vdd) return 0; } - if (!vreg_sts) { + if (!vreg_sts && !machine_is_qsd8x50_ffa()) { rc = vreg_set_level(vreg_mmc, 2850); if (!rc) rc = vreg_enable(vreg_mmc); @@ -1268,9 +1244,7 @@ static struct mmc_platform_data qsd8x50_sdcc_data = { static void __init qsd8x50_init_mmc(void) { - if (machine_is_qsd8x50_ffa()) - vreg_mmc = vreg_get(NULL, "gp6"); - else + if (!machine_is_qsd8x50_ffa()) vreg_mmc = vreg_get(NULL, "gp5"); if (IS_ERR(vreg_mmc)) { @@ -1360,6 +1334,37 @@ static struct msm_pm_platform_data msm_pm_data[MSM_PM_SLEEP_MODE_NR] = { [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].residency = 0, }; +static void __init gp6_init(void) +{ + struct vreg *vreg; + int rc; + + vreg = vreg_get(NULL, "gp6"); + if (IS_ERR(vreg)) { + printk(KERN_ERR "%s: vreg get failed (%ld)\n", + __func__, PTR_ERR(vreg)); + return; + } + + /* units of mV, steps of 50 mV */ + rc = vreg_set_level(vreg, 2850); + if (rc) { + printk(KERN_ERR "%s: vreg set level failed (%d)\n", + __func__, rc); + return; + } + + rc = vreg_enable(vreg); + if (rc) { + printk(KERN_ERR "%s: vreg enable failed (%d)\n", + __func__, rc); + return; + } + + if (machine_is_qsd8x50_ffa()) + vreg_mmc = vreg; +} + static void __init qsd8x50_init(void) { if (socinfo_init() < 0) @@ -1372,6 +1377,7 @@ static void __init qsd8x50_init(void) platform_add_devices(devices, ARRAY_SIZE(devices)); msm_fb_add_devices(); msm_camera_add_device(); + gp6_init(); qsd8x50_init_mmc(); bt_power_init(); audio_gpio_init(); -- cgit v1.2.3 From d578a8f599a6cf4941c9ee12e2a6df1c0e6ea9c0 Mon Sep 17 00:00:00 2001 From: Neil Leeder Date: Tue, 19 May 2009 17:40:48 -0400 Subject: [ARM] msm: add support for Comet board pass 2 Comet2 has a different peripheral mix and changed resources which are initialized in the board file. Signed-off-by: Neil Leeder --- arch/arm/mach-msm/board-comet.c | 111 ++++++++++++++++++++++++++++++++++------ 1 file changed, 95 insertions(+), 16 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/board-comet.c b/arch/arm/mach-msm/board-comet.c index 663ed1aba951..ffbd2657b27f 100644 --- a/arch/arm/mach-msm/board-comet.c +++ b/arch/arm/mach-msm/board-comet.c @@ -98,16 +98,60 @@ #define MSM_PMEM_GPU0_SIZE (MSM_SMI_SIZE - MSM_FB_SIZE) #define COMET_CPLD_START 0x70004000 -#define COMET_CPLD_SIZE 0x00000020 #define COMET_CPLD_PER_ENABLE 0x00000010 #define COMET_CPLD_PER_RESET 0x00000018 -#define COMET_CPLD_PER_RESET_BT_RESET 0x00000001 -#define COMET_CPLD_PER_RESET_ALL_RESET 0x000000FF +#define COMET_CPLD_STATUS 0x00000028 +#define COMET_CPLD_EXT_PER_ENABLE 0x00000030 +#define COMET_CPLD_I2C_ENABLE 0x00000038 +#define COMET_CPLD_EXT_PER_RESET 0x00000048 +#define COMET_CPLD_VERSION 0x00000058 + +#define COMET_CPLD_SIZE 0x00000060 +#define COMET_CPLD_STATUS_WVGA 0x0004 +#define COMET_CPLD_VERSION_MAJOR 0xFF00 +#define COMET_CPLD_PER_ENABLE_WVGA 0x0400 +#define COMET_CPLD_PER_ENABLE_LVDS 0x0200 +#define COMET_CPLD_PER_ENABLE_WXGA 0x0040 +#define COMET_CPLD_EXT_PER_ENABLE_WXGA 0x0080 + +static int cpld_version; +static bool wvga_present; +static bool wxga_present; +static struct comet_cpld_t { + u16 per_reset_all_reset; + u16 ext_per_reset_all_reset; + u16 i2c_enable; + u16 per_enable_all; + u16 ext_per_enable_all; + u16 bt_reset_reg; + u16 bt_reset_mask; +} comet_cpld[] = { + [0] = { + .per_reset_all_reset = 0x00FF, + /* enable all peripherals except microphones and */ + /* reset line for i2c touchpad */ + .per_enable_all = 0xFFD8, + .bt_reset_reg = 0x0018, + .bt_reset_mask = 0x0001, + }, + [1] = { + .per_reset_all_reset = 0x00BF, + .ext_per_reset_all_reset = 0x0007, + .i2c_enable = 0x07FF, + /* enable all peripherals except microphones and */ + /* displays */ + .per_enable_all = 0xF9B0, + .ext_per_enable_all = 0x007F, + .bt_reset_reg = 0x0048, + .bt_reset_mask = 0x0004, + }, +}; +static struct comet_cpld_t *cpld_info; static struct resource smc911x_resources[] = { [0] = { - .start = 0x90000000, - .end = 0x90000100, + .start = 0x84000000, + .end = 0x84000100, .flags = IORESOURCE_MEM, }, [1] = { @@ -318,7 +362,8 @@ static int msm_fb_detect_panel(const char *name) { int ret; - if (!strcmp(name, "mddi_toshiba_wvga")) + if ((!strcmp(name, "mddi_toshiba_wvga") && wvga_present) || + (!strcmp(name, "lcdc_wxga") && wxga_present)) ret = 0; else ret = -ENODEV; @@ -526,12 +571,12 @@ static int bluetooth_power(int on) } gpio_set_value(22, on); /* PWR_EN */ - writeb(COMET_CPLD_PER_RESET_BT_RESET, - cpld_base + COMET_CPLD_PER_RESET); /* SYSRST */ + writeb(cpld_info->bt_reset_mask, + cpld_base + cpld_info->bt_reset_reg); /* SYSRST */ } else { - writeb(COMET_CPLD_PER_RESET_BT_RESET, - cpld_base + COMET_CPLD_PER_RESET); /* SYSRST */ + writeb(cpld_info->bt_reset_mask, + cpld_base + cpld_info->bt_reset_reg); /* SYSRST */ gpio_set_value(22, on); /* PWR_EN */ for (pin = 0; pin < ARRAY_SIZE(bt_config_power_off); pin++) { @@ -948,16 +993,50 @@ static struct msm_pm_platform_data msm_pm_data[MSM_PM_SLEEP_MODE_NR] = { static void __init comet_init(void) { char __iomem *cpld_base; + int per_enable; + int ext_per_enable; cpld_base = comet_cpld_base(); - if (cpld_base) { - /* enable all peripherals except microphones and */ - /* reset line for i2c touchpad */ - writew(0xFFD8, cpld_base + COMET_CPLD_PER_ENABLE); - writew(COMET_CPLD_PER_RESET_ALL_RESET, - cpld_base + COMET_CPLD_PER_RESET); + + if (!cpld_base) + return; + + cpld_version = (readw(cpld_base + COMET_CPLD_VERSION) & + COMET_CPLD_VERSION_MAJOR) >> 8; + if (cpld_version >= 2) { + cpld_info = &comet_cpld[1]; + per_enable = cpld_info->per_enable_all; + wvga_present = (readw(cpld_base + COMET_CPLD_STATUS) + & COMET_CPLD_STATUS_WVGA) != 0; + wxga_present = !wvga_present; + ext_per_enable = cpld_info->ext_per_enable_all; + if (wvga_present) + per_enable |= COMET_CPLD_PER_ENABLE_WVGA; + else { + per_enable |= COMET_CPLD_PER_ENABLE_LVDS | + COMET_CPLD_PER_ENABLE_WXGA; + ext_per_enable |= COMET_CPLD_EXT_PER_ENABLE_WXGA; + } + writew(ext_per_enable, + cpld_base + COMET_CPLD_EXT_PER_ENABLE); + writew(cpld_info->i2c_enable, + cpld_base + COMET_CPLD_I2C_ENABLE); + writew(cpld_info->ext_per_reset_all_reset, + cpld_base + COMET_CPLD_EXT_PER_RESET); + } else { + cpld_info = &comet_cpld[0]; + wvga_present = 1; + wxga_present = 1; + per_enable = cpld_info->per_enable_all; + smc911x_resources[0].start = 0x90000000; + smc911x_resources[0].end = 0x90000100; } + writew(per_enable, + cpld_base + COMET_CPLD_PER_ENABLE); + writew(cpld_info->per_reset_all_reset, + cpld_base + COMET_CPLD_PER_RESET); + msm_acpu_clock_init(&comet_clock_data); msm_device_hsusb_peripheral.dev.platform_data = &msm_hsusb_pdata; -- cgit v1.2.3 From 675dae6becb3f793e5ec681bc44baf6751b1eb19 Mon Sep 17 00:00:00 2001 From: "Vishwanathapura, Niranjana" Date: Wed, 20 May 2009 15:11:40 -0600 Subject: [ARM] msm: Add smd rpc ping module Add smd rpc ping module. Currently, the ping module implements the ping modem client rpc apis and also provides open/close/ioctl test access to the userspace. This is useful as a test rpc client in the kernel. Signed-off-by: Niranjana Vishwanathapura --- arch/arm/mach-msm/Kconfig | 7 + arch/arm/mach-msm/Makefile | 1 + arch/arm/mach-msm/smd_rpc_ping.c | 628 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 636 insertions(+) create mode 100644 arch/arm/mach-msm/smd_rpc_ping.c (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index 024713ffa411..d9a534a5a532 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -398,6 +398,13 @@ config MSM_RPCSERVERS help none +config MSM_RPC_PING + depends on MSM_ONCRPCROUTER + default m + bool "MSM rpc ping" + help + Implements MSM rpc ping module. + config MSM_RPCSERVER_HANDSET depends on MSM_ONCRPCROUTER default y diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index bd683a62883d..a0eb02d95919 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter.o obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_device.o obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_servers.o obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_clients.o +obj-$(CONFIG_MSM_RPC_PING) += smd_rpc_ping.o obj-$(CONFIG_MSM_RPCSERVERS) += rpc_server_dog_keepalive.o obj-$(CONFIG_MSM_RPCSERVERS) += rpc_server_time_remote.o obj-$(CONFIG_MSM_DALRPC) += dal.o diff --git a/arch/arm/mach-msm/smd_rpc_ping.c b/arch/arm/mach-msm/smd_rpc_ping.c new file mode 100644 index 000000000000..fc23a8e6dd1c --- /dev/null +++ b/arch/arm/mach-msm/smd_rpc_ping.c @@ -0,0 +1,628 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* + * SMD RPC PING MODEM Driver + */ + +#include +#include +#include +#include +#include +#include + +#define PING_TEST_BASE 0x31 + +#define PTIOC_NULL_TEST _IO(PING_TEST_BASE, 1) +#define PTIOC_REG_TEST _IO(PING_TEST_BASE, 2) +#define PTIOC_DATA_REG_TEST _IO(PING_TEST_BASE, 3) +#define PTIOC_DATA_CB_REG_TEST _IO(PING_TEST_BASE, 4) +#define PTIOC_USE_MULTI_CLIENTS _IO(PING_TEST_BASE, 5) +#define PTIOC_USE_DEFAULT_CLIENT _IO(PING_TEST_BASE, 6) + +#define PING_MDM_PROG 0x30000081 +#define PING_MDM_VERS 0x00010001 +#define PING_MDM_CB_PROG 0x31000081 +#define PING_MDM_CB_VERS 0x00010001 + +#define PING_MDM_NULL_PROC 0 +#define PING_MDM_RPC_GLUE_CODE_INFO_REMOTE_PROC 1 +#define PING_MDM_REGISTER_PROC 2 +#define PING_MDM_UNREGISTER_PROC 3 +#define PING_MDM_REGISTER_DATA_PROC 4 +#define PING_MDM_UNREGISTER_DATA_CB_PROC 5 +#define PING_MDM_REGISTER_DATA_CB_PROC 6 + +#define PING_MDM_DATA_CB_PROC 1 +#define PING_MDM_CB_PROC 2 + +static struct msm_rpc_client *rpc_client; +static uint32_t open_count; +static uint32_t ping_test_use_multi_clients; +static DEFINE_MUTEX(ping_mdm_lock); +static DEFINE_MUTEX(ping_mdm_cb_lock); +static LIST_HEAD(ping_mdm_cb_list); +static atomic_t next_cb_id = ATOMIC_INIT(1); + +struct ping_mdm_cb_item { + struct list_head list; + + uint32_t cb_id; + + wait_queue_head_t wait; + int done_flag; + + int num; + int num_req; +}; + +struct ping_mdm_cb_item *ping_mdm_get_cb_item(uint32_t cb_id) +{ + struct ping_mdm_cb_item *cb_item; + + mutex_lock(&ping_mdm_cb_lock); + list_for_each_entry(cb_item, &ping_mdm_cb_list, list) { + if (cb_item->cb_id == cb_id) { + mutex_unlock(&ping_mdm_cb_lock); + return cb_item; + } + } + mutex_unlock(&ping_mdm_cb_lock); + return NULL; +} + +static void ping_mdm_register_cb(struct msm_rpc_client *client, + void *buffer, int in_size) +{ + struct rpc_request_hdr *req; + int rc, num; + void *buf; + uint32_t cb_id; + struct ping_mdm_cb_item *cb_item; + + req = (struct rpc_request_hdr *)buffer; + buf = (void *)(req + 1); + + cb_id = be32_to_cpu(*(uint32_t *)buf); + buf += sizeof(uint32_t); + num = be32_to_cpu(*(int32_t *)buf); + buf += sizeof(int32_t); + pr_info("%s: received cb_id %d, val = %d\n", __func__, cb_id, num); + + rc = msm_rpc_send_accepted_reply(client, be32_to_cpu(req->xid), + RPC_ACCEPTSTAT_SUCCESS, NULL, 0); + if (rc) { + pr_err("%s: sending reply failed: %d\n", __func__, rc); + return; + } + + cb_item = ping_mdm_get_cb_item(cb_id); + if (!cb_item) { + pr_err("%s: no cb item found\n", __func__); + return; + } + cb_item->num++; + + if (cb_item->num == cb_item->num_req) { + cb_item->done_flag = 1; + wake_up(&cb_item->wait); + } +} + +static void ping_mdm_data_cb(struct msm_rpc_client *client, + void *buffer, int in_size) +{ + struct rpc_request_hdr *req; + int rc, i; + void *buf; + uint32_t cb_id = 0; + uint32_t size, *data, req_size, sum, my_sum, my_data; + struct ping_mdm_cb_item *cb_item; + + req = (struct rpc_request_hdr *)buffer; + buf = (void *)(req + 1); + + my_sum = 0; + cb_id = be32_to_cpu(*(uint32_t *)buf); + buf += sizeof(uint32_t); + size = be32_to_cpu(*(uint32_t *)buf); + buf += sizeof(uint32_t); + data = (uint32_t *)buf; + buf += sizeof(uint32_t) * size; + for (i = 0; i < size; i++) + my_sum = be32_to_cpu(*(data + i)) ^ my_sum; + + req_size = be32_to_cpu(*(uint32_t *)buf); + buf += sizeof(uint32_t); + sum = be32_to_cpu(*(uint32_t *)buf); + pr_info("%s: received cb_id %d, xid = %d, size = %d," + "req_size = %d, sum = %u, my_sum = %u\n", __func__, + cb_id, be32_to_cpu(req->xid), size, req_size, sum, my_sum); + + if (sum != my_sum) + pr_err("%s: sum mismatch\n", __func__); + + my_data = cpu_to_be32(1); + rc = msm_rpc_send_accepted_reply(client, be32_to_cpu(req->xid), + RPC_ACCEPTSTAT_SUCCESS, + (char *)&my_data, sizeof(my_data)); + if (rc) + pr_err("%s: sending reply failed: %d\n", __func__, rc); + + cb_item = ping_mdm_get_cb_item(cb_id); + if (!cb_item) { + pr_err("%s: no cb item found\n", __func__); + return; + } + cb_item->num++; + + if (cb_item->num == cb_item->num_req) { + cb_item->done_flag = 1; + wake_up(&cb_item->wait); + } +} + +static int ping_mdm_cb_func(struct msm_rpc_client *client, + void *buffer, int in_size) +{ + struct rpc_request_hdr *req; + + req = (struct rpc_request_hdr *)buffer; + + switch (be32_to_cpu(req->procedure)) { + case PING_MDM_CB_PROC: + ping_mdm_register_cb(client, buffer, in_size); + break; + case PING_MDM_DATA_CB_PROC: + ping_mdm_data_cb(client, buffer, in_size); + break; + default: + pr_err("%s: procedure not supported %d\n", __func__, + be32_to_cpu(req->procedure)); + break; + } + return 0; +} + +static struct msm_rpc_client *ping_mdm_get_client(char *name) +{ + struct msm_rpc_client *client; + + if (ping_test_use_multi_clients) { + client = msm_rpc_register_client(name, + PING_MDM_PROG, + PING_MDM_VERS, 0, + ping_mdm_cb_func); + if (IS_ERR(client)) + pr_err("%s: could not open rpc client:%ld\n", + __func__, PTR_ERR(client)); + } else + client = rpc_client; + + return client; +} + +static struct ping_mdm_cb_item *ping_mdm_create_cb_item(uint32_t cb_id, + int num_req) +{ + struct ping_mdm_cb_item *cb_item; + + cb_item = kmalloc(sizeof(struct ping_mdm_cb_item), GFP_KERNEL); + if (!cb_item) + return ERR_PTR(-ENOMEM); + + INIT_LIST_HEAD(&cb_item->list); + cb_item->num_req = num_req; + cb_item->num = 0; + init_waitqueue_head(&cb_item->wait); + cb_item->done_flag = 0; + cb_item->cb_id = cb_id; + + mutex_lock(&ping_mdm_cb_lock); + list_add_tail(&cb_item->list, &ping_mdm_cb_list); + mutex_unlock(&ping_mdm_cb_lock); + + return cb_item; +} + +static void ping_mdm_destroy_cb_item(struct ping_mdm_cb_item *cb_item) +{ + mutex_lock(&ping_mdm_cb_lock); + list_del(&cb_item->list); + mutex_unlock(&ping_mdm_cb_lock); + + kfree(cb_item); +} + +static int ping_mdm_data_cb_register_arg(void *buf, void *data) +{ + int size = 0; + + *((uint32_t *)buf) = cpu_to_be32((uint32_t)data); + size += sizeof(uint32_t); + buf += sizeof(uint32_t); + + *((uint32_t *)buf) = cpu_to_be32(10); + size += sizeof(uint32_t); + buf += sizeof(uint32_t); + + *((uint32_t *)buf) = cpu_to_be32(64); + size += sizeof(uint32_t); + buf += sizeof(uint32_t); + + *((uint32_t *)buf) = cpu_to_be32(10); + size += sizeof(uint32_t); + buf += sizeof(uint32_t); + + *((uint32_t *)buf) = cpu_to_be32(1); + size += sizeof(uint32_t); + buf += sizeof(uint32_t); + + return size; +} + +static int ping_mdm_data_cb_register_arg_unreg(void *buf, void *data) +{ + *((uint32_t *)buf) = cpu_to_be32((uint32_t)data); + return sizeof(uint32_t); +} + +static int ping_mdm_data_cb_register_result(void *buf, void *data) +{ + uint32_t result; + + result = *((uint32_t *)buf); + pr_info("%s: request completed: 0x%x\n", __func__, result); + + return 0; +} + +static int ping_mdm_data_cb_register_test(void) +{ + int rc; + struct ping_mdm_cb_item *cb_item; + struct msm_rpc_client *client; + + client = ping_mdm_get_client("pingdatacb"); + if (IS_ERR(client)) + return PTR_ERR(client); + + cb_item = ping_mdm_create_cb_item(atomic_add_return(1, &next_cb_id), + 10); + if (IS_ERR(cb_item)) { + rc = PTR_ERR(cb_item); + goto release_client; + } + + rc = msm_rpc_client_req(client, + PING_MDM_REGISTER_DATA_CB_PROC, + ping_mdm_data_cb_register_arg, + ping_mdm_data_cb_register_result, + (void *)(cb_item->cb_id)); + if (rc) + goto free_and_release_client; + + wait_event(cb_item->wait, cb_item->done_flag); + + rc = msm_rpc_client_req(client, + PING_MDM_UNREGISTER_DATA_CB_PROC, + ping_mdm_data_cb_register_arg_unreg, + ping_mdm_data_cb_register_result, + (void *)(cb_item->cb_id)); + + + free_and_release_client: + ping_mdm_destroy_cb_item(cb_item); + release_client: + if (client != rpc_client) + msm_rpc_unregister_client(client); + + return rc; +} + +static int ping_mdm_data_register_arg(void *buf, void *data) +{ + int i, size = 0; + + *((uint32_t *)buf) = cpu_to_be32(64); + size += sizeof(uint32_t); + buf += size; + for (i = 0; i < 64; i++) { + *((uint32_t *)buf) = cpu_to_be32(42 + i); + size += sizeof(uint32_t); + buf += sizeof(uint32_t); + *(uint32_t *)data = (*(uint32_t *)data) ^ (42 | i); + } + *((uint32_t *)buf) = cpu_to_be32(64); + size += sizeof(uint32_t); + + return size; +} + +static int ping_mdm_data_register_result(void *buf, void *data) +{ + uint32_t result; + + result = *((uint32_t *)buf); + pr_info("%s: request completed: 0x%x\n", __func__, result); + + if (result != *(uint32_t *)data) + pr_err("%s: sum mismatch\n", __func__); + + return 0; +} + +static int ping_mdm_data_register_test(void) +{ + int rc = 0; + struct msm_rpc_client *client; + uint32_t my_sum = 0; + + client = ping_mdm_get_client("pingdata"); + if (IS_ERR(client)) + return PTR_ERR(client); + + + rc = msm_rpc_client_req(client, + PING_MDM_REGISTER_DATA_PROC, + ping_mdm_data_register_arg, + ping_mdm_data_register_result, &my_sum); + + if (client != rpc_client) + msm_rpc_unregister_client(client); + + return rc; +} + +static int ping_mdm_register_arg(void *buf, void *data) +{ + int num, size = 0; + + /* revist to pass in num also through data */ + num = 10; + *((uint32_t *)buf) = cpu_to_be32((uint32_t)data); + size += sizeof(uint32_t); + buf += size; + + *((int *)buf) = cpu_to_be32(num); + size += sizeof(int); + + return size; +} + +static int ping_mdm_register_arg_unreg(void *buf, void *data) +{ + *((uint32_t *)buf) = cpu_to_be32((uint32_t)data); + return sizeof(uint32_t); +} + +static int ping_mdm_register_result(void *buf, void *data) +{ + uint32_t result; + + result = *((uint32_t *)buf); + pr_info("%s: request completed: 0x%x\n", __func__, result); + + return 0; +} + +static int ping_mdm_register_test(void) +{ + int rc; + struct ping_mdm_cb_item *cb_item; + struct msm_rpc_client *client; + + client = ping_mdm_get_client("pingreg"); + if (IS_ERR(client)) + return PTR_ERR(client); + + cb_item = ping_mdm_create_cb_item(atomic_add_return(1, &next_cb_id), + 10); + if (IS_ERR(cb_item)) { + rc = PTR_ERR(cb_item); + goto release_client; + } + + rc = msm_rpc_client_req(client, + PING_MDM_REGISTER_PROC, + ping_mdm_register_arg, + ping_mdm_register_result, + (void *)(cb_item->cb_id)); + if (rc) + goto free_and_release_client; + + wait_event(cb_item->wait, cb_item->done_flag); + + rc = msm_rpc_client_req(client, + PING_MDM_UNREGISTER_PROC, + ping_mdm_register_arg_unreg, + ping_mdm_register_result, + (void *)(cb_item->cb_id)); + + free_and_release_client: + ping_mdm_destroy_cb_item(cb_item); + release_client: + if (client != rpc_client) + msm_rpc_unregister_client(client); + + return rc; +} + +static int ping_mdm_null_test(void) +{ + int rc; + struct msm_rpc_client *client; + + client = ping_mdm_get_client("pingnull"); + if (IS_ERR(client)) + return PTR_ERR(client); + + rc = msm_rpc_client_req(client, PING_MDM_NULL_PROC, NULL, NULL, NULL); + + if (client != rpc_client) + msm_rpc_unregister_client(client); + + return rc; +} + +static int ping_test_release(struct inode *ip, struct file *fp) +{ + mutex_lock(&ping_mdm_lock); + if (--open_count == 0) { + msm_rpc_unregister_client(rpc_client); + pr_info("%s: disconnected from remote ping server\n", + __func__); + } + mutex_unlock(&ping_mdm_lock); + return 0; +} + +static int ping_test_open(struct inode *ip, struct file *fp) +{ + mutex_lock(&ping_mdm_lock); + if (open_count++ == 0) { + rpc_client = msm_rpc_register_client("pingdef", + PING_MDM_PROG, + PING_MDM_VERS, 1, + ping_mdm_cb_func); + if (IS_ERR(rpc_client)) { + pr_err("%s: couldn't open rpc client\n", __func__); + return PTR_ERR(rpc_client); + } + pr_info("%s: connected to remote ping server\n", __func__); + } + mutex_unlock(&ping_mdm_lock); + return 0; +} + +static int ping_test_ioctl(struct inode *ip, struct file *fp, + unsigned int cmd, unsigned long arg) +{ + int rc; + + switch (cmd) { + default: + return -ENOTTY; + + case PTIOC_NULL_TEST: + rc = ping_mdm_null_test(); + break; + case PTIOC_REG_TEST: + rc = ping_mdm_register_test(); + break; + case PTIOC_DATA_REG_TEST: + rc = ping_mdm_data_register_test(); + break; + case PTIOC_DATA_CB_REG_TEST: + rc = ping_mdm_data_cb_register_test(); + break; + case PTIOC_USE_MULTI_CLIENTS: + ping_test_use_multi_clients = 1; + pr_info("%s: tests to use multiple clients\n", __func__); + return 0; + case PTIOC_USE_DEFAULT_CLIENT: + ping_test_use_multi_clients = 0; + pr_info("%s: tests to use default client\n", __func__); + return 0; + } + + if (rc) + pr_info("%s: ping mdm test FAILed: %d\n", __func__, rc); + else + pr_info("%s: ping mdm test PASSed\n", __func__); + + return 0; +} + +static const struct file_operations ping_test_fops = { + .owner = THIS_MODULE, + .open = ping_test_open, + .release = ping_test_release, + .ioctl = ping_test_ioctl, +}; + +static struct miscdevice ping_test_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "ping_test", + .fops = &ping_test_fops, +}; + +static void __exit ping_test_exit(void) +{ + misc_deregister(&ping_test_device); +} + +static int __init ping_test_init(void) +{ + int rc = 0; + + open_count = 0; + ping_test_use_multi_clients = 0; + rc = misc_register(&ping_test_device); + if (rc) + pr_err("%s: ping_test_device reg fail\n", __func__); + + return rc; +} + + +module_init(ping_test_init); +module_exit(ping_test_exit); + +MODULE_DESCRIPTION("PING TEST Driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From b919cd060b7558a108e8e87bfa5d162963c893ce Mon Sep 17 00:00:00 2001 From: Kiran Kandi Date: Thu, 2 Apr 2009 23:51:59 -0700 Subject: msm: export msm_rpc_create_server Signed-off-by: Kiran Kandi --- arch/arm/mach-msm/smd_rpcrouter_servers.c | 1 + 1 file changed, 1 insertion(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/smd_rpcrouter_servers.c b/arch/arm/mach-msm/smd_rpcrouter_servers.c index 496ab3fcb0e0..931c30118fb5 100644 --- a/arch/arm/mach-msm/smd_rpcrouter_servers.c +++ b/arch/arm/mach-msm/smd_rpcrouter_servers.c @@ -96,6 +96,7 @@ int msm_rpc_create_server(struct msm_rpc_server *server) return 0; } +EXPORT_SYMBOL(msm_rpc_create_server); static int rpc_send_accepted_void_reply(struct msm_rpc_endpoint *client, uint32_t xid, uint32_t accept_status) -- cgit v1.2.3 From 5c31284813d18837e7a98f92a414649397a3049c Mon Sep 17 00:00:00 2001 From: Saravana Kannan Date: Thu, 21 May 2009 12:02:00 -0700 Subject: [ARM] msm: clock: Add new clocks for 7x27 and 8x50. Signed-off-by: Saravana Kannan --- arch/arm/mach-msm/clock.h | 9 ++++++++- arch/arm/mach-msm/devices.c | 5 +++++ 2 files changed, 13 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/clock.h b/arch/arm/mach-msm/clock.h index c342ca924ab5..8564c65ea19c 100644 --- a/arch/arm/mach-msm/clock.h +++ b/arch/arm/mach-msm/clock.h @@ -97,7 +97,14 @@ struct clk { #define SPI_CLK 45 #define VFE_AXI_CLK 46 -#define NR_CLKS 47 +#define USB_HS2_CLK 47 /* High speed USB 2 core clock */ +#define USB_HS2_PCLK 48 /* High speed USB 2 pbus clock */ +#define USB_HS3_CLK 49 /* High speed USB 3 core clock */ +#define USB_HS3_PCLK 50 /* High speed USB 3 pbus clock */ + +#define GRP_PCLK 51 /* Graphics pbus clock */ + +#define NR_CLKS 52 #ifdef CONFIG_DEBUG_FS #define CLOCK_DBG_NAME(x) .dbg_name = x, diff --git a/arch/arm/mach-msm/devices.c b/arch/arm/mach-msm/devices.c index 8465be7cbc64..fd51b134a6a6 100644 --- a/arch/arm/mach-msm/devices.c +++ b/arch/arm/mach-msm/devices.c @@ -530,6 +530,7 @@ struct clk msm_clocks_7x27[] = { CLOCK("vdc_clk", VDC_CLK, NULL, OFF | CLK_MIN), CLOCK("vfe_clk", VFE_CLK, NULL, OFF), CLOCK("vfe_mdc_clk", VFE_MDC_CLK, NULL, OFF), + CLOCK("grp_pclk", GRP_PCLK, NULL, 0), }; unsigned msm_num_clocks_7x27 = ARRAY_SIZE(msm_clocks_7x27); @@ -580,6 +581,10 @@ struct clk msm_clocks_8x50[] = { CLOCK("vfe_clk", VFE_CLK, NULL, OFF), CLOCK("vfe_mdc_clk", VFE_MDC_CLK, NULL, OFF), CLOCK("vfe_axi_clk", VFE_AXI_CLK, NULL, OFF), + CLOCK("usb_hs2_clk", USB_HS2_CLK, NULL, OFF), + CLOCK("usb_hs2_pclk", USB_HS2_PCLK, NULL, OFF), + CLOCK("usb_hs3_clk", USB_HS3_CLK, NULL, OFF), + CLOCK("usb_hs3_pclk", USB_HS3_PCLK, NULL, OFF), }; unsigned msm_num_clocks_8x50 = ARRAY_SIZE(msm_clocks_8x50); -- cgit v1.2.3 From 409133317b7544d595f646b1d55a097df25f8dec Mon Sep 17 00:00:00 2001 From: "Pfeffer, Zach" Date: Fri, 22 May 2009 13:30:33 -0600 Subject: [ARM] msm: Add write and read to execute tests and return results Reading the device node returns the return code of the last test run. If no tests have been run the node will return 0. The return code is returned as an ASCII coded signed integer. Tests and Test Modification Commands ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ null_test reg_test data_reg_test data_cb_reg_test use_multi_clients use_default_client Execute Test Example ~~~~~~~~~~~~~~~~~~~~ echo null_test > /dev/ping_test Read Last Test Example ~~~~~~~~~~~~~~~~~~~~~~ cat /dev/ping_test Signed-off-by: Zach Pfeffer --- arch/arm/mach-msm/smd_rpc_ping.c | 71 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/smd_rpc_ping.c b/arch/arm/mach-msm/smd_rpc_ping.c index fc23a8e6dd1c..6dc2e8ef9a0f 100644 --- a/arch/arm/mach-msm/smd_rpc_ping.c +++ b/arch/arm/mach-msm/smd_rpc_ping.c @@ -64,6 +64,7 @@ #include #include #include +#include #include #define PING_TEST_BASE 0x31 @@ -527,6 +528,7 @@ static int ping_test_release(struct inode *ip, struct file *fp) msm_rpc_unregister_client(rpc_client); pr_info("%s: disconnected from remote ping server\n", __func__); + kfree(fp->private_data); } mutex_unlock(&ping_mdm_lock); return 0; @@ -534,6 +536,8 @@ static int ping_test_release(struct inode *ip, struct file *fp) static int ping_test_open(struct inode *ip, struct file *fp) { + int *test_res; + mutex_lock(&ping_mdm_lock); if (open_count++ == 0) { rpc_client = msm_rpc_register_client("pingdef", @@ -545,6 +549,16 @@ static int ping_test_open(struct inode *ip, struct file *fp) return PTR_ERR(rpc_client); } pr_info("%s: connected to remote ping server\n", __func__); + test_res = kzalloc(sizeof(int), GFP_KERNEL); + if (IS_ERR(test_res)) { + msm_rpc_unregister_client(rpc_client); + pr_info("%s: disconnected from remote ping server\n", + __func__); + mutex_unlock(&ping_mdm_lock); + return -ENOMEM; + } + + fp->private_data = test_res; } mutex_unlock(&ping_mdm_lock); return 0; @@ -589,9 +603,66 @@ static int ping_test_ioctl(struct inode *ip, struct file *fp, return 0; } +static ssize_t ping_test_read(struct file *fp, char __user *buf, + size_t count, loff_t *pos) +{ + int *test_res = fp->private_data; + char _buf[16]; + + snprintf(_buf, sizeof(_buf), "%i\n", *test_res); + + return simple_read_from_buffer(buf, count, pos, _buf, strlen(_buf)); +} + +static ssize_t ping_test_write(struct file *fp, const char __user *buf, + size_t count, loff_t *pos) +{ + unsigned char cmd[64]; + int len; + int *test_res; + + test_res = (int *) fp->private_data; + + if (count < 1) + return 0; + + len = count > 63 ? 63 : count; + + if (copy_from_user(cmd, buf, len)) + return -EFAULT; + + cmd[len] = 0; + + /* lazy */ + if (cmd[len-1] == '\n') { + cmd[len-1] = 0; + len--; + } + + if (!strncmp(cmd, "null_test", 64)) { + *test_res = ping_mdm_null_test(); + } else if (!strncmp(cmd, "reg_test", 64)) { + *test_res = ping_mdm_register_test(); + } else if (!strncmp(cmd, "data_reg_test", 64)) { + *test_res = ping_mdm_data_register_test(); + } else if (!strncmp(cmd, "data_cb_reg_test", 64)) { + *test_res = ping_mdm_data_cb_register_test(); + } else if (!strncmp(cmd, "use_multi_clients", 64)) { + ping_test_use_multi_clients = 1; + pr_info("%s: tests to use multiple clients\n", __func__); + } else if (!strncmp(cmd, "use_default_client", 64)) { + ping_test_use_multi_clients = 0; + pr_info("%s: tests to use default client\n", __func__); + } + + return count; +} + static const struct file_operations ping_test_fops = { .owner = THIS_MODULE, .open = ping_test_open, + .read = ping_test_read, + .write = ping_test_write, .release = ping_test_release, .ioctl = ping_test_ioctl, }; -- cgit v1.2.3 From 3e6ca518723f2ba7562f65100f1c5b1064e085f0 Mon Sep 17 00:00:00 2001 From: Neil Leeder Date: Fri, 29 May 2009 15:59:37 -0400 Subject: [ARM] msm: turn on USB clock for 8K Comet2 Enable the USB TCXO clock in the Comet CPLD Signed-off-by: Neil Leeder --- arch/arm/mach-msm/board-comet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/board-comet.c b/arch/arm/mach-msm/board-comet.c index ffbd2657b27f..cb4569d01a5b 100644 --- a/arch/arm/mach-msm/board-comet.c +++ b/arch/arm/mach-msm/board-comet.c @@ -140,7 +140,7 @@ static struct comet_cpld_t { .i2c_enable = 0x07FF, /* enable all peripherals except microphones and */ /* displays */ - .per_enable_all = 0xF9B0, + .per_enable_all = 0xF9B8, .ext_per_enable_all = 0x007F, .bt_reset_reg = 0x0048, .bt_reset_mask = 0x0004, -- cgit v1.2.3 From 7aee42ee8e14c0f04c174f9760cc742a37cd1f17 Mon Sep 17 00:00:00 2001 From: Neil Leeder Date: Fri, 29 May 2009 18:04:18 -0400 Subject: [ARM] msm: add platform support for Comet displays Supports the various display combinations available on both the Comet1 and Comet2 boards Signed-off-by: Neil Leeder --- arch/arm/mach-msm/board-comet.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/board-comet.c b/arch/arm/mach-msm/board-comet.c index cb4569d01a5b..cfc8cd2f2cd2 100644 --- a/arch/arm/mach-msm/board-comet.c +++ b/arch/arm/mach-msm/board-comet.c @@ -363,6 +363,7 @@ static int msm_fb_detect_panel(const char *name) int ret; if ((!strcmp(name, "mddi_toshiba_wvga") && wvga_present) || + (!strcmp(name, "lcdc_external") && wvga_present) || (!strcmp(name, "lcdc_wxga") && wxga_present)) ret = 0; else @@ -1026,7 +1027,7 @@ static void __init comet_init(void) } else { cpld_info = &comet_cpld[0]; wvga_present = 1; - wxga_present = 1; + wxga_present = 0; per_enable = cpld_info->per_enable_all; smc911x_resources[0].start = 0x90000000; smc911x_resources[0].end = 0x90000100; -- cgit v1.2.3 From 2b9754baa308c98e1451acd4895cc5e43ed56ef9 Mon Sep 17 00:00:00 2001 From: Neil Leeder Date: Fri, 29 May 2009 13:30:55 -0400 Subject: [ARM] msm: keep vmalloc space location with 2G/2G memory split The 2G/2G memory split option moves the kernel starting address PAGE_OFFSET down 1GB from its default location. This keeps vmalloc space at the same location, ending at 0xE0000000. Signed-off-by: Neil Leeder --- arch/arm/mach-msm/include/mach/vmalloc.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/include/mach/vmalloc.h b/arch/arm/mach-msm/include/mach/vmalloc.h index b70059d432ac..9d8c8375b206 100644 --- a/arch/arm/mach-msm/include/mach/vmalloc.h +++ b/arch/arm/mach-msm/include/mach/vmalloc.h @@ -1,6 +1,7 @@ /* arch/arm/mach-msm/include/mach/vmalloc.h * * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2009, Code Aurora Forum. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -16,7 +17,11 @@ #ifndef __ASM_ARCH_MSM_VMALLOC_H #define __ASM_ARCH_MSM_VMALLOC_H +#ifdef CONFIG_VMSPLIT_2G +#define VMALLOC_END (PAGE_OFFSET + 0x60000000) +#else #define VMALLOC_END (PAGE_OFFSET + 0x20000000) +#endif #endif -- cgit v1.2.3 From 1380c03b75ec6b95e3aef5f45167fa16882db585 Mon Sep 17 00:00:00 2001 From: Trilok Soni Date: Fri, 5 Jun 2009 15:30:29 +0530 Subject: [ARM] msm: handset: Add handset callback api support Add support for receiving handset events from modem through RPC callback api mechanism. Enabled only for 7x27 SURF and FFAs. Signed-off-by: Trilok Soni --- arch/arm/mach-msm/rpc_server_handset.c | 201 ++++++++++++++++++++++++++++++++- 1 file changed, 196 insertions(+), 5 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/rpc_server_handset.c b/arch/arm/mach-msm/rpc_server_handset.c index 4b97c6a4f7e7..d44574361d02 100644 --- a/arch/arm/mach-msm/rpc_server_handset.c +++ b/arch/arm/mach-msm/rpc_server_handset.c @@ -18,6 +18,8 @@ #include #include +#include + #include #include #include @@ -27,6 +29,15 @@ #define HS_SERVER_PROG 0x30000062 #define HS_SERVER_VERS 0x00010001 +#define HS_RPC_PROG 0x30000091 +#define HS_RPC_VERS 0x00010001 + +#define HS_RPC_CB_PROG 0x31000091 +#define HS_RPC_CB_VERS 0x00010001 + +#define HS_SUBSCRIBE_SRVC_PROC 0x03 +#define HS_EVENT_CB_PROC 1 + #define RPC_KEYPAD_NULL_PROC 0 #define RPC_KEYPAD_PASS_KEY_CODE_PROC 2 #define RPC_KEYPAD_SET_PWR_KEY_STATE_PROC 3 @@ -39,6 +50,60 @@ #define KEY(hs_key, input_key) ((hs_key << 24) | input_key) +struct hs_key_data { + uint32_t ver; /* Version number to track sturcture changes */ + uint32_t code; /* which key? */ + uint32_t parm; /* key status. Up/down or pressed/released */ +}; + +enum hs_subs_srvc { + HS_SUBS_SEND_CMD = 0, /* Subscribe to send commands to HS */ + HS_SUBS_RCV_EVNT, /* Subscribe to receive Events from HS */ + HS_SUBS_SRVC_MAX +}; + +enum hs_subs_req { + HS_SUBS_REGISTER, /* Subscribe */ + HS_SUBS_CANCEL, /* Unsubscribe */ + HS_SUB_STATUS_MAX +}; + +enum hs_event_class { + HS_EVNT_CLASS_ALL = 0, /* All HS events */ + HS_EVNT_CLASS_LAST, /* Should always be the last class type */ + HS_EVNT_CLASS_MAX +}; + +enum hs_cmd_class { + HS_CMD_CLASS_LCD = 0, /* Send LCD related commands */ + HS_CMD_CLASS_KPD, /* Send KPD related commands */ + HS_CMD_CLASS_LAST, /* Should always be the last class type */ + HS_CMD_CLASS_MAX +}; + +/* + * Receive events or send command + */ +union hs_subs_class { + enum hs_event_class evnt; + enum hs_cmd_class cmd; +}; + +struct hs_subs { + uint32_t ver; + enum hs_subs_srvc srvc; /* commands or events */ + enum hs_subs_req req; /* subscribe or unsubscribe */ + uint32_t host_os; + enum hs_subs_req disc; /* discriminator */ + union hs_subs_class id; +}; + +struct hs_event_cb_recv { + uint32_t cb_id; + uint32_t hs_key_data_ptr; + struct hs_key_data key; +}; + static const uint32_t hs_key_map[] = { KEY(HS_PWR_K, KEY_POWER), KEY(HS_END_K, KEY_END), @@ -49,6 +114,7 @@ static const uint32_t hs_key_map[] = { static struct input_dev *kpdev; static struct input_dev *hsdev; +static struct msm_rpc_client *rpc_client; static int hs_find_key(uint32_t hscode) { @@ -98,6 +164,9 @@ static void report_hs_key(uint32_t key_code, uint32_t key_parm) if (key_parm == HS_REL_K) key_code = key_parm; + kpdev = msm_keypad_get_input_dev(); + hsdev = msm_get_handset_input_dev(); + switch (key) { case KEY_POWER: case KEY_END: @@ -144,9 +213,6 @@ static int handle_hs_rpc_call(struct msm_rpc_server *server, uint32_t key_parm; }; - kpdev = msm_keypad_get_input_dev(); - hsdev = msm_get_handset_input_dev(); - switch (req->procedure) { case RPC_KEYPAD_NULL_PROC: return 0; @@ -181,8 +247,133 @@ static struct msm_rpc_server hs_rpc_server = { .rpc_call = handle_hs_rpc_call, }; -static int __init hs_rpc_server_init(void) +static int process_subs_srvc_callback(struct hs_event_cb_recv *recv) +{ + if (!recv) + return -ENODATA; + + report_hs_key(be32_to_cpu(recv->key.code), be32_to_cpu(recv->key.parm)); + + return 0; +} + +static void process_hs_rpc_request(uint32_t proc, void *data) +{ + if (proc == HS_EVENT_CB_PROC) + process_subs_srvc_callback(data); + else + pr_err("%s: unknown rpc proc %d\n", __func__, proc); +} + +static int hs_rpc_register_subs_arg(void *buffer, void *data) { + struct hs_subs_rpc_req { + uint32_t hs_subs_ptr; + struct hs_subs hs_subs; + uint32_t hs_cb_id; + uint32_t hs_handle_ptr; + uint32_t hs_handle_data; + }; + + struct hs_subs_rpc_req *req = buffer; + + req->hs_subs_ptr = cpu_to_be32(0x1); + req->hs_subs.ver = cpu_to_be32(0x1); + req->hs_subs.srvc = cpu_to_be32(HS_SUBS_RCV_EVNT); + req->hs_subs.req = cpu_to_be32(HS_SUBS_REGISTER); + req->hs_subs.host_os = cpu_to_be32(0x4); /* linux */ + req->hs_subs.disc = cpu_to_be32(HS_SUBS_RCV_EVNT); + req->hs_subs.id.evnt = cpu_to_be32(HS_EVNT_CLASS_ALL); + + req->hs_cb_id = cpu_to_be32(0x1); + + req->hs_handle_ptr = cpu_to_be32(0x1); + req->hs_handle_data = cpu_to_be32(0x0); + + return sizeof(*req); +} + +static int hs_rpc_register_subs_res(void *buffer, void *data) +{ + uint32_t result; + + result = be32_to_cpu(*((uint32_t *)buffer)); + pr_debug("%s: request completed: 0x%x\n", __func__, result); + + return 0; +} + +static int hs_cb_func(struct msm_rpc_client *client, void *buffer, int in_size) +{ + int rc = -1; + + struct rpc_request_hdr *hdr = buffer; + + hdr->type = be32_to_cpu(hdr->type); + hdr->xid = be32_to_cpu(hdr->xid); + hdr->rpc_vers = be32_to_cpu(hdr->rpc_vers); + hdr->prog = be32_to_cpu(hdr->prog); + hdr->vers = be32_to_cpu(hdr->vers); + hdr->procedure = be32_to_cpu(hdr->procedure); + + if (hdr->type != 0) + return rc; + if (hdr->rpc_vers != 2) + return rc; + if (hdr->prog != HS_RPC_CB_PROG) + return rc; + if (!msm_rpc_is_compatible_version(HS_RPC_CB_VERS, + hdr->vers)) + return rc; + + process_hs_rpc_request(hdr->procedure, + (void *) (hdr + 1)); + + rc = msm_rpc_send_accepted_reply(client, hdr->xid, + RPC_ACCEPTSTAT_SUCCESS, NULL, 0); + if (rc) { + pr_err("%s: sending reply failed: %d\n", __func__, rc); + return rc; + } + + return 0; +} + +static int __init hs_rpc_cb_init(void) +{ + int rc = 0; + + rpc_client = msm_rpc_register_client("hs", + HS_RPC_PROG, HS_RPC_VERS, 0, hs_cb_func); + + if (IS_ERR(rpc_client)) { + pr_err("%s: couldn't open rpc client err %ld\n", __func__, + PTR_ERR(rpc_client)); + return PTR_ERR(rpc_client); + } + + rc = msm_rpc_client_req(rpc_client, HS_SUBSCRIBE_SRVC_PROC, + hs_rpc_register_subs_arg, + hs_rpc_register_subs_res, + NULL); + if (rc) { + pr_err("%s: couldn't send rpc client request\n", __func__); + msm_rpc_unregister_client(rpc_client); + } + + return rc; +} + +static int __init hs_rpc_init(void) +{ + int rc; + + if (machine_is_msm7x27_surf() || machine_is_msm7x27_ffa()) { + rc = hs_rpc_cb_init(); + if (rc) + pr_err("%s: failed to initialize\n", __func__); + } + return msm_rpc_create_server(&hs_rpc_server); } -module_init(hs_rpc_server_init); +module_init(hs_rpc_init); -- cgit v1.2.3 From 1d6ff152cda7b72c2221bac7e558346c9792a1be Mon Sep 17 00:00:00 2001 From: "Pfeffer, Zach" Date: Fri, 5 Jun 2009 09:58:29 -0600 Subject: [ARM] msm: Save test results across reads and writes This module contains many tests that are launched by writing the test name into the device node. Test results are retrieved by reading the device node. The test return value was being allocated in the open and freed in the close. This meant that the typical open, read, close and open, write, close of echo and cat deallocated the return value. This fix statically allocates the return value so that its value is saved across echo and cat. Signed-off-by: Zach Pfeffer --- arch/arm/mach-msm/smd_rpc_ping.c | 28 +++++++--------------------- 1 file changed, 7 insertions(+), 21 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/smd_rpc_ping.c b/arch/arm/mach-msm/smd_rpc_ping.c index 6dc2e8ef9a0f..60858f555437 100644 --- a/arch/arm/mach-msm/smd_rpc_ping.c +++ b/arch/arm/mach-msm/smd_rpc_ping.c @@ -93,6 +93,7 @@ #define PING_MDM_CB_PROC 2 static struct msm_rpc_client *rpc_client; +static uint32_t test_res; static uint32_t open_count; static uint32_t ping_test_use_multi_clients; static DEFINE_MUTEX(ping_mdm_lock); @@ -536,8 +537,6 @@ static int ping_test_release(struct inode *ip, struct file *fp) static int ping_test_open(struct inode *ip, struct file *fp) { - int *test_res; - mutex_lock(&ping_mdm_lock); if (open_count++ == 0) { rpc_client = msm_rpc_register_client("pingdef", @@ -549,16 +548,6 @@ static int ping_test_open(struct inode *ip, struct file *fp) return PTR_ERR(rpc_client); } pr_info("%s: connected to remote ping server\n", __func__); - test_res = kzalloc(sizeof(int), GFP_KERNEL); - if (IS_ERR(test_res)) { - msm_rpc_unregister_client(rpc_client); - pr_info("%s: disconnected from remote ping server\n", - __func__); - mutex_unlock(&ping_mdm_lock); - return -ENOMEM; - } - - fp->private_data = test_res; } mutex_unlock(&ping_mdm_lock); return 0; @@ -606,10 +595,9 @@ static int ping_test_ioctl(struct inode *ip, struct file *fp, static ssize_t ping_test_read(struct file *fp, char __user *buf, size_t count, loff_t *pos) { - int *test_res = fp->private_data; char _buf[16]; - snprintf(_buf, sizeof(_buf), "%i\n", *test_res); + snprintf(_buf, sizeof(_buf), "%i\n", test_res); return simple_read_from_buffer(buf, count, pos, _buf, strlen(_buf)); } @@ -619,9 +607,6 @@ static ssize_t ping_test_write(struct file *fp, const char __user *buf, { unsigned char cmd[64]; int len; - int *test_res; - - test_res = (int *) fp->private_data; if (count < 1) return 0; @@ -640,13 +625,13 @@ static ssize_t ping_test_write(struct file *fp, const char __user *buf, } if (!strncmp(cmd, "null_test", 64)) { - *test_res = ping_mdm_null_test(); + test_res = ping_mdm_null_test(); } else if (!strncmp(cmd, "reg_test", 64)) { - *test_res = ping_mdm_register_test(); + test_res = ping_mdm_register_test(); } else if (!strncmp(cmd, "data_reg_test", 64)) { - *test_res = ping_mdm_data_register_test(); + test_res = ping_mdm_data_register_test(); } else if (!strncmp(cmd, "data_cb_reg_test", 64)) { - *test_res = ping_mdm_data_cb_register_test(); + test_res = ping_mdm_data_cb_register_test(); } else if (!strncmp(cmd, "use_multi_clients", 64)) { ping_test_use_multi_clients = 1; pr_info("%s: tests to use multiple clients\n", __func__); @@ -682,6 +667,7 @@ static int __init ping_test_init(void) { int rc = 0; + test_res = 0; open_count = 0; ping_test_use_multi_clients = 0; rc = misc_register(&ping_test_device); -- cgit v1.2.3 From 570f1514e2ae395a3b9e97c346c7060b42a69462 Mon Sep 17 00:00:00 2001 From: "Li, Ai" Date: Tue, 5 May 2009 16:04:44 -0600 Subject: [ARM] msm: pm: set CLK_SLEEP_EN register before SWFI Setting the register before SWFI allows several clocks to be turned off during SWFI. This could yield additional power savings. Signed-off-by: Li, Ai --- arch/arm/mach-msm/pm2.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/pm2.c b/arch/arm/mach-msm/pm2.c index 88f07b056f77..4112b368b937 100644 --- a/arch/arm/mach-msm/pm2.c +++ b/arch/arm/mach-msm/pm2.c @@ -368,10 +368,17 @@ static void msm_pm_config_hw_before_power_down(void) */ static void msm_pm_config_hw_after_power_up(void) { - writel(0x00, APPS_CLK_SLEEP_EN); writel(0, APPS_PWRDOWN); } +/* + * Configure hardware registers in preparation for SWFI. + */ +static void msm_pm_config_hw_before_swfi(void) +{ + writel(0x1f, APPS_CLK_SLEEP_EN); +} + /****************************************************************************** * State Polling Definitions @@ -1166,6 +1173,7 @@ static int msm_pm_swfi(bool ramp_acpu) return -EIO; } + msm_pm_config_hw_before_swfi(); msm_arch_idle(); if (ramp_acpu) { -- cgit v1.2.3 From 2a1cc0afd98e7187ebb87fbd4ddf0e1c952b28df Mon Sep 17 00:00:00 2001 From: "Li, Ai" Date: Thu, 4 Jun 2009 21:52:30 -0400 Subject: [ARM] msm: suspend: fix suspend restore code Added code to preserve critical CP15 registers. Update MMU restore function to properly follow ARMv7 TEX remapping procedures. Clean up code. Signed-off-by: Li, Ai --- arch/arm/mach-msm/idle-v7.S | 62 ++++++++++++++++++++++++++++++++------------- 1 file changed, 44 insertions(+), 18 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/idle-v7.S b/arch/arm/mach-msm/idle-v7.S index ad49e46b45c7..00175f0bcc3d 100644 --- a/arch/arm/mach-msm/idle-v7.S +++ b/arch/arm/mach-msm/idle-v7.S @@ -19,43 +19,56 @@ #include #include +ENTRY(msm_arch_idle) + wfi + bx lr + ENTRY(msm_pm_collapse) +#if defined(CONFIG_MSM_FIQ_SUPPORT) + cpsid f +#endif + ldr r0, =saved_state stmia r0!, {r4-r14} mrc p15, 0, r1, c1, c0, 0 /* MMU control */ - mrc p15, 0, r2, c2, c0, 0 /* ttb */ + mrc p15, 0, r2, c2, c0, 0 /* TTBR0 */ mrc p15, 0, r3, c3, c0, 0 /* dacr */ mrc p15, 3, r4, c15, c0, 3 /* L2CR1 is the L2 cache control reg 1 */ + mrc p15, 0, r5, c10, c2, 0 /* PRRR */ + mrc p15, 0, r6, c10, c2, 1 /* NMRR */ + mrc p15, 0, r7, c1, c0, 1 /* ACTLR */ + mrc p15, 0, r8, c2, c0, 1 /* TTBR1 */ + mrc p15, 0, r9, c13, c0, 3 /* TPIDRURO */ mrc p15, 0, ip, c13, c0, 1 /* context ID */ - stmia r0!, {r1-r4, ip} + stmia r0!, {r1-r9, ip} + #ifdef CONFIG_VFP VFPFSTMIA r0, r1 /* Save VFP working registers */ fmrx r1, fpexc fmrx r2, fpscr stmia r0!, {r1, r2} /* Save VFP state registers */ #endif - stmfd sp!, {r4-r5, r7, r9-r11, lr} bl v7_flush_dcache_all - ldmfd sp!, {r4-r5, r7, r9-r11, lr} mrc p15, 0, r1, c1, c0, 0 /* read current CR */ bic r0, r1, #(1 << 2) /* clear dcache bit */ bic r0, r0, #(1 << 12) /* clear icache bit */ mcr p15, 0, r0, c1, c0, 0 /* disable d/i cache */ - /* fall though */ -ENTRY(msm_arch_idle) -#if defined(CONFIG_MSM_FIQ_SUPPORT) - cpsid f -#endif - mov r0, #0 /* prepare wfi value - * also used as return value from - * msm_pm_collapse */ + + dsb wfi + mcr p15, 0, r1, c1, c0, 0 /* restore d/i cache */ + isb + #if defined(CONFIG_MSM_FIQ_SUPPORT) cpsie f #endif - mov pc, lr + + ldr r0, =saved_state /* restore registers */ + ldmfd r0, {r4-r14} + mov r0, #0 /* return power collapse failed */ + bx lr ENTRY(msm_pm_collapse_exit) #if 0 /* serial debug */ @@ -89,11 +102,16 @@ ENTRY(msm_pm_collapse_exit) fmxr fpscr, r3 /* Restore FPSCR */ fmxr fpexc, r2 /* Restore FPEXC last */ #endif - ldmdb r1!, {r2-r6} + ldmdb r1!, {r2-r11} mcr p15, 0, r4, c3, c0, 0 /* dacr */ - mcr p15, 0, r3, c2, c0, 0 /* ttb */ + mcr p15, 0, r3, c2, c0, 0 /* TTBR0 */ mcr p15, 3, r5, c15, c0, 3 /* L2CR1 */ - mcr p15, 0, r6, c13, c0, 1 /* context ID */ + mcr p15, 0, r6, c10, c2, 0 /* PRRR */ + mcr p15, 0, r7, c10, c2, 1 /* NMRR */ + mcr p15, 0, r8, c1, c0, 1 /* ACTLR */ + mcr p15, 0, r9, c2, c0, 1 /* TTBR1 */ + mcr p15, 0, r10, c13, c0, 3 /* TPIDRURO */ + mcr p15, 0, r11, c13, c0, 1 /* context ID */ isb ldmdb r1!, {r4-r14} /* Add 1:1 map in the PMD to allow smooth switch when turning on MMU */ @@ -106,6 +124,7 @@ ENTRY(msm_pm_collapse_exit) lsr r0, #20 /* align current addr to 1MB boundary */ lsl r0, #20 /* Create new entry for this 1MB page */ + orr r0, r0, #0x4 /* PMD_SECT_BUFFERED */ orr r0, r0, #0x400 /* PMD_SECT_AP_WRITE */ orr r0, r0, #0x2 /* PMD_TYPE_SECT|PMD_DOMAIN(DOMAIN_KERNEL) */ str r0, [r3] /* put new entry into the MMU table */ @@ -127,8 +146,15 @@ msm_pm_pa_to_va: mcr p15, 0, r3, c7, c10, 1 /* flush_pmd */ dsb isb + mcr p15, 0, r3, c8, c7, 0 /* UTLBIALL */ + mcr p15, 0, r3, c7, c5, 6 /* BPIALL */ + dsb + isb + stmfd sp!, {lr} + bl v7_flush_kern_cache_all + ldmfd sp!, {lr} mov r0, #1 - mov pc, lr + bx lr nop nop nop @@ -141,7 +167,7 @@ msm_pm_pa_to_va: saved_state: .space 4 * 11 /* r4-14 */ - .space 4 * 5 /* cp15 */ + .space 4 * 10 /* cp15 */ #ifdef CONFIG_VFP .space 8 * 32 /* VFP working registers */ .space 4 * 2 /* VFP state registers */ -- cgit v1.2.3 From 28da3c811427394626af55a88f5e585e77bf9290 Mon Sep 17 00:00:00 2001 From: Saravana Kannan Date: Fri, 5 Jun 2009 13:52:52 -0700 Subject: [ARM] msm: acpuclock-8x50: Fix SCPLL init and freq switching code. Use HOP switch method instead of SHOT switch method when changing SCPLL frequency (except for the very first time) to work around a hardware bug that manifests when using SHOT switch at temperatures around -20 C. Add a few delays between SCPLL state changes. CRs-fixed: 180376 Signed-off-by: Saravana Kannan --- arch/arm/mach-msm/acpuclock-8x50.c | 61 ++++++++++++++++++++++++++++++++++---- 1 file changed, 55 insertions(+), 6 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/acpuclock-8x50.c b/arch/arm/mach-msm/acpuclock-8x50.c index fd2400dedd53..17c89c5e9ba0 100644 --- a/arch/arm/mach-msm/acpuclock-8x50.c +++ b/arch/arm/mach-msm/acpuclock-8x50.c @@ -208,9 +208,9 @@ static void scpll_set_freq(uint32_t lval, unsigned freq_switch) while (readl(SCPLL_STATUS_ADDR) & 0x1) ; - /* status bit seems to clear early, requires at least - * ~8 microseconds to settle, using 20 to be safe */ - udelay(20); + /* status bit seems to clear early, using + * 100us to handle the worst case. */ + udelay(100); } static void scpll_apps_enable(bool state) @@ -234,6 +234,7 @@ static void scpll_apps_enable(bool state) regval = readl(SCPLL_CTL_ADDR); regval |= (0x7); writel(regval, SCPLL_CTL_ADDR); + udelay(200); } else { /* put the pll in power down mode */ regval = readl(SCPLL_CTL_ADDR); @@ -245,6 +246,10 @@ static void scpll_apps_enable(bool state) static void scpll_init(void) { + uint32_t regval; +#define L_VAL_384MHZ 0xA +#define L_VAL_768MHZ 0x14 + /* power down scpll */ writel(0x0, SCPLL_CTL_ADDR); @@ -264,8 +269,52 @@ static void scpll_init(void) while (readl(SCPLL_STATUS_ADDR) & 0x2) ; - /* power down scpll */ - writel(0x0, SCPLL_CTL_ADDR); + /* Start: Set of experimentally derived steps + * to work around a h/w bug. */ + + /* Put the pll in normal mode */ + scpll_apps_enable(1); + + /* SHOT switch to 384 MHz */ + regval = readl(SCPLL_FSM_CTL_EXT_ADDR); + regval &= ~(0x3f << 3); + regval |= (L_VAL_384MHZ << 3); + writel(regval, SCPLL_FSM_CTL_EXT_ADDR); + + regval &= ~0x7; + regval |= SHOT_SWITCH; + writel(regval, SCPLL_FSM_CTL_EXT_ADDR); + + /* Wait for frequency switch to finish */ + while (readl(SCPLL_STATUS_ADDR) & 0x1) + ; + + /* Status bit seems to clear early, using + * 800 microseconds for the worst case. */ + udelay(800); + + /* HOP switch to 768 MHz. */ + regval = readl(SCPLL_FSM_CTL_EXT_ADDR); + regval &= ~(0x3f << 3); + regval |= (L_VAL_768MHZ << 3); + writel(regval, SCPLL_FSM_CTL_EXT_ADDR); + + regval &= ~0x7; + regval |= HOP_SWITCH; + writel(regval, SCPLL_FSM_CTL_EXT_ADDR); + + /* Wait for frequency switch to finish */ + while (readl(SCPLL_STATUS_ADDR) & 0x1) + ; + + /* Status bit seems to clear early, using + * 100 microseconds for the worst case. */ + udelay(100); + + /* End: Work around for h/w bug */ + + /* Power down scpll */ + scpll_apps_enable(0); } static void config_pll(struct clkctl_acpu_speed *s) @@ -273,7 +322,7 @@ static void config_pll(struct clkctl_acpu_speed *s) uint32_t regval; if (s->pll == ACPU_PLL_3) - scpll_set_freq(s->sc_l_value, SHOT_SWITCH); + scpll_set_freq(s->sc_l_value, HOP_SWITCH); else { /* get the current clock source selection */ regval = readl(SPSS_CLK_SEL_ADDR) & 0x1; -- cgit v1.2.3 From 192f43243614f50bbbebb145abf264cc94aa0668 Mon Sep 17 00:00:00 2001 From: Sriranjan Srikantam Date: Tue, 9 Jun 2009 20:05:16 +0530 Subject: [ARM] msm: snd: Update snd end points list with new devices Signed-off-by: Sriranjan Srikantam --- arch/arm/mach-msm/board-msm7x27.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/board-msm7x27.c b/arch/arm/mach-msm/board-msm7x27.c index 84f9d797b8f6..7dd5468d2240 100644 --- a/arch/arm/mach-msm/board-msm7x27.c +++ b/arch/arm/mach-msm/board-msm7x27.c @@ -165,9 +165,15 @@ static struct msm_hsusb_platform_data msm_hsusb_pdata = { #define SND(desc, num) { .name = #desc, .id = num } static struct snd_endpoint snd_endpoints_list[] = { SND(HANDSET, 0), - SND(HEADSET, 2), + SND(MONO_HEADSET, 2), + SND(HEADSET, 3), SND(SPEAKER, 6), + SND(TTY_HEADSET, 8), + SND(TTY_VCO, 9), + SND(TTY_HCO, 10), SND(BT, 12), + SND(IN_S_SADC_OUT_HANDSET, 16), + SND(IN_S_SADC_OUT_SPEAKER_PHONE, 25), SND(CURRENT, 27), }; #undef SND -- cgit v1.2.3 From 9ccbec36ac35cecc0a102cf7401f63fab80623b9 Mon Sep 17 00:00:00 2001 From: Saravana Kannan Date: Mon, 8 Jun 2009 20:02:49 -0700 Subject: [ARM] msm: acpuclock-8x50: Fix efuse magic value bit length. Turns out the magic value is only 4 bits long. So don't look at the other 4 bits anymore. CRs-fixed: 183437 Signed-off-by: Saravana Kannan --- arch/arm/mach-msm/acpuclock-8x50.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/acpuclock-8x50.c b/arch/arm/mach-msm/acpuclock-8x50.c index 17c89c5e9ba0..36c90ea7d27a 100644 --- a/arch/arm/mach-msm/acpuclock-8x50.c +++ b/arch/arm/mach-msm/acpuclock-8x50.c @@ -561,8 +561,7 @@ static void __init acpu_freq_tbl_fixup(void) tcsr_spare2 = readl(TCSR_SPARE2_ADDR); /* Check if the register is supported and meaningful. */ - if ((tcsr_spare2 & 0xFF00) != 0xA500 - && (tcsr_spare2 & 0xFF00) != 0xA000) { + if ((tcsr_spare2 & 0xF000) != 0xA000) { pr_info("Efuse data on Max ACPU freq not present.\n"); goto skip_efuse_fixup; } -- cgit v1.2.3 From 4b147ece64a72f33075713ce595fc09eaeafac5e Mon Sep 17 00:00:00 2001 From: Neil Leeder Date: Wed, 10 Jun 2009 14:08:26 -0400 Subject: [ARM] msm: move DRAM physical address for 8K QSD Several address constants are changed to match the new 8K QSD physical DRAM region which is now based at 0x24000000, if new config option QSD_BASE_24000000 is set. Signed-off-by: Neil Leeder --- arch/arm/mach-msm/Kconfig | 8 ++++++++ arch/arm/mach-msm/Makefile.boot | 6 ++++++ arch/arm/mach-msm/include/mach/memory.h | 4 +++- 3 files changed, 17 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index d9a534a5a532..0d06e84cd249 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -543,4 +543,12 @@ config MSM_SLEEP_TIME_OVERRIDE in units of seconds, it overwrites the normal sleep time of suspend. The feature is required for automated power management testing. + +config QSD_BASE_24000000 + bool "Base memory at 0x24000000" + depends on ARCH_MSM_SCORPION + default n + help + Select if physical DRAM at 0x24000000 + endif diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot index ff5582cdddeb..21c60030ef38 100644 --- a/arch/arm/mach-msm/Makefile.boot +++ b/arch/arm/mach-msm/Makefile.boot @@ -1,3 +1,8 @@ +ifeq ($(CONFIG_QSD_BASE_24000000),y) + zreladdr-y := 0x24008000 +params_phys-y := 0x24000100 +initrd_phys-y := 0x28000000 +else # !CONFIG_QSD_BASE_24000000 ifeq ($(CONFIG_ARCH_QSD),y) zreladdr-y := 0x16008000 params_phys-y := 0x16000100 @@ -13,3 +18,4 @@ params_phys-y := 0x00200100 initrd_phys-y := 0x0A000000 endif # CONFIG_MSM_STACKED_MEMORY endif # CONFIG_ARCH_QSD +endif # CONFIG_QSD_BASE_24000000 diff --git a/arch/arm/mach-msm/include/mach/memory.h b/arch/arm/mach-msm/include/mach/memory.h index 7cf04464e9a6..b5be737ecdec 100644 --- a/arch/arm/mach-msm/include/mach/memory.h +++ b/arch/arm/mach-msm/include/mach/memory.h @@ -19,7 +19,9 @@ /* physical offset of RAM */ #ifdef CONFIG_MSM_STACKED_MEMORY -#ifdef CONFIG_ARCH_QSD +#ifdef CONFIG_QSD_BASE_24000000 +#define PHYS_OFFSET UL(0x24000000) +#elif defined(CONFIG_ARCH_MSM_SCORPION) #define PHYS_OFFSET UL(0x16000000) #else #define PHYS_OFFSET UL(0x10000000) -- cgit v1.2.3 From 3d5c8ce5afd788e103d9aaec755e89292c087a65 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Tue, 29 Dec 2009 11:59:36 -0800 Subject: arch/arm/mach-msm/Makefile.boot --- arch/arm/mach-msm/Makefile.boot | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot index 21c60030ef38..2bcb77de7920 100644 --- a/arch/arm/mach-msm/Makefile.boot +++ b/arch/arm/mach-msm/Makefile.boot @@ -1,13 +1,14 @@ +ifeq ($(CONFIG_ARCH_MSM_SCORPION),y) ifeq ($(CONFIG_QSD_BASE_24000000),y) zreladdr-y := 0x24008000 params_phys-y := 0x24000100 initrd_phys-y := 0x28000000 else # !CONFIG_QSD_BASE_24000000 -ifeq ($(CONFIG_ARCH_QSD),y) zreladdr-y := 0x16008000 params_phys-y := 0x16000100 initrd_phys-y := 0x1A000000 -else # !CONFIG_ARCH_QSD +endif # CONFIG_QSD_BASE_24000000 +else # CONFIG_ARCH_MSM_ARM11 ifeq ($(CONFIG_MSM_STACKED_MEMORY), y) zreladdr-y := 0x10008000 params_phys-y := 0x10000100 @@ -17,5 +18,4 @@ else # !CONFIG_MSM_STACKED_MEMORY params_phys-y := 0x00200100 initrd_phys-y := 0x0A000000 endif # CONFIG_MSM_STACKED_MEMORY -endif # CONFIG_ARCH_QSD -endif # CONFIG_QSD_BASE_24000000 +endif # CONFIG_ARCH_MSM_SCORPION -- cgit v1.2.3 From 3c250973ea680c635a8d1c7d58a553a66e4f0f62 Mon Sep 17 00:00:00 2001 From: Michael Bohan Date: Thu, 28 May 2009 14:33:11 -0700 Subject: [ARM]: msm: Add base board support for msm7x30 The MSM7X30 SoC includes a Scorpions apps processor with 512 KB of L2 cache. This patch includes support the MSM7X30 SURF board. FFA board support is not included in this patch. Signed-off-by: Michael Bohan --- arch/arm/mach-msm/Kconfig | 16 +++ arch/arm/mach-msm/Makefile | 4 +- arch/arm/mach-msm/Makefile.boot | 11 +- arch/arm/mach-msm/board-msm7x30.c | 162 ++++++++++++++++++++++ arch/arm/mach-msm/include/mach/board.h | 1 + arch/arm/mach-msm/include/mach/dma.h | 31 +++-- arch/arm/mach-msm/include/mach/irqs-7x30.h | 187 +++++++++++++++++++++++++ arch/arm/mach-msm/include/mach/irqs-7xxx.h | 2 + arch/arm/mach-msm/include/mach/irqs-8xxx.h | 2 + arch/arm/mach-msm/include/mach/irqs.h | 13 +- arch/arm/mach-msm/include/mach/msm_iomap.h | 27 +++- arch/arm/mach-msm/io.c | 37 +++++ arch/arm/mach-msm/irq.c | 216 +++++++++++++++++++---------- arch/arm/mach-msm/irq.h | 2 +- arch/arm/mach-msm/timer.c | 18 ++- 15 files changed, 617 insertions(+), 112 deletions(-) create mode 100644 arch/arm/mach-msm/board-msm7x30.c create mode 100644 arch/arm/mach-msm/include/mach/irqs-7x30.h (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index 0d06e84cd249..265e76d47de2 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -85,6 +85,22 @@ config MACH_MSM7X27_FFA help Support for the Qualcomm MSM7x27 FFA eval board. +config MACH_MSM7X30_SURF + depends on ARCH_MSM7X30 + depends on !MSM_STACKED_MEMORY + default y + bool "MSM7x30 SURF" + help + Support for the Qualcomm MSM7x30 SURF eval board. + +config MACH_MSM7X30_FFA + depends on ARCH_MSM7X30 + depends on !MSM_STACKED_MEMORY + default y + bool "MSM7x30 FFA" + help + Support for the Qualcomm MSM7x30 FFA eval board. + config MACH_SAPPHIRE depends on ARCH_MSM7X01A default n diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index a0eb02d95919..984c2ee6b37a 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -14,10 +14,11 @@ obj-y += nohlt.o obj-y += pmic.o obj-$(CONFIG_ARCH_MSM_ARM11) += acpuclock.o -obj-$(CONFIG_ARCH_MSM_SCORPION) += acpuclock-8x50.o sirc.o +obj-$(CONFIG_ARCH_MSM_SCORPION) += acpuclock-8x50.o obj-$(CONFIG_CPU_V6) += idle-v6.o obj-$(CONFIG_CPU_V7) += idle-v7.o +obj-$(CONFIG_ARCH_QSD8X50) += sirc.o obj-$(CONFIG_MSM_FIQ_SUPPORT) += fiq_glue.o obj-$(CONFIG_MACH_TROUT) += board-trout-rfkill.o obj-$(CONFIG_MSM_SMD) += smd.o smd_tty.o smd_qmi.o smem_log.o @@ -55,6 +56,7 @@ obj-$(CONFIG_TROUT_H2W) += board-trout-h2w.o obj-$(CONFIG_TROUT_BATTCHG) += htc_battery.o obj-$(CONFIG_TROUT_PWRSINK) += htc_pwrsink.o obj-$(CONFIG_ARCH_MSM7X27) += board-msm7x27.o +obj-$(CONFIG_ARCH_MSM7X30) += board-msm7x30.o obj-$(CONFIG_QSD_AUDIO) += qdsp6/ diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot index 2bcb77de7920..5a8ae0a2b516 100644 --- a/arch/arm/mach-msm/Makefile.boot +++ b/arch/arm/mach-msm/Makefile.boot @@ -3,12 +3,17 @@ ifeq ($(CONFIG_QSD_BASE_24000000),y) zreladdr-y := 0x24008000 params_phys-y := 0x24000100 initrd_phys-y := 0x28000000 -else # !CONFIG_QSD_BASE_24000000 +endif # CONFIG_QSD_BASE_24000000 +ifeq ($(CONFIG_MSM_STACKED_MEMORY), y) zreladdr-y := 0x16008000 params_phys-y := 0x16000100 initrd_phys-y := 0x1A000000 -endif # CONFIG_QSD_BASE_24000000 -else # CONFIG_ARCH_MSM_ARM11 +else # !CONFIG_MSM_STACKED_MEMORY + zreladdr-y := 0x00208000 +params_phys-y := 0x00200100 +initrd_phys-y := 0x01200000 +endif # CONFIG_MSM_STACKED_MEMORY +else # !CONFIG_ARCH_MSM_SCORPION ifeq ($(CONFIG_MSM_STACKED_MEMORY), y) zreladdr-y := 0x10008000 params_phys-y := 0x10000100 diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c new file mode 100644 index 000000000000..c701f8df489d --- /dev/null +++ b/arch/arm/mach-msm/board-msm7x30.c @@ -0,0 +1,162 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include "devices.h" +#include "timer.h" +#include "socinfo.h" +#include "pm.h" + +static struct resource smc91x_resources[] = { + [0] = { + .start = 0x8A000300, + .end = 0x8A000400, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = MSM_GPIO_TO_INT(156), + .end = MSM_GPIO_TO_INT(156), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device smc91x_device = { + .name = "smc91x", + .id = 0, + .num_resources = ARRAY_SIZE(smc91x_resources), + .resource = smc91x_resources, +}; + +static struct platform_device *devices[] __initdata = { + &msm_device_smd, + &smc91x_device, + &msm_device_nand, +}; + +static void __init msm7x30_init_irq(void) +{ + msm_init_irq(); +} + +static struct msm_pm_platform_data msm_pm_data[MSM_PM_SLEEP_MODE_NR] = { + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].supported = 0, + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].suspend_enabled = 0, + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].idle_enabled = 1, + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].latency = 16000, + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].residency = 20000, + + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].supported = 0, + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].suspend_enabled = 0, + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].idle_enabled = 0, + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].latency = 12000, + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].residency = 20000, + + [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].supported = 0, + [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].suspend_enabled + = 0, + [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].idle_enabled = 0, + [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].latency = 2000, + [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].residency = 10000, + + [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].supported = 0, + [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].suspend_enabled = 0, + [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].idle_enabled = 0, + [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].latency = 500, + [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].residency = 0, +}; + +static void __init msm7x30_init(void) +{ + if (socinfo_init() < 0) + printk(KERN_ERR "%s: socinfo_init() failed!\n", + __func__); + platform_add_devices(devices, ARRAY_SIZE(devices)); + msm_pm_set_platform_data(msm_pm_data); +} + +static void __init msm7x30_map_io(void) +{ + msm_shared_ram_phys = 0x07F00000; + msm_map_msm7x30_io(); + msm_clock_init(msm_clocks_8x50, msm_num_clocks_8x50); +} + +MACHINE_START(MSM7X30_SURF, "QCT MSM7X30 SURF") +#ifdef CONFIG_MSM_DEBUG_UART + .phys_io = MSM_DEBUG_UART_PHYS, + .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc, +#endif + .boot_params = 0x00200100, + .map_io = msm7x30_map_io, + .init_irq = msm7x30_init_irq, + .init_machine = msm7x30_init, + .timer = &msm_timer, +MACHINE_END diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h index 390a6af2dad0..5045edd36131 100644 --- a/arch/arm/mach-msm/include/mach/board.h +++ b/arch/arm/mach-msm/include/mach/board.h @@ -46,6 +46,7 @@ struct msm_acpu_clock_platform_data void __init msm_add_devices(void); void __init msm_map_common_io(void); void __init msm_map_qsd8x50_io(void); +void __init msm_map_msm7x30_io(void); void __init msm_map_comet_io(void); void __init msm_init_irq(void); void __init msm_clock_init(struct clk *clock_tbl, unsigned num_clocks); diff --git a/arch/arm/mach-msm/include/mach/dma.h b/arch/arm/mach-msm/include/mach/dma.h index d743ef88cd3a..76b545c7e725 100644 --- a/arch/arm/mach-msm/include/mach/dma.h +++ b/arch/arm/mach-msm/include/mach/dma.h @@ -42,40 +42,41 @@ int msm_dmov_exec_cmd(unsigned id, unsigned int cmdptr); #define DMOV_SD2(off, ch) (MSM_DMOV_BASE + 0x0800 + (off) + ((ch) << 2)) #define DMOV_SD3(off, ch) (MSM_DMOV_BASE + 0x0C00 + (off) + ((ch) << 2)) -/* only security domain 3 is available to the ARM11 - * SD0 -> mARM trusted, SD1 -> mARM nontrusted, SD2 -> aDSP, SD3 -> aARM - */ +#if defined(CONFIG_ARCH_MSM7X30) +#define DMOV_SD_AARM DMOV_SD2 +#else +#define DMOV_SD_AARM DMOV_SD3 +#endif -#define DMOV_CMD_PTR(ch) DMOV_SD3(0x000, ch) +#define DMOV_CMD_PTR(ch) DMOV_SD_AARM(0x000, ch) #define DMOV_CMD_LIST (0 << 29) /* does not work */ #define DMOV_CMD_PTR_LIST (1 << 29) /* works */ #define DMOV_CMD_INPUT_CFG (2 << 29) /* untested */ #define DMOV_CMD_OUTPUT_CFG (3 << 29) /* untested */ #define DMOV_CMD_ADDR(addr) ((addr) >> 3) -#define DMOV_RSLT(ch) DMOV_SD3(0x040, ch) +#define DMOV_RSLT(ch) DMOV_SD_AARM(0x040, ch) #define DMOV_RSLT_VALID (1 << 31) /* 0 == host has empties result fifo */ #define DMOV_RSLT_ERROR (1 << 3) #define DMOV_RSLT_FLUSH (1 << 2) #define DMOV_RSLT_DONE (1 << 1) /* top pointer done */ #define DMOV_RSLT_USER (1 << 0) /* command with FR force result */ -#define DMOV_FLUSH0(ch) DMOV_SD3(0x080, ch) -#define DMOV_FLUSH1(ch) DMOV_SD3(0x0C0, ch) -#define DMOV_FLUSH2(ch) DMOV_SD3(0x100, ch) -#define DMOV_FLUSH3(ch) DMOV_SD3(0x140, ch) -#define DMOV_FLUSH4(ch) DMOV_SD3(0x180, ch) -#define DMOV_FLUSH5(ch) DMOV_SD3(0x1C0, ch) +#define DMOV_FLUSH0(ch) DMOV_SD_AARM(0x080, ch) +#define DMOV_FLUSH1(ch) DMOV_SD_AARM(0x0C0, ch) +#define DMOV_FLUSH2(ch) DMOV_SD_AARM(0x100, ch) +#define DMOV_FLUSH3(ch) DMOV_SD_AARM(0x140, ch) +#define DMOV_FLUSH4(ch) DMOV_SD_AARM(0x180, ch) +#define DMOV_FLUSH5(ch) DMOV_SD_AARM(0x1C0, ch) -#define DMOV_STATUS(ch) DMOV_SD3(0x200, ch) +#define DMOV_STATUS(ch) DMOV_SD_AARM(0x200, ch) #define DMOV_STATUS_RSLT_COUNT(n) (((n) >> 29)) #define DMOV_STATUS_CMD_COUNT(n) (((n) >> 27) & 3) #define DMOV_STATUS_RSLT_VALID (1 << 1) #define DMOV_STATUS_CMD_PTR_RDY (1 << 0) +#define DMOV_ISR DMOV_SD_AARM(0x380, 0) -#define DMOV_ISR DMOV_SD3(0x380, 0) - -#define DMOV_CONFIG(ch) DMOV_SD3(0x300, ch) +#define DMOV_CONFIG(ch) DMOV_SD_AARM(0x300, ch) #define DMOV_CONFIG_FORCE_TOP_PTR_RSLT (1 << 2) #define DMOV_CONFIG_FORCE_FLUSH_RSLT (1 << 1) #define DMOV_CONFIG_IRQ_EN (1 << 0) diff --git a/arch/arm/mach-msm/include/mach/irqs-7x30.h b/arch/arm/mach-msm/include/mach/irqs-7x30.h new file mode 100644 index 000000000000..5d3a7ac08f46 --- /dev/null +++ b/arch/arm/mach-msm/include/mach/irqs-7x30.h @@ -0,0 +1,187 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef __ASM_ARCH_MSM_IRQS_7X30_H +#define __ASM_ARCH_MSM_IRQS_7X30_H + +/* MSM ACPU Interrupt Numbers */ + +#define INT_DEBUG_TIMER_EXP 0 +#define INT_GPT0_TIMER_EXP 1 +#define INT_GPT1_TIMER_EXP 2 +#define INT_WDT0_ACCSCSSBARK 3 +#define INT_WDT1_ACCSCSSBARK 4 +#define INT_AVS_SVIC 5 +#define INT_AVS_SVIC_SW_DONE 6 +#define INT_SC_DBG_RX_FULL 7 +#define INT_SC_DBG_TX_EMPTY 8 +#define INT_SC_PERF_MON 9 +#define INT_AVS_REQ_DOWN 10 +#define INT_AVS_REQ_UP 11 +#define INT_SC_ACG 12 +/* SCSS_VICFIQSTS1[13:15] are RESERVED */ +#define INT_L2_SVICCPUIRPTREQ 16 +#define INT_L2_SVICDMANSIRPTREQ 17 +#define INT_L2_SVICDMASIRPTREQ 18 +#define INT_L2_SVICSLVIRPTREQ 19 +#define INT_AD5A_MPROC_APPS_0 20 +#define INT_AD5A_MPROC_APPS_1 21 +#define INT_A9_M2A_0 22 +#define INT_A9_M2A_1 23 +#define INT_A9_M2A_2 24 +#define INT_A9_M2A_3 25 +#define INT_A9_M2A_4 26 +#define INT_A9_M2A_5 27 +#define INT_A9_M2A_6 28 +#define INT_A9_M2A_7 29 +#define INT_A9_M2A_8 30 +#define INT_A9_M2A_9 31 + +#define INT_AXI_EBI1_SC (32 + 0) +#define INT_IMEM_ERR (32 + 1) +#define INT_AXI_EBI0_SC (32 + 2) +#define INT_PBUS_SC_IRQC (32 + 3) +#define INT_PERPH_BUS_BPM (32 + 4) +#define INT_CC_TEMP_SENSE (32 + 5) +#define INT_UXMC_EBI0 (32 + 6) +#define INT_UXMC_EBI1 (32 + 7) +#define INT_EBI2_OP_DONE (32 + 8) +#define INT_EBI2_WR_ER_DONE (32 + 9) +#define INT_TCSR_SPSS_CE (32 + 10) +#define INT_EMDH (32 + 11) +#define INT_PMDH (32 + 12) +#define INT_MDC (32 + 13) +#define INT_MIDI_TO_SUPSS (32 + 14) +#define INT_LPA_2 (32 + 15) +#define INT_GPIO_GROUP1_SECURE (32 + 16) +#define INT_GPIO_GROUP2_SECURE (32 + 17) +#define INT_GPIO_GROUP1 (32 + 18) +#define INT_GPIO_GROUP2 (32 + 19) +#define INT_MPRPH_SOFTRESET (32 + 20) +#define INT_PWB_I2C (32 + 21) +#define INT_PWB_I2C_2 (32 + 22) +#define INT_TSSC_SAMPLE (32 + 23) +#define INT_TSSC_PENUP (32 + 24) +#define INT_TCHSCRN_SSBI (32 + 25) +#define INT_FM_RDS (32 + 26) +#define INT_KEYSENSE (32 + 27) +#define INT_USB_OTG_HS (32 + 28) +#define INT_USB_OTG_HS2 (32 + 29) +#define INT_USB_OTG_HS3 (32 + 30) +#define INT_RESERVED_BIT31 (32 + 31) + +#define INT_SPI_OUTPUT (64 + 0) +#define INT_SPI_INPUT (64 + 1) +#define INT_SPI_ERROR (64 + 2) +#define INT_UART1 (64 + 3) +#define INT_UART1_RX (64 + 4) +#define INT_UART2 (64 + 5) +#define INT_UART2_RX (64 + 6) +#define INT_UART3 (64 + 7) +#define INT_UART3_RX (64 + 8) +#define INT_UART1DM_IRQ (64 + 9) +#define INT_UART1DM_RX (64 + 10) +#define INT_UART2DM_IRQ (64 + 11) +#define INT_UART2DM_RX (64 + 12) +#define INT_TSIF (64 + 13) +#define INT_ADM_SC1 (64 + 14) +#define INT_ADM_SC2 (64 + 15) +#define INT_MDP (64 + 16) +#define INT_VPE (64 + 17) +#define INT_GRP_2D (64 + 18) +#define INT_GRP_3D (64 + 19) +#define INT_ROTATOR (64 + 20) +#define INT_MFC720 (64 + 21) +#define INT_JPEG (64 + 22) +#define INT_VFE (64 + 23) +#define INT_TV_ENC (64 + 24) +#define INT_PMIC_SSBI (64 + 25) +#define INT_MPM_1 (64 + 26) +#define INT_TCSR_SPSS_SAMPLE (64 + 27) +#define INT_TCSR_SPSS_PENUP (64 + 28) +#define INT_MPM_2 (64 + 29) +#define INT_SDC1_0 (64 + 30) +#define INT_SDC1_1 (64 + 31) + +#define INT_SDC3_0 (96 + 0) +#define INT_SDC3_1 (96 + 1) +#define INT_SDC2_0 (96 + 2) +#define INT_SDC2_1 (96 + 3) +#define INT_SDC4_0 (96 + 4) +#define INT_SDC4_1 (96 + 5) +/* SCSS_VICFIQSTS3[6:31] are RESERVED */ + +/* Retrofit universal macro names */ +#define INT_ADM_AARM INT_ADM_SC2 +#define INT_USB_HS INT_USB_OTG_HS +#define INT_USB_OTG INT_USB_OTG_HS +#define INT_TCHSCRN1 INT_TSSC_PENUP +#define INT_TCHSCRN2 INT_TSSC_SAMPLE +#define INT_GP_TIMER_EXP INT_GPT0_TIMER_EXP +#define INT_ADSP_A11 INT_AD5A_MPROC_APPS_0 +#define INT_ADSP_A9_A11 INT_AD5A_MPROC_APPS_1 +#define INT_MDDI_EXT INT_EMDH +#define INT_MDDI_PRI INT_PMDH +#define INT_MDDI_CLIENT INT_MDC +#define INT_NAND_WR_ER_DONE INT_EBI2_WR_ER_DONE +#define INT_NAND_OP_DONE INT_EBI2_OP_DONE + +#define NR_GPIO_IRQS 181 +#define NR_MSM_IRQS 128 +#define NR_BOARD_IRQS 128 + +#endif /* __ASM_ARCH_MSM_IRQS_7X30_H */ diff --git a/arch/arm/mach-msm/include/mach/irqs-7xxx.h b/arch/arm/mach-msm/include/mach/irqs-7xxx.h index ccb13eb67bde..63fd5ed417be 100644 --- a/arch/arm/mach-msm/include/mach/irqs-7xxx.h +++ b/arch/arm/mach-msm/include/mach/irqs-7xxx.h @@ -70,5 +70,7 @@ /* 7x00A uses 122, but 7x25 has up to 132. */ #define NR_GPIO_IRQS 133 +#define NR_MSM_IRQS 64 +#define NR_BOARD_IRQS 64 #endif diff --git a/arch/arm/mach-msm/include/mach/irqs-8xxx.h b/arch/arm/mach-msm/include/mach/irqs-8xxx.h index 9cedbfeb60b8..53a732abf4d1 100644 --- a/arch/arm/mach-msm/include/mach/irqs-8xxx.h +++ b/arch/arm/mach-msm/include/mach/irqs-8xxx.h @@ -127,5 +127,7 @@ #define INT_SIRC_1 (32 + 31) #define NR_GPIO_IRQS 165 +#define NR_MSM_IRQS 64 +#define NR_BOARD_IRQS 64 #endif diff --git a/arch/arm/mach-msm/include/mach/irqs.h b/arch/arm/mach-msm/include/mach/irqs.h index ed5c12602b68..902910ad3b16 100644 --- a/arch/arm/mach-msm/include/mach/irqs.h +++ b/arch/arm/mach-msm/include/mach/irqs.h @@ -19,18 +19,19 @@ #define MSM_IRQ_BIT(irq) (1 << ((irq) & 31)) -#define NR_MSM_IRQS 64 -#define NR_BOARD_IRQS 64 - -#if defined(CONFIG_ARCH_MSM_SCORPION) +#if defined(CONFIG_ARCH_MSM7X30) +#include "irqs-7x30.h" +#elif defined(CONFIG_ARCH_QSD8X50) #include "irqs-8xxx.h" #include "sirc.h" -#else +#elif defined(CONFIG_ARCH_MSM_ARM11) #include "irqs-7xxx.h" +#else +#error "Unknown architecture specification" #endif #define NR_IRQS (NR_MSM_IRQS + NR_GPIO_IRQS + NR_BOARD_IRQS) - #define MSM_GPIO_TO_INT(n) (NR_MSM_IRQS + (n)) +#define MSM_INT_TO_REG(base, irq) (base + irq / 32) #endif diff --git a/arch/arm/mach-msm/include/mach/msm_iomap.h b/arch/arm/mach-msm/include/mach/msm_iomap.h index 60df1ef0c4a9..7a3dcebf7731 100644 --- a/arch/arm/mach-msm/include/mach/msm_iomap.h +++ b/arch/arm/mach-msm/include/mach/msm_iomap.h @@ -45,15 +45,17 @@ #endif #define MSM_VIC_BASE IOMEM(0xE0000000) -#if defined(CONFIG_ARCH_MSM_SCORPION) +#if defined(CONFIG_ARCH_QSD8X50) #define MSM_VIC_PHYS 0xAC000000 +#elif defined(CONFIG_ARCH_MSM7X30) +#define MSM_VIC_PHYS 0xC0080000 #else #define MSM_VIC_PHYS 0xC0000000 #endif #define MSM_VIC_SIZE SZ_4K #define MSM_CSR_BASE IOMEM(0xE0001000) -#if defined(CONFIG_ARCH_MSM_SCORPION) +#if defined(CONFIG_ARCH_QSD8X50) #define MSM_CSR_PHYS 0xAC100000 #else #define MSM_CSR_PHYS 0xC0100000 @@ -65,19 +67,28 @@ #define MSM_GPT_SIZE SZ_4K #define MSM_DMOV_BASE IOMEM(0xE0002000) +#if defined(CONFIG_ARCH_MSM7X30) +#define MSM_DMOV_PHYS 0xAC400000 +#else #define MSM_DMOV_PHYS 0xA9700000 +#endif #define MSM_DMOV_SIZE SZ_4K #define MSM_GPIO1_BASE IOMEM(0xE0003000) -#if defined(CONFIG_ARCH_MSM_SCORPION) +#if defined(CONFIG_ARCH_QSD8X50) #define MSM_GPIO1_PHYS 0xA9000000 +#elif defined(CONFIG_ARCH_MSM7X30) +#define MSM_GPIO1_PHYS 0xABE00000 #else #define MSM_GPIO1_PHYS 0xA9200000 #endif #define MSM_GPIO1_SIZE SZ_4K #define MSM_GPIO2_BASE IOMEM(0xE0004000) -#if defined(CONFIG_ARCH_MSM_SCORPION) + +#if defined(CONFIG_ARCH_QSD8X50) +#define MSM_GPIO2_PHYS 0xABF00000 +#elif defined(CONFIG_ARCH_MSM7X30) #define MSM_GPIO2_PHYS 0xA9100000 #else #define MSM_GPIO2_PHYS 0xA9300000 @@ -85,7 +96,11 @@ #define MSM_GPIO2_SIZE SZ_4K #define MSM_CLK_CTL_BASE IOMEM(0xE0005000) +#if defined(CONFIG_ARCH_MSM7X30) +#define MSM_CLK_CTL_PHYS 0xAB800000 +#else #define MSM_CLK_CTL_PHYS 0xA8600000 +#endif #define MSM_CLK_CTL_SIZE SZ_4K #define MSM_L2CC_BASE IOMEM(0xE0006000) @@ -100,6 +115,10 @@ #define MSM_SCPLL_PHYS 0xA8800000 #define MSM_SCPLL_SIZE SZ_4K +#define MSM_GCC_BASE IOMEM(0xE0008000) +#define MSM_GCC_PHYS 0xC0182000 +#define MSM_GCC_SIZE SZ_4K + #define MSM_SHARED_RAM_BASE IOMEM(0xE0100000) #define MSM_SHARED_RAM_SIZE SZ_1M diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c index c66d50196064..7511d6f30e92 100644 --- a/arch/arm/mach-msm/io.c +++ b/arch/arm/mach-msm/io.c @@ -89,6 +89,29 @@ static struct map_desc qsd8x50_io_desc[] __initdata = { }, }; +static struct map_desc msm7x30_io_desc[] __initdata = { + MSM_DEVICE(VIC), + MSM_DEVICE(CSR), + MSM_DEVICE(GPT), + MSM_DEVICE(DMOV), + MSM_DEVICE(GPIO1), + MSM_DEVICE(GPIO2), + MSM_DEVICE(CLK_CTL), + MSM_DEVICE(SIRC), + MSM_DEVICE(SCPLL), + MSM_DEVICE(AD5), + MSM_DEVICE(MDC), + MSM_DEVICE(GCC), +#ifdef CONFIG_MSM_DEBUG_UART + MSM_DEVICE(DEBUG_UART), +#endif + { + .virtual = (unsigned long) MSM_SHARED_RAM_BASE, + .length = MSM_SHARED_RAM_SIZE, + .type = MT_DEVICE, + }, +}; + static struct map_desc comet_io_desc[] __initdata = { MSM_DEVICE(VIC), MSM_DEVICE(CSR), @@ -145,6 +168,20 @@ void __init msm_map_qsd8x50_io(void) iotable_init(qsd8x50_io_desc, ARRAY_SIZE(qsd8x50_io_desc)); } +void __init msm_map_msm7x30_io(void) +{ + int i; + + BUG_ON(!ARRAY_SIZE(msm7x30_io_desc)); + for (i = 0; i < ARRAY_SIZE(msm7x30_io_desc); i++) + if (msm7x30_io_desc[i].virtual == + (unsigned long)MSM_SHARED_RAM_BASE) + msm7x30_io_desc[i].pfn = + __phys_to_pfn(msm_shared_ram_phys); + + iotable_init(msm7x30_io_desc, ARRAY_SIZE(msm7x30_io_desc)); +} + void __init msm_map_comet_io(void) { int i; diff --git a/arch/arm/mach-msm/irq.c b/arch/arm/mach-msm/irq.c index 8a33e21b2d02..51861e4db582 100644 --- a/arch/arm/mach-msm/irq.c +++ b/arch/arm/mach-msm/irq.c @@ -43,19 +43,33 @@ static int msm_irq_debug_mask; module_param_named(debug_mask, msm_irq_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP); #define VIC_REG(off) (MSM_VIC_BASE + (off)) +#define VIC_INT_TO_REG_ADDR(base, irq) (base + (irq / 32) * 4) +#define VIC_INT_TO_REG_INDEX(irq) ((irq >> 5) & 3) #define VIC_INT_SELECT0 VIC_REG(0x0000) /* 1: FIQ, 0: IRQ */ #define VIC_INT_SELECT1 VIC_REG(0x0004) /* 1: FIQ, 0: IRQ */ +#define VIC_INT_SELECT2 VIC_REG(0x0008) /* 1: FIQ, 0: IRQ */ +#define VIC_INT_SELECT3 VIC_REG(0x000C) /* 1: FIQ, 0: IRQ */ #define VIC_INT_EN0 VIC_REG(0x0010) #define VIC_INT_EN1 VIC_REG(0x0014) +#define VIC_INT_EN2 VIC_REG(0x0018) +#define VIC_INT_EN3 VIC_REG(0x001C) #define VIC_INT_ENCLEAR0 VIC_REG(0x0020) #define VIC_INT_ENCLEAR1 VIC_REG(0x0024) +#define VIC_INT_ENCLEAR2 VIC_REG(0x0028) +#define VIC_INT_ENCLEAR3 VIC_REG(0x002C) #define VIC_INT_ENSET0 VIC_REG(0x0030) #define VIC_INT_ENSET1 VIC_REG(0x0034) +#define VIC_INT_ENSET2 VIC_REG(0x0038) +#define VIC_INT_ENSET3 VIC_REG(0x003C) #define VIC_INT_TYPE0 VIC_REG(0x0040) /* 1: EDGE, 0: LEVEL */ #define VIC_INT_TYPE1 VIC_REG(0x0044) /* 1: EDGE, 0: LEVEL */ +#define VIC_INT_TYPE2 VIC_REG(0x0048) /* 1: EDGE, 0: LEVEL */ +#define VIC_INT_TYPE3 VIC_REG(0x004C) /* 1: EDGE, 0: LEVEL */ #define VIC_INT_POLARITY0 VIC_REG(0x0050) /* 1: NEG, 0: POS */ #define VIC_INT_POLARITY1 VIC_REG(0x0054) /* 1: NEG, 0: POS */ +#define VIC_INT_POLARITY2 VIC_REG(0x0058) /* 1: NEG, 0: POS */ +#define VIC_INT_POLARITY3 VIC_REG(0x005C) /* 1: NEG, 0: POS */ #define VIC_NO_PEND_VAL VIC_REG(0x0060) #if defined(CONFIG_ARCH_MSM_SCORPION) @@ -70,14 +84,24 @@ module_param_named(debug_mask, msm_irq_debug_mask, int, S_IRUGO | S_IWUSR | S_IW #define VIC_IRQ_STATUS0 VIC_REG(0x0080) #define VIC_IRQ_STATUS1 VIC_REG(0x0084) +#define VIC_IRQ_STATUS2 VIC_REG(0x0088) +#define VIC_IRQ_STATUS3 VIC_REG(0x008C) #define VIC_FIQ_STATUS0 VIC_REG(0x0090) #define VIC_FIQ_STATUS1 VIC_REG(0x0094) +#define VIC_FIQ_STATUS2 VIC_REG(0x0098) +#define VIC_FIQ_STATUS3 VIC_REG(0x009C) #define VIC_RAW_STATUS0 VIC_REG(0x00A0) #define VIC_RAW_STATUS1 VIC_REG(0x00A4) +#define VIC_RAW_STATUS2 VIC_REG(0x00A8) +#define VIC_RAW_STATUS3 VIC_REG(0x00AC) #define VIC_INT_CLEAR0 VIC_REG(0x00B0) #define VIC_INT_CLEAR1 VIC_REG(0x00B4) +#define VIC_INT_CLEAR2 VIC_REG(0x00B8) +#define VIC_INT_CLEAR3 VIC_REG(0x00BC) #define VIC_SOFTINT0 VIC_REG(0x00C0) #define VIC_SOFTINT1 VIC_REG(0x00C4) +#define VIC_SOFTINT2 VIC_REG(0x00C8) +#define VIC_SOFTINT3 VIC_REG(0x00CC) #define VIC_IRQ_VEC_RD VIC_REG(0x00D0) /* pending int # */ #define VIC_IRQ_VEC_PEND_RD VIC_REG(0x00D4) /* pending vector addr */ #define VIC_IRQ_VEC_WR VIC_REG(0x00D8) @@ -101,14 +125,40 @@ module_param_named(debug_mask, msm_irq_debug_mask, int, S_IRUGO | S_IWUSR | S_IW #define VIC_VECTPRIORITY(n) VIC_REG(0x0200+((n) * 4)) #define VIC_VECTADDR(n) VIC_REG(0x0400+((n) * 4)) +#if defined(CONFIG_ARCH_MSM7X30) +#define VIC_NUM_REGS 4 +#else +#define VIC_NUM_REGS 2 +#endif + +#if VIC_NUM_REGS == 2 +#define DPRINT_REGS(base_reg, format, ...) \ + printk(KERN_INFO format " %x %x\n", ##__VA_ARGS__, \ + readl(base_reg ## 0), readl(base_reg ## 1)) +#define DPRINT_ARRAY(array, format, ...) \ + printk(KERN_INFO format " %x %x\n", ##__VA_ARGS__, \ + array[0], array[1]) +#elif VIC_NUM_REGS == 4 +#define DPRINT_REGS(base_reg, format, ...) \ + printk(KERN_INFO format " %x %x %x %x\n", ##__VA_ARGS__, \ + readl(base_reg ## 0), readl(base_reg ## 1), \ + readl(base_reg ## 2), readl(base_reg ## 3)) +#define DPRINT_ARRAY(array, format, ...) \ + printk(KERN_INFO format " %x %x %x %x\n", ##__VA_ARGS__, \ + array[0], array[1], \ + array[2], array[3]) +#else +#error "VIC_NUM_REGS set to illegal value" +#endif + static uint32_t msm_irq_smsm_wake_enable[2]; static struct { uint32_t int_en[2]; uint32_t int_type; uint32_t int_polarity; uint32_t int_select; -} msm_irq_shadow_reg[2]; -static uint32_t msm_irq_idle_disable[2]; +} msm_irq_shadow_reg[VIC_NUM_REGS]; +static uint32_t msm_irq_idle_disable[VIC_NUM_REGS]; #define SMSM_FAKE_IRQ (0xff) static uint8_t msm_irq_to_smsm[NR_IRQS] = { @@ -135,7 +185,9 @@ static uint8_t msm_irq_to_smsm[NR_IRQS] = { [INT_UART1DM_IRQ] = 17, [INT_UART1DM_RX] = 18, [INT_KEYSENSE] = 19, +#if !defined(CONFIG_ARCH_MSM7X30) [INT_AD_HSSD] = 20, +#endif [INT_NAND_WR_ER_DONE] = 21, [INT_NAND_OP_DONE] = 22, @@ -161,23 +213,31 @@ static uint8_t msm_irq_to_smsm[NR_IRQS] = { [INT_GP_TIMER_EXP] = SMSM_FAKE_IRQ, [INT_DEBUG_TIMER_EXP] = SMSM_FAKE_IRQ, [INT_ADSP_A11] = SMSM_FAKE_IRQ, -#if defined(CONFIG_ARCH_MSM_SCORPION) +#ifdef CONFIG_ARCH_QSD8X50 [INT_SIRC_0] = SMSM_FAKE_IRQ, [INT_SIRC_1] = SMSM_FAKE_IRQ, #endif }; +static inline void msm_irq_write_all_regs(void __iomem *base, unsigned int val) +{ + int i; + + for (i = 0; i < VIC_NUM_REGS; i++) + writel(val, base + (i * 4)); +} + static void msm_irq_ack(unsigned int irq) { - void __iomem *reg = VIC_INT_CLEAR0 + ((irq & 32) ? 4 : 0); + void __iomem *reg = VIC_INT_TO_REG_ADDR(VIC_INT_CLEAR0, irq); irq = 1 << (irq & 31); writel(irq, reg); } static void msm_irq_mask(unsigned int irq) { - void __iomem *reg = VIC_INT_ENCLEAR0 + ((irq & 32) ? 4 : 0); - unsigned index = (irq >> 5) & 1; + void __iomem *reg = VIC_INT_TO_REG_ADDR(VIC_INT_ENCLEAR0, irq); + unsigned index = VIC_INT_TO_REG_INDEX(irq); uint32_t mask = 1UL << (irq & 31); int smsm_irq = msm_irq_to_smsm[irq]; @@ -193,8 +253,8 @@ static void msm_irq_mask(unsigned int irq) static void msm_irq_unmask(unsigned int irq) { - void __iomem *reg = VIC_INT_ENSET0 + ((irq & 32) ? 4 : 0); - unsigned index = (irq >> 5) & 1; + void __iomem *reg = VIC_INT_TO_REG_ADDR(VIC_INT_ENSET0, irq); + unsigned index = VIC_INT_TO_REG_INDEX(irq); uint32_t mask = 1UL << (irq & 31); int smsm_irq = msm_irq_to_smsm[irq]; @@ -211,7 +271,7 @@ static void msm_irq_unmask(unsigned int irq) static int msm_irq_set_wake(unsigned int irq, unsigned int on) { - unsigned index = (irq >> 5) & 1; + unsigned index = VIC_INT_TO_REG_INDEX(irq); uint32_t mask = 1UL << (irq & 31); int smsm_irq = msm_irq_to_smsm[irq]; @@ -237,9 +297,9 @@ static int msm_irq_set_wake(unsigned int irq, unsigned int on) static int msm_irq_set_type(unsigned int irq, unsigned int flow_type) { - void __iomem *treg = VIC_INT_TYPE0 + ((irq & 32) ? 4 : 0); - void __iomem *preg = VIC_INT_POLARITY0 + ((irq & 32) ? 4 : 0); - unsigned index = (irq >> 5) & 1; + void __iomem *treg = VIC_INT_TO_REG_ADDR(VIC_INT_TYPE0, irq); + void __iomem *preg = VIC_INT_TO_REG_ADDR(VIC_INT_POLARITY0, irq); + unsigned index = VIC_INT_TO_REG_INDEX(irq); int b = 1 << (irq & 31); uint32_t polarity; uint32_t type; @@ -266,26 +326,37 @@ static int msm_irq_set_type(unsigned int irq, unsigned int flow_type) return 0; } -int msm_irq_pending(void) +unsigned int msm_irq_pending(void) { - return readl(VIC_IRQ_STATUS0) || readl(VIC_IRQ_STATUS1); + unsigned int i, pending = 0; + + for (i = 0; (i < VIC_NUM_REGS) && !pending; i++) + pending |= readl(VIC_IRQ_STATUS0 + (i * 4)); + + return pending; } int msm_irq_idle_sleep_allowed(void) { + uint32_t i, disable = 0; + if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP_REQUEST) - printk(KERN_INFO "msm_irq_idle_sleep_allowed: disable %x %x\n", - msm_irq_idle_disable[0], msm_irq_idle_disable[1]); - return !(msm_irq_idle_disable[0] || msm_irq_idle_disable[1]); + DPRINT_ARRAY(msm_irq_idle_disable, + "msm_irq_idle_sleep_allowed: disable"); + + for (i = 0; i < VIC_NUM_REGS; i++) + disable |= msm_irq_idle_disable[i]; + + return !disable; } /* * Prepare interrupt subsystem for entering sleep -- phase 1. - * If arm9_wake is true, return currently enabled interrupts in *irq_mask. + * If modem_wake is true, return currently enabled interrupts in *irq_mask. */ -void msm_irq_enter_sleep1(bool arm9_wake, int from_idle, uint32_t *irq_mask) +void msm_irq_enter_sleep1(bool modem_wake, int from_idle, uint32_t *irq_mask) { - if (arm9_wake) { + if (modem_wake) { *irq_mask = msm_irq_smsm_wake_enable[!from_idle]; if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP) printk(KERN_INFO @@ -302,37 +373,38 @@ void msm_irq_enter_sleep1(bool arm9_wake, int from_idle, uint32_t *irq_mask) * is not changed. * 0: success */ -int msm_irq_enter_sleep2(bool arm9_wake, int from_idle) +int msm_irq_enter_sleep2(bool modem_wake, int from_idle) { - int limit = 10; - uint32_t pending0, pending1; + int i, limit = 10; + uint32_t pending[VIC_NUM_REGS]; - if (from_idle && !arm9_wake) + if (from_idle && !modem_wake) return 0; /* edge triggered interrupt may get lost if this mode is used */ - WARN_ON_ONCE(!arm9_wake && !from_idle); + WARN_ON_ONCE(!modem_wake && !from_idle); if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP) - printk(KERN_INFO "%s change irq, pend %x %x\n", __func__, - readl(VIC_IRQ_STATUS0), readl(VIC_IRQ_STATUS1)); + DPRINT_REGS(VIC_IRQ_STATUS, "%s change irq, pend", __func__); + + for (i = 0; i < VIC_NUM_REGS; i++) { + pending[i] = readl(VIC_IRQ_STATUS0 + (i * 4)); + pending[i] &= msm_irq_shadow_reg[i].int_en[!from_idle]; + } - pending0 = readl(VIC_IRQ_STATUS0); - pending1 = readl(VIC_IRQ_STATUS1); - pending0 &= msm_irq_shadow_reg[0].int_en[!from_idle]; /* Clear INT_A9_M2A_5 since requesting sleep triggers it */ - pending0 &= ~(1U << INT_A9_M2A_5); - pending1 &= msm_irq_shadow_reg[1].int_en[!from_idle]; - - if (pending0 || pending1) { - if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP_ABORT) - printk(KERN_INFO "%s abort %x %x\n", __func__, - pending0, pending1); - return -EAGAIN; + pending[0] &= ~(1U << INT_A9_M2A_5); + + for (i = 0; i < VIC_NUM_REGS; i++) { + if (pending[i]) + if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP_ABORT) { + DPRINT_ARRAY(pending, "%s abort", + __func__); + return -EAGAIN; + } } - writel(0, VIC_INT_EN0); - writel(0, VIC_INT_EN1); + msm_irq_write_all_regs(VIC_INT_EN0, 0); while (limit-- > 0) { int pend_irq; @@ -345,12 +417,13 @@ int msm_irq_enter_sleep2(bool arm9_wake, int from_idle) __func__, irq, pend_irq); } - if (arm9_wake) { + if (modem_wake) { msm_irq_set_type(INT_A9_M2A_6, IRQF_TRIGGER_RISING); writel(1U << INT_A9_M2A_6, VIC_INT_ENSET0); } else { - writel(msm_irq_shadow_reg[0].int_en[1], VIC_INT_ENSET0); - writel(msm_irq_shadow_reg[1].int_en[1], VIC_INT_ENSET1); + for (i = 0; i < VIC_NUM_REGS; i++) + writel(msm_irq_shadow_reg[i].int_en[1], + VIC_INT_ENSET0 + (i * 4)); } return 0; @@ -367,7 +440,7 @@ void msm_irq_exit_sleep1(uint32_t irq_mask, uint32_t wakeup_reason, msm_irq_ack(INT_A9_M2A_6); - for (i = 0; i < 2; i++) { + for (i = 0; i < NR_MSM_IRQS; i++) { writel(msm_irq_shadow_reg[i].int_type, VIC_INT_TYPE0 + i * 4); writel(msm_irq_shadow_reg[i].int_polarity, @@ -381,9 +454,8 @@ void msm_irq_exit_sleep1(uint32_t irq_mask, uint32_t wakeup_reason, writel(3, VIC_INT_MASTEREN); if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP) - printk(KERN_INFO "%s %x %x %x now %x %x\n", - __func__, irq_mask, pending_irqs, wakeup_reason, - readl(VIC_IRQ_STATUS0), readl(VIC_IRQ_STATUS1)); + DPRINT_REGS(VIC_IRQ_STATUS, "%s %x %x %x now", + __func__, irq_mask, pending_irqs, wakeup_reason); } /* @@ -396,12 +468,11 @@ void msm_irq_exit_sleep2(uint32_t irq_mask, uint32_t wakeup_reason, int i; if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP) - printk(KERN_INFO "%s %x %x %x now %x %x\n", - __func__, irq_mask, pending, wakeup_reason, - readl(VIC_IRQ_STATUS0), readl(VIC_IRQ_STATUS1)); + DPRINT_REGS(VIC_IRQ_STATUS, "%s %x %x %x now", + __func__, irq_mask, pending, wakeup_reason); for (i = 0; pending && i < ARRAY_SIZE(msm_irq_to_smsm); i++) { - unsigned reg_offset = (i & 32) ? 4 : 0; + unsigned reg_offset = VIC_INT_TO_REG_ADDR(0, i); uint32_t reg_mask = 1UL << (i & 31); int smsm_irq = msm_irq_to_smsm[i]; uint32_t smsm_mask; @@ -415,11 +486,9 @@ void msm_irq_exit_sleep2(uint32_t irq_mask, uint32_t wakeup_reason, pending &= ~smsm_mask; if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP_INT) - printk(KERN_INFO - "%s: irq %d still pending %x now %x %x\n", - __func__, i, pending, - readl(VIC_IRQ_STATUS0), - readl(VIC_IRQ_STATUS1)); + DPRINT_REGS(VIC_IRQ_STATUS, + "%s: irq %d still pending %x now", + __func__, i, pending); #if 0 /* debug intetrrupt trigger */ if (readl(VIC_IRQ_STATUS0 + reg_offset) & reg_mask) writel(reg_mask, VIC_INT_CLEAR0 + reg_offset); @@ -430,11 +499,9 @@ void msm_irq_exit_sleep2(uint32_t irq_mask, uint32_t wakeup_reason, writel(reg_mask, VIC_SOFTINT0 + reg_offset); if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP_INT_TRIGGER) - printk(KERN_INFO - "%s: irq %d need trigger, now %x %x\n", - __func__, i, - readl(VIC_IRQ_STATUS0), - readl(VIC_IRQ_STATUS1)); + DPRINT_REGS(VIC_IRQ_STATUS, + "%s: irq %d need trigger, now", + __func__, i); } } @@ -446,9 +513,8 @@ void msm_irq_exit_sleep3(uint32_t irq_mask, uint32_t wakeup_reason, uint32_t pending_irqs) { if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP) - printk(KERN_INFO "%s %x %x %x now %x %x state %x\n", + DPRINT_REGS(VIC_IRQ_STATUS, "%s %x %x %x state %x now", __func__, irq_mask, pending_irqs, wakeup_reason, - readl(VIC_IRQ_STATUS0), readl(VIC_IRQ_STATUS1), smsm_get_state(SMSM_MODEM_STATE)); } @@ -467,22 +533,18 @@ void __init msm_init_irq(void) unsigned n; /* select level interrupts */ - writel(0, VIC_INT_TYPE0); - writel(0, VIC_INT_TYPE1); + msm_irq_write_all_regs(VIC_INT_TYPE0, 0); /* select highlevel interrupts */ - writel(0, VIC_INT_POLARITY0); - writel(0, VIC_INT_POLARITY1); + msm_irq_write_all_regs(VIC_INT_POLARITY0, 0); /* select IRQ for all INTs */ - writel(0, VIC_INT_SELECT0); - writel(0, VIC_INT_SELECT1); + msm_irq_write_all_regs(VIC_INT_SELECT0, 0); /* disable all INTs */ - writel(0, VIC_INT_EN0); - writel(0, VIC_INT_EN1); + msm_irq_write_all_regs(VIC_INT_EN0, 0); - /* don't use 1136 vic */ + /* don't use vic */ writel(0, VIC_CONFIG); /* enable interrupt controller */ @@ -498,7 +560,7 @@ void __init msm_init_irq(void) #if defined(CONFIG_MSM_FIQ_SUPPORT) void msm_trigger_irq(int irq) { - void __iomem *reg = VIC_SOFTINT0 + ((irq & 32) ? 4 : 0); + void __iomem *reg = VIC_INT_TO_REG_ADDR(VIC_SOFTINT0, irq); uint32_t mask = 1UL << (irq & 31); writel(mask, reg); } @@ -521,8 +583,8 @@ void msm_fiq_disable(int irq) void msm_fiq_select(int irq) { - void __iomem *reg = VIC_INT_SELECT0 + ((irq & 32) ? 4 : 0); - unsigned index = (irq >> 5) & 1; + void __iomem *reg = VIC_INT_TO_REG_ADDR(VIC_INT_SELECT0, irq); + unsigned index = VIC_INT_TO_REG_INDEX(irq); uint32_t mask = 1UL << (irq & 31); unsigned long flags; @@ -534,8 +596,8 @@ void msm_fiq_select(int irq) void msm_fiq_unselect(int irq) { - void __iomem *reg = VIC_INT_SELECT0 + ((irq & 32) ? 4 : 0); - unsigned index = (irq >> 5) & 1; + void __iomem *reg = VIC_INT_TO_REG_ADDR(VIC_INT_SELECT0, irq); + unsigned index = VIC_INT_TO_REG_INDEX(irq); uint32_t mask = 1UL << (irq & 31); unsigned long flags; diff --git a/arch/arm/mach-msm/irq.h b/arch/arm/mach-msm/irq.h index 40028485cc7c..2e1f68bd3d9a 100644 --- a/arch/arm/mach-msm/irq.h +++ b/arch/arm/mach-msm/irq.h @@ -59,7 +59,7 @@ #define _ARCH_ARM_MACH_MSM_IRQ_H_ int msm_irq_idle_sleep_allowed(void); -int msm_irq_pending(void); +unsigned int msm_irq_pending(void); void msm_irq_enter_sleep1(bool arm9_wake, int from_idle, uint32_t *irq_mask); int msm_irq_enter_sleep2(bool arm9_wake, int from_idle); void msm_irq_exit_sleep1 diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c index 341a4ecb08dc..fdbad01556bf 100644 --- a/arch/arm/mach-msm/timer.c +++ b/arch/arm/mach-msm/timer.c @@ -35,18 +35,26 @@ enum { static int msm_timer_debug_mask; module_param_named(debug_mask, msm_timer_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP); +#if defined(CONFIG_ARCH_MSM7X30) +#define MSM_DGT_BASE (MSM_GPT_BASE + 0x24) +#define MSM_DGT_SHIFT (5) + +#define TIMER_MATCH_VAL 0x0004 +#define TIMER_COUNT_VAL 0x0008 +#define TIMER_ENABLE 0x000C +#define TIMER_ENABLE_EN 1 + +#else + #define MSM_DGT_BASE (MSM_GPT_BASE + 0x10) #define MSM_DGT_SHIFT (5) #define TIMER_MATCH_VAL 0x0000 #define TIMER_COUNT_VAL 0x0004 #define TIMER_ENABLE 0x0008 -#define TIMER_ENABLE_CLR_ON_MATCH_EN 2 -#define TIMER_ENABLE_EN 1 -#define TIMER_CLEAR 0x000C +#define TIMER_ENABLE_EN 1 -#define CSR_PROTECTION 0x0020 -#define CSR_PROTECTION_EN 1 +#endif #define GPT_HZ 32768 #if defined(CONFIG_ARCH_MSM_SCORPION) -- cgit v1.2.3 From 4a292d17330975d13666c34f2fad19cc3ee829e9 Mon Sep 17 00:00:00 2001 From: Michael Bohan Date: Sun, 14 Jun 2009 18:43:40 -0700 Subject: [ARM] msm: Fix GPIO2 base address for ARCH_QSD8X50 The respective MSM_GPIO2_PHYS values for QSD8X50 and MSM7X30 are confused with each other. Signed-off-by: Michael Bohan --- arch/arm/mach-msm/include/mach/msm_iomap.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/include/mach/msm_iomap.h b/arch/arm/mach-msm/include/mach/msm_iomap.h index 7a3dcebf7731..a8a4051118b3 100644 --- a/arch/arm/mach-msm/include/mach/msm_iomap.h +++ b/arch/arm/mach-msm/include/mach/msm_iomap.h @@ -86,9 +86,9 @@ #define MSM_GPIO2_BASE IOMEM(0xE0004000) -#if defined(CONFIG_ARCH_QSD8X50) +#if defined(CONFIG_ARCH_MSM7X30) #define MSM_GPIO2_PHYS 0xABF00000 -#elif defined(CONFIG_ARCH_MSM7X30) +#elif defined(CONFIG_ARCH_QSD8X50) #define MSM_GPIO2_PHYS 0xA9100000 #else #define MSM_GPIO2_PHYS 0xA9300000 -- cgit v1.2.3 From d7a57be85e4bddb1f49f17836ff4f1d41bda29ee Mon Sep 17 00:00:00 2001 From: Michael Bohan Date: Tue, 16 Jun 2009 16:35:57 -0700 Subject: [ARM] msm: irq: Fix incorrect bounds checking The current code is clobbering several hundred bytes of memory. Signed-off-by: Michael Bohan --- arch/arm/mach-msm/irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/irq.c b/arch/arm/mach-msm/irq.c index 51861e4db582..add31d4d7a2b 100644 --- a/arch/arm/mach-msm/irq.c +++ b/arch/arm/mach-msm/irq.c @@ -440,7 +440,7 @@ void msm_irq_exit_sleep1(uint32_t irq_mask, uint32_t wakeup_reason, msm_irq_ack(INT_A9_M2A_6); - for (i = 0; i < NR_MSM_IRQS; i++) { + for (i = 0; i < VIC_NUM_REGS; i++) { writel(msm_irq_shadow_reg[i].int_type, VIC_INT_TYPE0 + i * 4); writel(msm_irq_shadow_reg[i].int_polarity, -- cgit v1.2.3 From d1f33d7c73d971ad3eefbf0f6b072f59adc37923 Mon Sep 17 00:00:00 2001 From: Praveen Chidambaram Date: Tue, 9 Jun 2009 12:24:42 -0600 Subject: [ARM] msm: svs: Make PMIC_DEFAULT_DCDC1 configurable Signed-off-by: Praveen Chidambaram --- arch/arm/mach-msm/Kconfig | 7 +++++++ arch/arm/mach-msm/board-comet.c | 8 +++----- arch/arm/mach-msm/board-qsd8x50.c | 8 +++----- 3 files changed, 13 insertions(+), 10 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index 265e76d47de2..d1fe69b08aa3 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -340,6 +340,13 @@ config QSD_SVS help Enables static voltage scaling using the TPS65023 PMIC. +config QSD_PMIC_DEFAULT_DCDC1 + int "PMIC default output voltage" + depends on (MACH_QSD8X50_SURF || MACH_QSD8X50_FFA || MACH_QSD8X50_COMET) + default 1250 + help + This is the PMIC voltage at Linux kernel boot. + config MSM_FIQ_SUPPORT default y bool "Enable installation of an FIQ handler." diff --git a/arch/arm/mach-msm/board-comet.c b/arch/arm/mach-msm/board-comet.c index cfc8cd2f2cd2..ed60f274a992 100644 --- a/arch/arm/mach-msm/board-comet.c +++ b/arch/arm/mach-msm/board-comet.c @@ -626,12 +626,10 @@ static struct platform_device *devices[] __initdata = { &msm_device_tssc, }; -/* The TPS65023 PMIC outputs 1.225V as default at boot */ -#define TPS65023_DEFAULT_DCDC1 1225 #ifdef CONFIG_QSD_SVS #define TPS65023_MAX_DCDC1 1600 #else -#define TPS65023_MAX_DCDC1 TPS65023_DEFAULT_DCDC1 +#define TPS65023_MAX_DCDC1 CONFIG_QSD_PMIC_DEFAULT_DCDC1 #endif static int qsd8x50_tps65023_set_dcdc1(int mVolts) @@ -643,13 +641,13 @@ static int qsd8x50_tps65023_set_dcdc1(int mVolts) * So we can safely switch to any frequency within this * voltage even if the device is not probed/ready. */ - if (rc == -ENODEV && mVolts <= TPS65023_DEFAULT_DCDC1) + if (rc == -ENODEV && mVolts <= CONFIG_QSD_PMIC_DEFAULT_DCDC1) rc = 0; #else /* Disallow frequencies not supported in the default PMIC * output voltage. */ - if (mVolts > TPS65023_DEFAULT_DCDC1) + if (mVolts > CONFIG_QSD_PMIC_DEFAULT_DCDC1) rc = -EFAULT; #endif return rc; diff --git a/arch/arm/mach-msm/board-qsd8x50.c b/arch/arm/mach-msm/board-qsd8x50.c index 7997fdd54eb6..6e2ba4b18d76 100644 --- a/arch/arm/mach-msm/board-qsd8x50.c +++ b/arch/arm/mach-msm/board-qsd8x50.c @@ -739,12 +739,10 @@ static struct platform_device *devices[] __initdata = { &msm_device_kgsl, }; -/* The TPS65023 PMIC outputs 1.225V as default at boot */ -#define TPS65023_DEFAULT_DCDC1 1225 #ifdef CONFIG_QSD_SVS #define TPS65023_MAX_DCDC1 1600 #else -#define TPS65023_MAX_DCDC1 TPS65023_DEFAULT_DCDC1 +#define TPS65023_MAX_DCDC1 CONFIG_QSD_PMIC_DEFAULT_DCDC1 #endif static int qsd8x50_tps65023_set_dcdc1(int mVolts) @@ -756,13 +754,13 @@ static int qsd8x50_tps65023_set_dcdc1(int mVolts) * So we can safely switch to any frequency within this * voltage even if the device is not probed/ready. */ - if (rc == -ENODEV && mVolts <= TPS65023_DEFAULT_DCDC1) + if (rc == -ENODEV && mVolts <= CONFIG_QSD_PMIC_DEFAULT_DCDC1) rc = 0; #else /* Disallow frequencies not supported in the default PMIC * output voltage. */ - if (mVolts > TPS65023_DEFAULT_DCDC1) + if (mVolts > CONFIG_QSD_PMIC_DEFAULT_DCDC1) rc = -EFAULT; #endif return rc; -- cgit v1.2.3 From 10114915eac86588bf9866d74f4269c4a5508be9 Mon Sep 17 00:00:00 2001 From: Zach Pfeffer Date: Tue, 16 Jun 2009 22:37:17 -0600 Subject: [ARM] msm: smd_ctl2: Use per-inst buf and inc tx/rx buf size from 1k to 2k The unused rx_buf associated with each smd_ctl2 instance is now used instead of a stack allocated buffer in the read. In addition to using a per-instance buffer each smd_ctl2 port's transmit and a receive buffer's size has been increased. It is an error to read or write more than this limit. Signed-off-by: Zach Pfeffer --- arch/arm/mach-msm/smd_ctl2.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/smd_ctl2.c b/arch/arm/mach-msm/smd_ctl2.c index 109a02f93d55..0b9668068256 100644 --- a/arch/arm/mach-msm/smd_ctl2.c +++ b/arch/arm/mach-msm/smd_ctl2.c @@ -76,7 +76,7 @@ #define NUM_SMD_CTL_PORTS 3 #define DEVICE_NAME "smdcntl" -#define MAX_BUF_SIZE 1024 +#define MAX_BUF_SIZE 2048 struct smd_ctl_dev { struct cdev cdev; @@ -207,7 +207,6 @@ ssize_t smd_ctl_read(struct file *file, size_t count, loff_t *ppos) { - unsigned char read_buf[MAX_BUF_SIZE]; int r; int bytes_read; struct smd_ctl_dev *smd_ctl_devp; @@ -271,7 +270,7 @@ ssize_t smd_ctl_read(struct file *file, } /* smd_read and copy_to_user need to be merged to only do 1 copy */ - if (smd_read(smd_ctl_devp->ctl_ch, read_buf, bytes_read) + if (smd_read(smd_ctl_devp->ctl_ch, smd_ctl_devp->rx_buf, bytes_read) != bytes_read) { if (smd_ctl_devp->has_reset) return -ENETRESET; @@ -279,8 +278,8 @@ ssize_t smd_ctl_read(struct file *file, printk(KERN_ERR "user read: not enough data?!\n"); return -EINVAL; } - D_DUMP_BUFFER("read: ", bytes_read, read_buf); - r = copy_to_user(buf, read_buf, bytes_read); + D_DUMP_BUFFER("read: ", bytes_read, smd_ctl_devp->rx_buf); + r = copy_to_user(buf, smd_ctl_devp->rx_buf, bytes_read); if (r > 0) { printk(KERN_ERR "ERROR:%s:%i:%s: " -- cgit v1.2.3 From 5ffbb133973108ee27e737d3acddb85900405530 Mon Sep 17 00:00:00 2001 From: Michael Bohan Date: Wed, 17 Jun 2009 16:20:36 -0700 Subject: [ARM] msm: smd: Add support for msm7x30 msm7x30 uses a bit offset into a single register to interrupt the modem processor. Signed-off-by: Michael Bohan --- arch/arm/mach-msm/smd.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c index 609a7f19893c..3dd65db80276 100644 --- a/arch/arm/mach-msm/smd.c +++ b/arch/arm/mach-msm/smd.c @@ -81,7 +81,11 @@ static unsigned last_heap_free = 0xffffffff; #define D(x...) do {} while (0) #endif -#define MSM_A2M_INT(n) (MSM_CSR_BASE + 0x400 + (n) * 4) +#if defined(CONFIG_ARCH_MSM7X30) +#define MSM_TRIG_A2M_INT(n) (writel(1 << n, MSM_GCC_BASE + 0x8)) +#else +#define MSM_TRIG_A2M_INT(n) (writel(1, MSM_CSR_BASE + 0x400 + (n) * 4)) +#endif static void notify_other_smsm(uint32_t smsm_entry, uint32_t old_val, uint32_t new_val) @@ -98,7 +102,7 @@ static void notify_other_smsm(uint32_t smsm_entry, if (!smsm_intr_mask || (smsm_intr_mask[smsm_entry * SMSM_NUM_HOSTS + SMSM_MODEM] & (old_val ^ new_val))) - writel(1, MSM_A2M_INT(5)); + MSM_TRIG_A2M_INT(5); if (smsm_intr_mask && (smsm_intr_mask[smsm_entry * SMSM_NUM_HOSTS + SMSM_Q6_I] & @@ -109,16 +113,16 @@ static void notify_other_smsm(uint32_t smsm_entry, if (smsm_intr_mux) smsm_intr_mux[SMEM_APPS_Q6_SMSM]++; - writel(1, MSM_A2M_INT(8)); + MSM_TRIG_A2M_INT(8); } } static inline void notify_other_smd(uint32_t ch_type) { if (ch_type == SMD_APPS_MODEM) - writel(1, MSM_A2M_INT(0)); + MSM_TRIG_A2M_INT(0); else if (ch_type == SMD_APPS_QDSP_I) - writel(1, MSM_A2M_INT(8)); + MSM_TRIG_A2M_INT(8); } void smd_diag(void) -- cgit v1.2.3 From 73f09a3533c074b7e62d9a596ecc7248049374e7 Mon Sep 17 00:00:00 2001 From: Michael Bohan Date: Wed, 17 Jun 2009 16:39:16 -0700 Subject: [ARM] msm: smd: Add error checking to smem_find calls It's better to get a warning message than a NULL pointer dereference. Signed-off-by: Michael Bohan --- arch/arm/mach-msm/smd.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c index 3dd65db80276..cf82470cd765 100644 --- a/arch/arm/mach-msm/smd.c +++ b/arch/arm/mach-msm/smd.c @@ -273,6 +273,8 @@ static void smd_channel_probe_worker(struct work_struct *work) shared = smem_find(ID_CH_ALLOC_TBL, sizeof(*shared) * 64); + BUG_ON(!shared); + for (n = 0; n < 64; n++) { if (smd_ch_allocated[n]) continue; @@ -1700,6 +1702,8 @@ static int debug_read_alloc_tbl(char *buf, int max) shared = smem_find(ID_CH_ALLOC_TBL, sizeof(struct smd_alloc_elm[64])); + BUG_ON(!shared); + for (n = 0; n < 64; n++) { i += scnprintf(buf + i, max - i, "name=%s cid=%d ch type=%d " -- cgit v1.2.3 From 4e8d0d0a4c208101dc60d3e7abf620c097ac3c7e Mon Sep 17 00:00:00 2001 From: Michael Bohan Date: Mon, 22 Jun 2009 12:15:22 -0700 Subject: [ARM] msm: proc_comm: Add support for msm7x30 msm7x30 uses a bit offset into a single register to interrupt the modem processor. Signed-off-by: Michael Bohan --- arch/arm/mach-msm/proc_comm.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/proc_comm.c b/arch/arm/mach-msm/proc_comm.c index d5d498d000fb..937e59b46dfe 100644 --- a/arch/arm/mach-msm/proc_comm.c +++ b/arch/arm/mach-msm/proc_comm.c @@ -25,11 +25,15 @@ #include "proc_comm.h" -#define MSM_A2M_INT(n) (MSM_CSR_BASE + 0x400 + (n) * 4) +#if defined(CONFIG_ARCH_MSM7X30) +#define MSM_TRIG_A2M_INT(n) (writel(1 << n, MSM_GCC_BASE + 0x8)) +#else +#define MSM_TRIG_A2M_INT(n) (writel(1, MSM_CSR_BASE + 0x400 + (n) * 4)) +#endif static inline void notify_other_proc_comm(void) { - writel(1, MSM_A2M_INT(6)); + MSM_TRIG_A2M_INT(6); } #define APP_COMMAND 0x00 -- cgit v1.2.3 From 878bc14759bd86f5f444d5d0dd90822599a7f62e Mon Sep 17 00:00:00 2001 From: Kuogee Hsieh Date: Mon, 22 Jun 2009 13:36:19 -0700 Subject: [ARM] msm: pmic: fix endless read operation during debugfs read return 0 to indicate an end-of-read condition to debugfs during read operation Signed-off-by: Kuogee Hsieh --- arch/arm/mach-msm/pmic_debugfs.c | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/pmic_debugfs.c b/arch/arm/mach-msm/pmic_debugfs.c index 8d872c90cbcd..3614c3bcde0e 100644 --- a/arch/arm/mach-msm/pmic_debugfs.c +++ b/arch/arm/mach-msm/pmic_debugfs.c @@ -1009,7 +1009,7 @@ struct pmic_debug_desc pmic_debug[] = { {debug_get_spkr_configuration, NULL}, /* GET_SPKR_CONFIGURATION_PROC */ {debug_spkr_get_gain, NULL}, /* SPKR_GET_GAIN_PROC */ {debug_spkr_is_en, NULL}, /* SPKR_IS_EN_PROC */ - {debug_spkr_en_mute, NULL}, /* SPKR_EN_MUTE_PROC */ + {NULL, debug_spkr_en_mute}, /* SPKR_EN_MUTE_PROC */ {debug_spkr_is_mute_en, NULL}, /* SPKR_IS_MUTE_EN_PROC */ {NULL, debug_spkr_set_delay}, /* SPKR_SET_DELAY_PROC */ {debug_spkr_get_delay, NULL}, /* SPKR_GET_DELAY_PROC */ @@ -1081,6 +1081,8 @@ DEFINE_SIMPLE_ATTRIBUTE( static int pmic_debugfs_open(struct inode *inode, struct file *file) { + /* non-seekable */ + file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE); return 0; } @@ -1096,6 +1098,10 @@ static ssize_t pmic_debugfs_write( loff_t *ppos) { struct pmic_debug_desc *pd; + int len = 0; + + printk(KERN_INFO "%s: proc=%d count=%d *ppos=%d\n", + __func__, debug_proc, count, (uint)*ppos); if (count > sizeof(debug_buf)) return -EFAULT; @@ -1108,8 +1114,11 @@ static ssize_t pmic_debugfs_write( pd = &pmic_debug[debug_proc]; - if (pd->set) - return pd->set(debug_buf, count); + if (pd->set) { + len = pd->set(debug_buf, count); + printk(KERN_INFO "%s: len=%d\n", __func__, len); + return len; + } return 0; } @@ -1121,10 +1130,16 @@ static ssize_t pmic_debugfs_read( loff_t *ppos) { struct pmic_debug_desc *pd; - int len = 0; + int len = 0; + + printk(KERN_INFO "%s: proc=%d count=%d *ppos=%d\n", + __func__, debug_proc, count, (uint)*ppos); pd = &pmic_debug[debug_proc]; + if (*ppos) + return 0; /* the end */ + if (pd->get) { len = pd->get(debug_buf, sizeof(debug_buf)); if (len > 0) { @@ -1135,10 +1150,16 @@ static ssize_t pmic_debugfs_read( } } + printk(KERN_INFO "%s: len=%d\n", __func__, len); + + if (len < 0) + return 0; + + *ppos += len; /* increase offset */ + return len; } - static const struct file_operations pmic_debugfs_fops = { .open = pmic_debugfs_open, .release = pmic_debugfs_release, -- cgit v1.2.3 From 1a68cdae060f56605df33c9a8d4bc4bc64edd303 Mon Sep 17 00:00:00 2001 From: "Vishwanathapura, Niranjana" Date: Thu, 25 Jun 2009 10:43:19 -0600 Subject: [ARM] msm: Remove loopback driver Remove loopback driver as tty driver is being used to drive loopback port. Signed-off-by: Niranjana Vishwanathapura --- arch/arm/mach-msm/Makefile | 2 +- arch/arm/mach-msm/smd_loopback.c | 306 --------------------------------------- 2 files changed, 1 insertion(+), 307 deletions(-) delete mode 100644 arch/arm/mach-msm/smd_loopback.c (limited to 'arch') diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 984c2ee6b37a..09f04583929e 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -22,7 +22,7 @@ obj-$(CONFIG_ARCH_QSD8X50) += sirc.o obj-$(CONFIG_MSM_FIQ_SUPPORT) += fiq_glue.o obj-$(CONFIG_MACH_TROUT) += board-trout-rfkill.o obj-$(CONFIG_MSM_SMD) += smd.o smd_tty.o smd_qmi.o smem_log.o -obj-$(CONFIG_MSM_SMD) += smd_ctl2.o smd_loopback.o smd_nmea.o +obj-$(CONFIG_MSM_SMD) += smd_ctl2.o smd_nmea.o obj-$(CONFIG_DEBUG_FS) += pmic_debugfs.o obj-$(CONFIG_MSM_RESET_MODEM) += reset_modem.o obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter.o diff --git a/arch/arm/mach-msm/smd_loopback.c b/arch/arm/mach-msm/smd_loopback.c deleted file mode 100644 index 49312a89424e..000000000000 --- a/arch/arm/mach-msm/smd_loopback.c +++ /dev/null @@ -1,306 +0,0 @@ -/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Code Aurora Forum nor - * the names of its contributors may be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * Alternatively, provided that this notice is retained in full, this software - * may be relicensed by the recipient under the terms of the GNU General Public - * License version 2 ("GPL") and only version 2, in which case the provisions of - * the GPL apply INSTEAD OF those given above. If the recipient relicenses the - * software under the GPL, then the identification text in the MODULE_LICENSE - * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a - * recipient changes the license terms to the GPL, subsequent recipients shall - * not relicense under alternate licensing terms, including the BSD or dual - * BSD/GPL terms. In addition, the following license statement immediately - * below and between the words START and END shall also then apply when this - * software is relicensed under the GPL: - * - * START - * - * 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. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * END - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - */ -/* - * SMD Loopback Driver -- Provides a loopback SMD port interface. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "smd_private.h" - -#define MAX_BUF_SIZE 512 - -static DEFINE_MUTEX(loopback_ch_lock); -static DEFINE_MUTEX(loopback_rx_buf_lock); -static DEFINE_MUTEX(loopback_tx_buf_lock); -static DEFINE_SPINLOCK(loopback_read_lock); - -static DECLARE_WAIT_QUEUE_HEAD(loopback_wait_queue); - -struct loopback_device_t { - struct miscdevice misc; - - struct smd_channel *ch; - - unsigned char tx_buf[MAX_BUF_SIZE]; - unsigned char rx_buf[MAX_BUF_SIZE]; - unsigned int read_avail; -}; - -struct loopback_device_t *loopback_devp; - -static void loopback_notify(void *priv, unsigned event) -{ - unsigned long flags; - - switch (event) { - case SMD_EVENT_DATA: { - int sz; - sz = smd_cur_packet_size(loopback_devp->ch); - if ((sz > 0) && (sz <= smd_read_avail(loopback_devp->ch))) { - /* queue_work(loopback_wq, &loopback_work); */ - spin_lock_irqsave(&loopback_read_lock, flags); - if (loopback_devp->read_avail == 0) { - loopback_devp->read_avail = sz; - wake_up_interruptible(&loopback_wait_queue); - } - spin_unlock_irqrestore(&loopback_read_lock, flags); - } - break; - } - case SMD_EVENT_OPEN: - printk(KERN_INFO "loopback: smd opened\n"); - break; - case SMD_EVENT_CLOSE: - printk(KERN_INFO "loopback: smd closed\n"); - break; - } -} - -static ssize_t loopback_read(struct file *fp, char __user *buf, - size_t count, loff_t *pos) -{ - int r = 0; - int bytes_read = 0; - unsigned long flags; - int sz; - - for (;;) { - mutex_lock(&loopback_rx_buf_lock); - - spin_lock_irqsave(&loopback_read_lock, flags); - loopback_devp->read_avail = 0; - spin_unlock_irqrestore(&loopback_read_lock, flags); - - sz = smd_cur_packet_size(loopback_devp->ch); - - if ((sz != 0) && (sz <= smd_read_avail(loopback_devp->ch))) { - if (sz > MAX_BUF_SIZE) { - smd_read(loopback_devp->ch, 0, sz); - mutex_unlock(&loopback_rx_buf_lock); - continue; - } - - if (sz != smd_read(loopback_devp->ch, - loopback_devp->rx_buf, sz)) { - mutex_unlock(&loopback_rx_buf_lock); - continue; - } - - bytes_read = sz; - break; - } - - mutex_unlock(&loopback_rx_buf_lock); - r = wait_event_interruptible(loopback_wait_queue, - loopback_devp->read_avail); - if (r < 0) { - /* qualify error message */ - if (r != -ERESTARTSYS) { - /* we get this anytime a signal comes in */ - printk(KERN_ERR "ERROR:%s:%i:%s: " - "wait_event_interruptible ret %i\n", - __FILE__, - __LINE__, - __func__, - r - ); - } - return r; - } - } - - r = copy_to_user(buf, loopback_devp->rx_buf, bytes_read); - mutex_unlock(&loopback_rx_buf_lock); - - if (r > 0) { - printk(KERN_ERR "ERROR:%s:%i:%s: " - "copy_to_user could not copy %i bytes.\n", - __FILE__, - __LINE__, - __func__, - r); - } - - return bytes_read; -} - -static ssize_t loopback_write(struct file *file, - const char __user *buf, - size_t count, - loff_t *ppos) -{ - int r, n; - - if (count > MAX_BUF_SIZE) - count = MAX_BUF_SIZE; - - r = copy_from_user(loopback_devp->tx_buf, buf, count); - if (r > 0) { - printk(KERN_ERR "ERROR:%s:%i:%s: " - "copy_from_user could not copy %i bytes.\n", - __FILE__, - __LINE__, - __func__, - r); - return 0; - } - - mutex_lock(&loopback_tx_buf_lock); - n = smd_write_avail(loopback_devp->ch); - while (n < count) { - mutex_unlock(&loopback_tx_buf_lock); - msleep(250); - mutex_lock(&loopback_tx_buf_lock); - n = smd_write_avail(loopback_devp->ch); - } - - r = smd_write(loopback_devp->ch, loopback_devp->tx_buf, count); - mutex_unlock(&loopback_tx_buf_lock); - - if (r != count) { - printk(KERN_ERR "ERROR:%s:%i:%s: " - "smd_write(ch,buf,count = %i) ret %i.\n", - __FILE__, - __LINE__, - __func__, - count, - r); - return r; - } - - return count; -} - -static int loopback_open(struct inode *ip, struct file *fp) -{ - int r = 0; - - mutex_lock(&loopback_ch_lock); - if (loopback_devp->ch == 0) { - smsm_change_state(SMSM_APPS_STATE, 0, SMSM_SMD_LOOPBACK); - msleep(100); - r = smd_open("LOOPBACK", &loopback_devp->ch, - 0, loopback_notify); - } - - mutex_unlock(&loopback_ch_lock); - return r; -} - -static int loopback_release(struct inode *ip, struct file *fp) -{ - int r = 0; - - mutex_lock(&loopback_ch_lock); - if (loopback_devp->ch != 0) { - r = smd_close(loopback_devp->ch); - loopback_devp->ch = 0; - } - mutex_unlock(&loopback_ch_lock); - - return r; -} - -static const struct file_operations loopback_fops = { - .owner = THIS_MODULE, - .read = loopback_read, - .write = loopback_write, - .open = loopback_open, - .release = loopback_release, -}; - -static struct loopback_device_t loopback_device = { - .misc = { - .minor = MISC_DYNAMIC_MINOR, - .name = "loopback", - .fops = &loopback_fops, - } -}; - -static void __exit loopback_exit(void) -{ - misc_deregister(&loopback_device.misc); -} - -static int __init loopback_init(void) -{ - int ret; - - loopback_devp = &loopback_device; - - ret = misc_register(&loopback_device.misc); - return ret; -} - -module_init(loopback_init); -module_exit(loopback_exit); - -MODULE_DESCRIPTION("MSM Shared Memory loopback Driver"); -MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 8245150c5226f2427f2de40c544944279e5e4126 Mon Sep 17 00:00:00 2001 From: "Pfeffer, Zach" Date: Tue, 23 Jun 2009 23:07:47 -0600 Subject: [ARM] msm: acpuclock: Disable PLLs during 7x30 power collapse. Unlike the older 7k series of SoCs, the application processor in the 7x27 SoC directly controls the PLLs. So, when the application processor goes into power collapse, it has to take care of turning off the unused PLLs and can't depend on the modem processor to do it. Signed-off-by: Zach Pfeffer --- arch/arm/mach-msm/acpuclock.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/acpuclock.c b/arch/arm/mach-msm/acpuclock.c index 3ef81c5fde4e..01caa2df70e2 100644 --- a/arch/arm/mach-msm/acpuclock.c +++ b/arch/arm/mach-msm/acpuclock.c @@ -536,12 +536,13 @@ int acpuclk_set_rate(unsigned long rate, enum setrate_reason reason) pr_err("Setting AXI min rate failed!\n"); } - /* Nothing else to do for power collapse. */ - if (reason == SETRATE_PC) + /* Nothing else to do for power collapse if not 7x27. */ + if (reason == SETRATE_PC && !cpu_is_msm7x27()) return 0; /* Disable PLLs we are not using anymore. */ - plls_enabled &= ~(1 << tgt_s->pll); + if (tgt_s->pll != ACPU_PLL_TCXO) + plls_enabled &= ~(1 << tgt_s->pll); for (pll = ACPU_PLL_0; pll <= ACPU_PLL_2; pll++) if (plls_enabled & (1 << pll)) { rc = pc_pll_request(pll, 0); @@ -551,6 +552,10 @@ int acpuclk_set_rate(unsigned long rate, enum setrate_reason reason) } } + /* Nothing else to do for power collapse. */ + if (reason == SETRATE_PC) + return 0; + /* Drop VDD level if we can. */ if (tgt_s->vdd < strt_s->vdd) { if (acpuclk_set_vdd_level(tgt_s->vdd) < 0) -- cgit v1.2.3 From 8e46bbf03e9e6532ed7192a1d4778770c147193f Mon Sep 17 00:00:00 2001 From: "Pfeffer, Zach" Date: Thu, 25 Jun 2009 14:52:18 -0700 Subject: [ARM] msm: pm: pm2: Enable msm_pm_restart restart handling. This function's reset hook or PCOM_RESET_CHIP modem command was ifdef'd out for bringup. This patch removes the ifdef, allowing this function to execute the reset hook or modem commanded restart. This function is executed when the user runs /sbin/shutdown or kill 1 (kill init). Signed-off-by: Zach Pfeffer --- arch/arm/mach-msm/pm.c | 13 ++----------- arch/arm/mach-msm/pm2.c | 12 ++---------- 2 files changed, 4 insertions(+), 21 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/pm.c b/arch/arm/mach-msm/pm.c index 29b0ce9805d3..1b75c9ee5495 100644 --- a/arch/arm/mach-msm/pm.c +++ b/arch/arm/mach-msm/pm.c @@ -667,17 +667,8 @@ static void msm_pm_power_off(void) static void msm_pm_restart(char str) { - /* If there's a hard reset hook and the restart_reason - * is the default, prefer that to the (slower) proc_comm - * reset command. - */ -#if 0 - if ((restart_reason == 0x776655AA) && msm_hw_reset_hook) { - msm_hw_reset_hook(); - } else { - msm_proc_comm(PCOM_RESET_CHIP, &restart_reason, 0); - } -#endif + msm_proc_comm(PCOM_RESET_CHIP, &restart_reason, 0); + for (;;) ; } diff --git a/arch/arm/mach-msm/pm2.c b/arch/arm/mach-msm/pm2.c index 4112b368b937..5db0c70c8743 100644 --- a/arch/arm/mach-msm/pm2.c +++ b/arch/arm/mach-msm/pm2.c @@ -1508,16 +1508,8 @@ static void msm_pm_power_off(void) static void msm_pm_restart(char str) { - /* If there's a hard reset hook and the restart_reason - * is the default, prefer that to the (slower) proc_comm - * reset command. - */ -#if 0 - if ((restart_reason == 0x776655AA) && msm_reset_hook) - msm_reset_hook(str); - else - msm_proc_comm(PCOM_RESET_CHIP, &restart_reason, 0); -#endif + msm_proc_comm(PCOM_RESET_CHIP, &restart_reason, 0); + for (;;) ; } -- cgit v1.2.3 From a7d5cd39c45da29f644a04c1307f91a25351f0c9 Mon Sep 17 00:00:00 2001 From: Saravana Kannan Date: Mon, 22 Jun 2009 19:25:26 -0700 Subject: [ARM] msm: clock: Add support for voting on EBI1 min rate. There are two ways of voting on EBI1 min rate. One is the PM QoS API (which might sleep) and the other is the ebi1_clk_set_min_rate() API (which won't sleep). The 2nd API is needed to aggregate the acpuclock vote and the final PM QoS vote since the acpuclock code can't afford to sleep in the context of the suspend code (one of the callers). Signed-off-by: Saravana Kannan --- arch/arm/mach-msm/acpuclock.c | 5 +++-- arch/arm/mach-msm/clock.c | 47 +++++++++++++++++++++++++++++++++++++++++++ arch/arm/mach-msm/clock.h | 7 ++++++- 3 files changed, 56 insertions(+), 3 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/acpuclock.c b/arch/arm/mach-msm/acpuclock.c index 01caa2df70e2..05b5ab1a87ff 100644 --- a/arch/arm/mach-msm/acpuclock.c +++ b/arch/arm/mach-msm/acpuclock.c @@ -531,7 +531,8 @@ int acpuclk_set_rate(unsigned long rate, enum setrate_reason reason) /* Change the AXI bus frequency if we can. */ if (strt_s->axiclk_khz != tgt_s->axiclk_khz) { - rc = pc_clk_set_min_rate(EBI1_CLK, tgt_s->axiclk_khz * 1000); + rc = ebi1_clk_set_min_rate(CLKVOTE_ACPUCLK, + tgt_s->axiclk_khz * 1000); if (rc < 0) pr_err("Setting AXI min rate failed!\n"); } @@ -605,7 +606,7 @@ static void __init acpuclk_init(void) drv_state.current_speed = speed; - rc = pc_clk_set_min_rate(EBI1_CLK, speed->axiclk_khz * 1000); + rc = ebi1_clk_set_min_rate(CLKVOTE_ACPUCLK, speed->axiclk_khz * 1000); if (rc < 0) pr_err("Setting AXI min rate failed!\n"); diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c index c3f48b113009..2b141cd31ae0 100644 --- a/arch/arm/mach-msm/clock.c +++ b/arch/arm/mach-msm/clock.c @@ -31,6 +31,7 @@ static DEFINE_MUTEX(clocks_mutex); static DEFINE_SPINLOCK(clocks_lock); +static DEFINE_SPINLOCK(ebi1_vote_lock); static LIST_HEAD(clocks); struct clk *msm_clocks; unsigned msm_num_clocks; @@ -231,6 +232,49 @@ int clk_set_flags(struct clk *clk, unsigned long flags) } EXPORT_SYMBOL(clk_set_flags); +/* EBI1 is the only shared clock that several clients want to vote on as of + * this commit. If this changes in the future, then it might be better to + * make clk_min_rate handle the voting or make ebi1_clk_set_min_rate more + * generic to support different clocks. + */ +static unsigned long ebi1_min_rate[CLKVOTE_MAX]; +static struct clk *ebi1_clk; + +/* Rate is in Hz to be consistent with the other clk APIs. */ +int ebi1_clk_set_min_rate(enum clkvote_client client, unsigned long rate) +{ + static unsigned long last_set_val = -1; + unsigned long new_val; + unsigned long flags; + int ret = 0, i; + + spin_lock_irqsave(&ebi1_vote_lock, flags); + + ebi1_min_rate[client] = rate; + + new_val = ebi1_min_rate[0]; + for (i = 1; i < CLKVOTE_MAX; i++) + if (ebi1_min_rate[i] > new_val) + new_val = ebi1_min_rate[i]; + + /* This check is to save a proc_comm call. */ + if (last_set_val != new_val) { + ret = clk_set_min_rate(ebi1_clk, new_val); + if (ret < 0) { + pr_err("Setting EBI1 min rate to %lu Hz failed!\n", + new_val); + pr_err("Last successful value was %lu Hz.\n", + last_set_val); + } else { + last_set_val = new_val; + } + } + + spin_unlock_irqrestore(&ebi1_vote_lock, flags); + + return ret; +} + /* * Find out whether any clock is enabled that needs the TCXO clock. * @@ -296,6 +340,9 @@ void __init msm_clock_init(struct clk *clock_tbl, unsigned num_clocks) for (n = 0; n < msm_num_clocks; n++) list_add_tail(&msm_clocks[n].list, &clocks); mutex_unlock(&clocks_mutex); + + ebi1_clk = clk_get(NULL, "ebi1_clk"); + BUG_ON(ebi1_clk == NULL); } #if defined(CONFIG_DEBUG_FS) diff --git a/arch/arm/mach-msm/clock.h b/arch/arm/mach-msm/clock.h index 8564c65ea19c..b68214a16067 100644 --- a/arch/arm/mach-msm/clock.h +++ b/arch/arm/mach-msm/clock.h @@ -125,9 +125,14 @@ struct clk { #define CLK_MAX CLKFLAG_MAX #define CLK_MINMAX (CLK_MIN | CLK_MAX) +enum clkvote_client { + CLKVOTE_ACPUCLK = 0, + CLKVOTE_MAX, +}; + int msm_clock_require_tcxo(unsigned long *reason, int nbits); int msm_clock_get_name(uint32_t id, char *name, uint32_t size); -int pc_clk_set_min_rate(unsigned id, unsigned rate); +int ebi1_clk_set_min_rate(enum clkvote_client client, unsigned long rate); #endif -- cgit v1.2.3 From c86b6e2228c8c7ef92743e269692db1c94f9e5e7 Mon Sep 17 00:00:00 2001 From: Praveen Chidambaram Date: Fri, 26 Jun 2009 09:16:30 -0600 Subject: [ARM] msm: clock: Use system bus QoS to vote for min AXI freq. The application processor usually sets the EBI1 clock frequency to match the processor frequency. In some cases, a lower CPU frequency but a higher AXI frequency may be required. The drivers and user space applications can vote for a min EBI1 clock frequency using the system bus QoS parameter. The QoS parameter is to be provided in KHz. Note, that this does not guarantee a bus bandwith. The resultant clock frequency will be atleast greater than or equal to the QoS value. CRs-fixed: 185976 Signed-off-by: Praveen Chidambaram --- arch/arm/mach-msm/clock.c | 12 ++++++++++++ arch/arm/mach-msm/clock.h | 1 + 2 files changed, 13 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c index 2b141cd31ae0..33fa6388186b 100644 --- a/arch/arm/mach-msm/clock.c +++ b/arch/arm/mach-msm/clock.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include "clock.h" @@ -42,6 +43,7 @@ unsigned msm_num_clocks; */ static DECLARE_BITMAP(clock_map_enabled, NR_CLKS); static DEFINE_SPINLOCK(clock_map_lock); +static struct notifier_block axi_freq_notifier_block; /* * glue for the proc_comm interface @@ -275,6 +277,12 @@ int ebi1_clk_set_min_rate(enum clkvote_client client, unsigned long rate) return ret; } +static int axi_freq_notifier_handler(struct notifier_block *block, + unsigned long min_freq, void *v) +{ + return ebi1_clk_set_min_rate(CLKVOTE_PMQOS, min_freq * 1000); +} + /* * Find out whether any clock is enabled that needs the TCXO clock. * @@ -343,6 +351,10 @@ void __init msm_clock_init(struct clk *clock_tbl, unsigned num_clocks) ebi1_clk = clk_get(NULL, "ebi1_clk"); BUG_ON(ebi1_clk == NULL); + + axi_freq_notifier_block.notifier_call = axi_freq_notifier_handler; + pm_qos_add_notifier(PM_QOS_SYSTEM_BUS_FREQ, &axi_freq_notifier_block); + } #if defined(CONFIG_DEBUG_FS) diff --git a/arch/arm/mach-msm/clock.h b/arch/arm/mach-msm/clock.h index b68214a16067..4cb65ac834b4 100644 --- a/arch/arm/mach-msm/clock.h +++ b/arch/arm/mach-msm/clock.h @@ -127,6 +127,7 @@ struct clk { enum clkvote_client { CLKVOTE_ACPUCLK = 0, + CLKVOTE_PMQOS, CLKVOTE_MAX, }; -- cgit v1.2.3 From 720ec736ea9e3411f0fe2709df24f4113c079100 Mon Sep 17 00:00:00 2001 From: Dave Estes Date: Thu, 25 Jun 2009 18:09:24 -0400 Subject: [ARM] msm: idle: Use vfp subsystem to preserve vfp context Use vfp subsystem interface to preserve vfp context through power collapse. Remove old assembly vfp preserve code in msm idle-v7.S implementation. Signed-off-by: Dave Estes --- arch/arm/mach-msm/idle-v7.S | 28 ---------------------------- arch/arm/mach-msm/pm2.c | 12 ++++++++++++ 2 files changed, 12 insertions(+), 28 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/idle-v7.S b/arch/arm/mach-msm/idle-v7.S index 00175f0bcc3d..164ed6dd383c 100644 --- a/arch/arm/mach-msm/idle-v7.S +++ b/arch/arm/mach-msm/idle-v7.S @@ -17,7 +17,6 @@ #include #include -#include ENTRY(msm_arch_idle) wfi @@ -42,12 +41,6 @@ ENTRY(msm_pm_collapse) mrc p15, 0, ip, c13, c0, 1 /* context ID */ stmia r0!, {r1-r9, ip} -#ifdef CONFIG_VFP - VFPFSTMIA r0, r1 /* Save VFP working registers */ - fmrx r1, fpexc - fmrx r2, fpscr - stmia r0!, {r1, r2} /* Save VFP state registers */ -#endif bl v7_flush_dcache_all mrc p15, 0, r1, c1, c0, 0 /* read current CR */ @@ -85,23 +78,6 @@ ENTRY(msm_pm_collapse_exit) adr r3, msm_pm_collapse_exit add r1, r1, r3 sub r1, r1, r2 -#ifdef CONFIG_VFP - mrc p15, 0, r2, c1, c0, 2 /* Read CP Access Control Register */ - orr r2, r2, #0x00F00000 /* Enable full access for p10,11 */ - mcr p15, 0, r2, c1, c0, 2 /* Write CPACR */ - isb - mov r2, #0x40000000 /* Enable VFP */ - fmxr fpexc, r2 - isb - ldmdb r1!, {r2, r3} /* Read saved VFP state registers */ - sub r1, r1, #32*8 /* Jump to start of vfp regs area */ - VFPFLDMIA r1, r4 /* Restore VFP working registers, - * r1 incremented to end of vfp - * regs area */ - sub r1, r1, #32*8 /* Jump back to start of vfp regs area */ - fmxr fpscr, r3 /* Restore FPSCR */ - fmxr fpexc, r2 /* Restore FPEXC last */ -#endif ldmdb r1!, {r2-r11} mcr p15, 0, r4, c3, c0, 0 /* dacr */ mcr p15, 0, r3, c2, c0, 0 /* TTBR0 */ @@ -168,9 +144,5 @@ msm_pm_pa_to_va: saved_state: .space 4 * 11 /* r4-14 */ .space 4 * 10 /* cp15 */ -#ifdef CONFIG_VFP - .space 8 * 32 /* VFP working registers */ - .space 4 * 2 /* VFP state registers */ -#endif saved_state_end: diff --git a/arch/arm/mach-msm/pm2.c b/arch/arm/mach-msm/pm2.c index 5db0c70c8743..1f015e827e0c 100644 --- a/arch/arm/mach-msm/pm2.c +++ b/arch/arm/mach-msm/pm2.c @@ -33,6 +33,9 @@ #ifdef CONFIG_CACHE_L2X0 #include #endif +#ifdef CONFIG_VFP +#include +#endif #include "smd_private.h" #include "acpuclock.h" @@ -968,6 +971,11 @@ static int msm_pm_power_collapse saved_vector[0], saved_vector[1], msm_pm_reset_vector[0], msm_pm_reset_vector[1]); +#ifdef CONFIG_VFP + if (from_idle) + vfp_flush_context(); +#endif + #ifdef CONFIG_CACHE_L2X0 l2x0_suspend(); #endif @@ -982,6 +990,10 @@ static int msm_pm_power_collapse msm_pm_reset_vector[1] = saved_vector[1]; if (collapsed) { +#ifdef CONFIG_VFP + if (from_idle) + vfp_reinit(); +#endif cpu_init(); local_fiq_enable(); } -- cgit v1.2.3 From 38b7cc5d952defefa5e32e9e6e3b7ac25db7c6b3 Mon Sep 17 00:00:00 2001 From: "Wilson, Matt" Date: Mon, 29 Jun 2009 14:13:04 -0500 Subject: [ARM] msm: add vreg reference count Support independent enable and disable by clients for common vreg. First enable switches on and last disable switches off. This change has no check for voltage level so clients must agree on level for common vreg. Signed-off-by: Matthew Wilson --- arch/arm/mach-msm/vreg.c | 115 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 79 insertions(+), 36 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/vreg.c b/arch/arm/mach-msm/vreg.c index 2cb7e88fe300..5a5c023e044f 100644 --- a/arch/arm/mach-msm/vreg.c +++ b/arch/arm/mach-msm/vreg.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include "proc_comm.h" @@ -35,43 +36,44 @@ struct vreg { const char *name; unsigned id; int status; + unsigned refcnt; }; -#define VREG(_name, _id, _status) \ - { .name = _name, .id = _id, .status = _status } +#define VREG(_name, _id, _status, _refcnt) \ + { .name = _name, .id = _id, .status = _status, .refcnt = _refcnt } static struct vreg vregs[] = { - VREG("msma", 0, 0), - VREG("msmp", 1, 0), - VREG("msme1", 2, 0), - VREG("msmc1", 3, 0), - VREG("msmc2", 4, 0), - VREG("gp3", 5, 0), - VREG("msme2", 6, 0), - VREG("gp4", 7, 0), - VREG("gp1", 8, 0), - VREG("tcxo", 9, 0), - VREG("pa", 10, 0), - VREG("rftx", 11, 0), - VREG("rfrx1", 12, 0), - VREG("rfrx2", 13, 0), - VREG("synt", 14, 0), - VREG("wlan", 15, 0), - VREG("usb", 16, 0), - VREG("boost", 17, 0), - VREG("mmc", 18, 0), - VREG("ruim", 19, 0), - VREG("msmc0", 20, 0), - VREG("gp2", 21, 0), - VREG("gp5", 22, 0), - VREG("gp6", 23, 0), - VREG("rf", 24, 0), - VREG("rf_vco", 26, 0), - VREG("mpll", 27, 0), - VREG("s2", 28, 0), - VREG("s3", 29, 0), - VREG("rfubm", 30, 0), - VREG("ncp", 31, 0), + VREG("msma", 0, 0, 0), + VREG("msmp", 1, 0, 0), + VREG("msme1", 2, 0, 0), + VREG("msmc1", 3, 0, 0), + VREG("msmc2", 4, 0, 0), + VREG("gp3", 5, 0, 0), + VREG("msme2", 6, 0, 0), + VREG("gp4", 7, 0, 0), + VREG("gp1", 8, 0, 0), + VREG("tcxo", 9, 0, 0), + VREG("pa", 10, 0, 0), + VREG("rftx", 11, 0, 0), + VREG("rfrx1", 12, 0, 0), + VREG("rfrx2", 13, 0, 0), + VREG("synt", 14, 0, 0), + VREG("wlan", 15, 0, 0), + VREG("usb", 16, 0, 0), + VREG("boost", 17, 0, 0), + VREG("mmc", 18, 0, 0), + VREG("ruim", 19, 0, 0), + VREG("msmc0", 20, 0, 0), + VREG("gp2", 21, 0, 0), + VREG("gp5", 22, 0, 0), + VREG("gp6", 23, 0, 0), + VREG("rf", 24, 0, 0), + VREG("rf_vco", 26, 0, 0), + VREG("mpll", 27, 0, 0), + VREG("s2", 28, 0, 0), + VREG("s3", 29, 0, 0), + VREG("rfubm", 30, 0, 0), + VREG("ncp", 31, 0, 0), }; struct vreg *vreg_get(struct device *dev, const char *id) @@ -94,7 +96,12 @@ int vreg_enable(struct vreg *vreg) unsigned id = vreg->id; int enable = VREG_SWITCH_ENABLE; - vreg->status = msm_proc_comm(PCOM_VREG_SWITCH, &id, &enable); + if (vreg->refcnt == 0) + vreg->status = msm_proc_comm(PCOM_VREG_SWITCH, &id, &enable); + + if ((vreg->refcnt < UINT_MAX) && (!vreg->status)) + vreg->refcnt++; + return vreg->status; } EXPORT_SYMBOL(vreg_enable); @@ -104,7 +111,15 @@ int vreg_disable(struct vreg *vreg) unsigned id = vreg->id; int disable = VREG_SWITCH_DISABLE; - vreg->status = msm_proc_comm(PCOM_VREG_SWITCH, &id, &disable); + if (!vreg->refcnt) + return 0; + + if (vreg->refcnt == 1) + vreg->status = msm_proc_comm(PCOM_VREG_SWITCH, &id, &disable); + + if (!vreg->status) + vreg->refcnt--; + return vreg->status; } EXPORT_SYMBOL(vreg_disable); @@ -149,21 +164,49 @@ static int vreg_debug_get(void *data, u64 *val) return 0; } +static int vreg_debug_count_set(void *data, u64 val) +{ + struct vreg *vreg = data; + if (val > UINT_MAX) + val = UINT_MAX; + vreg->refcnt = val; + return 0; +} + +static int vreg_debug_count_get(void *data, u64 *val) +{ + struct vreg *vreg = data; + + *val = vreg->refcnt; + + return 0; +} + DEFINE_SIMPLE_ATTRIBUTE(vreg_fops, vreg_debug_get, vreg_debug_set, "%llu\n"); +DEFINE_SIMPLE_ATTRIBUTE(vreg_count_fops, vreg_debug_count_get, + vreg_debug_count_set, "%llu\n"); static int __init vreg_debug_init(void) { struct dentry *dent; int n; + char name[32]; + const char *refcnt_name = "_refcnt"; dent = debugfs_create_dir("vreg", 0); if (IS_ERR(dent)) return 0; - for (n = 0; n < ARRAY_SIZE(vregs); n++) + for (n = 0; n < ARRAY_SIZE(vregs); n++) { (void) debugfs_create_file(vregs[n].name, 0644, dent, vregs + n, &vreg_fops); + strlcpy(name, vregs[n].name, sizeof(name)); + strlcat(name, refcnt_name, sizeof(name)); + (void) debugfs_create_file(name, 0644, + dent, vregs + n, &vreg_count_fops); + } + return 0; } -- cgit v1.2.3 From 28a86e4533cf6b37501b4b30bffb274dad28186c Mon Sep 17 00:00:00 2001 From: Dave Estes Date: Mon, 29 Jun 2009 15:26:30 -0400 Subject: [ARM] msm: Add jtag debug register save & restore Add ARM specified JTAG debug register save & restore code. This allows JTAG debug sessions to work through power collapse. Breakpoints etc. are preserved. Adds new jtag-v7.S file. Signed-off-by: Dave Estes --- arch/arm/mach-msm/Kconfig | 7 +++ arch/arm/mach-msm/Makefile | 1 + arch/arm/mach-msm/idle-v7.S | 7 +++ arch/arm/mach-msm/jtag-v7.S | 146 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 161 insertions(+) create mode 100644 arch/arm/mach-msm/jtag-v7.S (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index d1fe69b08aa3..376e2ad4b2ef 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -314,6 +314,13 @@ config MSM_SUSPEND_STATS_FIRST_BUCKET endif # MSM_IDLE_STATS +config MSM_JTAG_V7 + depends on CPU_V7 + default y if DEBUG_KERNEL + bool "JTAG debug support" + help + Add additional support for JTAG kernel debugging. + config HTC_HEADSET tristate "HTC 2 Wire detection driver" default n diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 09f04583929e..5917887300f6 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_ARCH_MSM_ARM11) += acpuclock.o obj-$(CONFIG_ARCH_MSM_SCORPION) += acpuclock-8x50.o obj-$(CONFIG_CPU_V6) += idle-v6.o obj-$(CONFIG_CPU_V7) += idle-v7.o +obj-$(CONFIG_MSM_JTAG_V7) += jtag-v7.o obj-$(CONFIG_ARCH_QSD8X50) += sirc.o obj-$(CONFIG_MSM_FIQ_SUPPORT) += fiq_glue.o diff --git a/arch/arm/mach-msm/idle-v7.S b/arch/arm/mach-msm/idle-v7.S index 164ed6dd383c..66f69f879beb 100644 --- a/arch/arm/mach-msm/idle-v7.S +++ b/arch/arm/mach-msm/idle-v7.S @@ -41,6 +41,9 @@ ENTRY(msm_pm_collapse) mrc p15, 0, ip, c13, c0, 1 /* context ID */ stmia r0!, {r1-r9, ip} +#ifdef CONFIG_MSM_JTAG_V7 + bl msm_save_jtag_debug +#endif bl v7_flush_dcache_all mrc p15, 0, r1, c1, c0, 0 /* read current CR */ @@ -128,6 +131,9 @@ msm_pm_pa_to_va: isb stmfd sp!, {lr} bl v7_flush_kern_cache_all +#ifdef CONFIG_MSM_JTAG_V7 + bl msm_restore_jtag_debug +#endif ldmfd sp!, {lr} mov r0, #1 bx lr @@ -146,3 +152,4 @@ saved_state: .space 4 * 10 /* cp15 */ saved_state_end: + diff --git a/arch/arm/mach-msm/jtag-v7.S b/arch/arm/mach-msm/jtag-v7.S new file mode 100644 index 000000000000..cd961109900b --- /dev/null +++ b/arch/arm/mach-msm/jtag-v7.S @@ -0,0 +1,146 @@ +/* + * JTAG support functions for ARMv7-based Qualcomm SoCs. + * + * Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include + +ENTRY(msm_save_jtag_debug) + /* lock debug and preserve registers through power collapse */ + ldr r3, =dbg_state /* store state at dbg_state */ + + ldr r1, =0xc5ACCE55 /* set DBGOSLAR lock */ + mcr p14,0,r1,c1,c0,4 + isb + + mrc p14,0,r1,c1,c2,4 /* DBGOSSRR state register count */ + + cmp r1, #(0x20-1) /* check for state overflow */ + movge r1, #0 /* if not enough space, don't save */ + + str r1,[r3],#4 /* save count for restore */ + +1: cmp r1,#0 + mrcne p14,0,r2,c1,c2,4 /* DBGOSSRR state value */ + strne r2,[r3],#4 /* push value */ + subne r1,r1,#1 + bne 1b + + /* unlock JTAG. Works better than leaving locked. */ + stmfd sp!, {lr} + bl msm_unlock_jtag_debug + ldmfd sp!, {lr} + bx lr + +ENTRY(msm_unlock_jtag_debug) + mov r0, #0 /* unlock value */ + mcr p14,0,r0,c1,c0,4 /* unlock DBGOSLAR */ + isb + bx lr + +ENTRY(msm_restore_jtag_debug) + /* restore debug registers after power collapse */ + ldr r3, =dbg_state /* load state from dbg_state */ + + ldr r1, =0xc5ACCE55 /* set DBGOSLAR lock */ + mcr p14,0,r1,c1,c0,4 + isb + + mrc p14,0,r1,c1,c2,4 /* DBGOSSRR dummy read (required)*/ + ldr r1,[r3],#4 /* load saved count */ + cmp r1,#0 /* skip if none stored + beq msm_pm_dbg_restore_end + + /* restores debug state except DBGDSCR */ +1: ldr r2,[r3],#4 + cmp r1,#0x10 /* DBGDSCR special case */ + biceq r2,r2,#0xc000 /* DBGDSCR = DBGDSCR & ~0xc000 */ + mcr p14,0,r2,c1,c2,4 /* DBGOSSRR write state value */ + subs r1,r1,#1 + bne 1b + isb + + /* second loop to restore DBGDSCR after other state restored */ + ldr r3, =dbg_state /* load state from dbg_state */ + + ldr r1, =0xc5ACCE55 /* set DBGOSLAR lock */ + mcr p14,0,r1,c1,c0,4 + isb + + mrc p14,0,r1,c1,c5,4 /* clear sticky power down bit */ + isb + + mrc p14,0,r1,c1,c2,4 /* DBGOSSRR dummy read (required)*/ + ldr r1,[r3],#4 /* load saved count */ + +1: ldr r2,[r3],#4 + mcr p14,0,r2,c1,c2,4 /* DBGOSSRR write state value */ + subs r1,r1,#1 + bne 1b +msm_pm_dbg_restore_end: + mcr p14,0,r1,c1,c0,4 /* unlock DBGOSLAR */ + isb + bx lr + + + .data + +dbg_state: + .space 4 * 0x20 + -- cgit v1.2.3 From c704aa4bf0c7b84831a9aff400fd0b0aef9c96bc Mon Sep 17 00:00:00 2001 From: "Dudani, Ajay" Date: Mon, 29 Jun 2009 12:07:05 -0700 Subject: [ARM] msm: move DRAM physical address for qsd8k Update physical addresses used for kernel decompression such that it does not get overwritten by other values. Since all ARCH_MSM_SCORPION targets now use a base of 0x24000000, the CONFIG_QSD_BASE_24000000 can be removed Signed-off-by: Ajay Dudani --- arch/arm/mach-msm/Kconfig | 7 ------- arch/arm/mach-msm/Makefile.boot | 7 +------ arch/arm/mach-msm/board-qsd8x50.c | 4 ++-- arch/arm/mach-msm/include/mach/memory.h | 4 +--- 4 files changed, 4 insertions(+), 18 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index 376e2ad4b2ef..5598ace3f4bc 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -574,11 +574,4 @@ config MSM_SLEEP_TIME_OVERRIDE suspend. The feature is required for automated power management testing. -config QSD_BASE_24000000 - bool "Base memory at 0x24000000" - depends on ARCH_MSM_SCORPION - default n - help - Select if physical DRAM at 0x24000000 - endif diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot index 5a8ae0a2b516..4e76b6cc2cbe 100644 --- a/arch/arm/mach-msm/Makefile.boot +++ b/arch/arm/mach-msm/Makefile.boot @@ -1,13 +1,8 @@ ifeq ($(CONFIG_ARCH_MSM_SCORPION),y) -ifeq ($(CONFIG_QSD_BASE_24000000),y) +ifeq ($(CONFIG_MSM_STACKED_MEMORY), y) zreladdr-y := 0x24008000 params_phys-y := 0x24000100 initrd_phys-y := 0x28000000 -endif # CONFIG_QSD_BASE_24000000 -ifeq ($(CONFIG_MSM_STACKED_MEMORY), y) - zreladdr-y := 0x16008000 -params_phys-y := 0x16000100 -initrd_phys-y := 0x1A000000 else # !CONFIG_MSM_STACKED_MEMORY zreladdr-y := 0x00208000 params_phys-y := 0x00200100 diff --git a/arch/arm/mach-msm/board-qsd8x50.c b/arch/arm/mach-msm/board-qsd8x50.c index 6e2ba4b18d76..b39c09f65850 100644 --- a/arch/arm/mach-msm/board-qsd8x50.c +++ b/arch/arm/mach-msm/board-qsd8x50.c @@ -1454,7 +1454,7 @@ MACHINE_START(QSD8X50_SURF, "QCT QSD8X50 SURF") .phys_io = MSM_DEBUG_UART_PHYS, .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc, #endif - .boot_params = 0x16000100, + .boot_params = 0x24000100, .map_io = qsd8x50_map_io, .init_irq = qsd8x50_init_irq, .init_machine = qsd8x50_init, @@ -1466,7 +1466,7 @@ MACHINE_START(QSD8X50_FFA, "QCT QSD8X50 FFA") .phys_io = MSM_DEBUG_UART_PHYS, .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc, #endif - .boot_params = 0x16000100, + .boot_params = 0x24000100, .map_io = qsd8x50_map_io, .init_irq = qsd8x50_init_irq, .init_machine = qsd8x50_init, diff --git a/arch/arm/mach-msm/include/mach/memory.h b/arch/arm/mach-msm/include/mach/memory.h index b5be737ecdec..fba44ae3b597 100644 --- a/arch/arm/mach-msm/include/mach/memory.h +++ b/arch/arm/mach-msm/include/mach/memory.h @@ -19,10 +19,8 @@ /* physical offset of RAM */ #ifdef CONFIG_MSM_STACKED_MEMORY -#ifdef CONFIG_QSD_BASE_24000000 +#ifdef CONFIG_ARCH_MSM_SCORPION #define PHYS_OFFSET UL(0x24000000) -#elif defined(CONFIG_ARCH_MSM_SCORPION) -#define PHYS_OFFSET UL(0x16000000) #else #define PHYS_OFFSET UL(0x10000000) #endif -- cgit v1.2.3 From ce9eac22e9c10109cf08360217a9f0a2da271b92 Mon Sep 17 00:00:00 2001 From: Michael Bohan Date: Wed, 15 Jul 2009 14:12:16 -0700 Subject: [ARM] msm: 7x30: Change smem base address for new modem The new Linux modem build for msm7x30 has a slightly different memory map than its predecessor. The new smem base reflects that change. Signed-off-by: Michael Bohan --- arch/arm/mach-msm/board-msm7x30.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c index c701f8df489d..18957b816a9e 100644 --- a/arch/arm/mach-msm/board-msm7x30.c +++ b/arch/arm/mach-msm/board-msm7x30.c @@ -144,7 +144,7 @@ static void __init msm7x30_init(void) static void __init msm7x30_map_io(void) { - msm_shared_ram_phys = 0x07F00000; + msm_shared_ram_phys = 0x00100000; msm_map_msm7x30_io(); msm_clock_init(msm_clocks_8x50, msm_num_clocks_8x50); } -- cgit v1.2.3 From 6ba4f5b2049c55ab94e4bd7b4c364fa735e3b0a7 Mon Sep 17 00:00:00 2001 From: Neil Leeder Date: Wed, 1 Jul 2009 12:06:23 -0400 Subject: [ARM] msm: allow external LCDC display for 8K surf Signed-off-by: Neil Leeder --- arch/arm/mach-msm/board-qsd8x50.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/board-qsd8x50.c b/arch/arm/mach-msm/board-qsd8x50.c index b39c09f65850..37fe6710ecc0 100644 --- a/arch/arm/mach-msm/board-qsd8x50.c +++ b/arch/arm/mach-msm/board-qsd8x50.c @@ -294,7 +294,8 @@ static int msm_fb_detect_panel(const char *name) ret = 0; else ret = -ENODEV; - } + } else if (machine_is_qsd8x50_surf() && !strcmp(name, "lcdc_external")) + ret = 0; return ret; } -- cgit v1.2.3 From 68d7d7b66ff7dc1d4e3b09728dfbb984edc17e02 Mon Sep 17 00:00:00 2001 From: Rajesha Kini Date: Fri, 17 Jul 2009 11:51:40 +0530 Subject: [ARM] msm: audio: Update ADSP firmware support details Added ADSP firmware details of msm7x27 target. It is queried by audio preprocessing layer to support multi decoder feature. Signed-off-by: Rajesha Kini --- arch/arm/mach-msm/board-msm7x27.c | 94 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/board-msm7x27.c b/arch/arm/mach-msm/board-msm7x27.c index 7dd5468d2240..c24f36f617fc 100644 --- a/arch/arm/mach-msm/board-msm7x27.c +++ b/arch/arm/mach-msm/board-msm7x27.c @@ -190,6 +190,99 @@ static struct platform_device msm_device_snd = { .platform_data = &msm_device_snd_endpoints }, }; + +#define DEC0_FORMAT ((1< Date: Thu, 16 Jul 2009 15:52:51 +0300 Subject: [ARM] msm: GPIO: group operations Provide facility to operate with groups of GPIO's. All GPIO information written in single structure, containing all bits as required for TLMM in GPIO_CFG() style. GPIO pin, as required by other functions, extracted from GPIO_CFG() style - this removes data duplication. Group functions provide accurate error checking and rollback in case of error Signed-off-by: Vladimir Kondratiev --- arch/arm/mach-msm/gpio.c | 98 +++++++++++++++++++++++++++++++++++ arch/arm/mach-msm/include/mach/gpio.h | 75 +++++++++++++++++++++++++++ 2 files changed, 173 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/gpio.c b/arch/arm/mach-msm/gpio.c index 4d1336b5c407..903379d6f8ed 100644 --- a/arch/arm/mach-msm/gpio.c +++ b/arch/arm/mach-msm/gpio.c @@ -591,6 +591,104 @@ int gpio_tlmm_config(unsigned config, unsigned disable) } EXPORT_SYMBOL(gpio_tlmm_config); +int msm_gpios_request_enable(const struct msm_gpio *table, int size) +{ + int rc = msm_gpios_request(table, size); + if (rc) + return rc; + rc = msm_gpios_enable(table, size); + if (rc) + msm_gpios_free(table, size); + return rc; +} +EXPORT_SYMBOL(msm_gpios_request_enable); + +void msm_gpios_disable_free(const struct msm_gpio *table, int size) +{ + msm_gpios_disable(table, size); + msm_gpios_free(table, size); +} +EXPORT_SYMBOL(msm_gpios_disable_free); + +int msm_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("gpio_request(%d) <%s> failed: %d\n", + GPIO_PIN(g->gpio_cfg), g->label ?: "?", rc); + goto err; + } + } + return 0; +err: + msm_gpios_free(table, i); + return rc; +} +EXPORT_SYMBOL(msm_gpios_request); + +void msm_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)); + } +} +EXPORT_SYMBOL(msm_gpios_free); + +int msm_gpios_enable(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_tlmm_config(g->gpio_cfg, GPIO_ENABLE); + if (rc) { + pr_err("gpio_tlmm_config(0x%08x, GPIO_ENABLE)" + " <%s> failed: %d\n", + g->gpio_cfg, g->label ?: "?", rc); + pr_err("pin %d func %d dir %d pull %d drvstr %d\n", + GPIO_PIN(g->gpio_cfg), GPIO_FUNC(g->gpio_cfg), + GPIO_DIR(g->gpio_cfg), GPIO_PULL(g->gpio_cfg), + GPIO_DRVSTR(g->gpio_cfg)); + goto err; + } + } + return 0; +err: + msm_gpios_disable(table, i); + return rc; +} +EXPORT_SYMBOL(msm_gpios_enable); + +void msm_gpios_disable(const struct msm_gpio *table, int size) +{ + int rc; + int i; + const struct msm_gpio *g; + for (i = size-1; i >= 0; i--) { + g = table + i; + rc = gpio_tlmm_config(g->gpio_cfg, GPIO_DISABLE); + if (rc) { + pr_err("gpio_tlmm_config(0x%08x, GPIO_DISABLE)" + " <%s> failed: %d\n", + g->gpio_cfg, g->label ?: "?", rc); + pr_err("pin %d func %d dir %d pull %d drvstr %d\n", + GPIO_PIN(g->gpio_cfg), GPIO_FUNC(g->gpio_cfg), + GPIO_DIR(g->gpio_cfg), GPIO_PULL(g->gpio_cfg), + GPIO_DRVSTR(g->gpio_cfg)); + } + } +} +EXPORT_SYMBOL(msm_gpios_disable); + #if defined(CONFIG_DEBUG_FS) static int msm_gpio_debug_result = 1; diff --git a/arch/arm/mach-msm/include/mach/gpio.h b/arch/arm/mach-msm/include/mach/gpio.h index 1c4e19ea15a0..713afb930d2d 100644 --- a/arch/arm/mach-msm/include/mach/gpio.h +++ b/arch/arm/mach-msm/include/mach/gpio.h @@ -20,6 +20,71 @@ #include +/** + * struct msm_gpio - GPIO pin description + * @gpio_cfg - configuration bitmap, as per gpio_tlmm_config() + * @label - textual label + * + * Usually, GPIO's are operated by sets. + * This struct accumulate all GPIO information in single source + * and facilitete group operations provided by msm_gpios_xxx() + */ +struct msm_gpio { + u32 gpio_cfg; + const char *label; +}; + +/** + * msm_gpios_request_enable() - request and enable set of GPIOs + * + * Request and configure set of GPIO's + * In case of error, all operations rolled back. + * Return error code. + * + * @table: GPIO table + * @size: number of entries in @table + */ +int msm_gpios_request_enable(const struct msm_gpio *table, int size); +/** + * msm_gpios_disable_free() - disable and free set of GPIOs + * + * @table: GPIO table + * @size: number of entries in @table + */ +void msm_gpios_disable_free(const struct msm_gpio *table, int size); +/** + * msm_gpios_request() - request set of GPIOs + * In case of error, all operations rolled back. + * Return error code. + * + * @table: GPIO table + * @size: number of entries in @table + */ +int msm_gpios_request(const struct msm_gpio *table, int size); +/** + * msm_gpios_free() - free set of GPIOs + * + * @table: GPIO table + * @size: number of entries in @table + */ +void msm_gpios_free(const struct msm_gpio *table, int size); +/** + * msm_gpios_enable() - enable set of GPIOs + * In case of error, all operations rolled back. + * Return error code. + * + * @table: GPIO table + * @size: number of entries in @table + */ +int msm_gpios_enable(const struct msm_gpio *table, int size); +/** + * msm_gpios_disable() - disable set of GPIOs + * + * @table: GPIO table + * @size: number of entries in @table + */ +void msm_gpios_disable(const struct msm_gpio *table, int size); + int gpio_request(unsigned gpio, const char *label); void gpio_free(unsigned gpio); int gpio_direction_input(unsigned gpio); @@ -87,6 +152,16 @@ enum { (((pull) & 0x3) << 15) | \ (((drvstr) & 0xF) << 17)) +/** + * extract GPIO pin from bit-field used for gpio_tlmm_config + */ +#define GPIO_PIN(gpio_cfg) (((gpio_cfg) >> 4) & 0x3ff) +#define GPIO_FUNC(gpio_cfg) (((gpio_cfg) >> 0) & 0xf) +#define GPIO_DIR(gpio_cfg) (((gpio_cfg) >> 14) & 0x1) +#define GPIO_PULL(gpio_cfg) (((gpio_cfg) >> 15) & 0x3) +#define GPIO_DRVSTR(gpio_cfg) (((gpio_cfg) >> 17) & 0xf) + int gpio_tlmm_config(unsigned config, unsigned disable); #endif + -- cgit v1.2.3 From 3b6fdbe6cbe9a2b0fae48095da463b4760731474 Mon Sep 17 00:00:00 2001 From: Ai Li Date: Thu, 16 Jul 2009 18:28:58 -0600 Subject: [ARM] pm: reset chip when Modem fails to respond to handshake When Modem fails to respond to the power collapse handshake, Modem and Apps are out of sync and Modem is in a bad state. There is no way of recovery other than resetting the chip. This patch also increases the timeout value dramatically to avoid false detection. The wait for Modem setting its RUN bit while Apps exiting power collapse is removed. The wait is not necessary and keeping it could lead to a Apps-Modem deadlock. Signed-off-by: Ai Li --- arch/arm/mach-msm/pm.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/pm.c b/arch/arm/mach-msm/pm.c index 1b75c9ee5495..1ca40dd25951 100644 --- a/arch/arm/mach-msm/pm.c +++ b/arch/arm/mach-msm/pm.c @@ -201,7 +201,7 @@ msm_pm_wait_state(uint32_t wait_state_all_set, uint32_t wait_state_all_clear, int i; uint32_t state; - for (i = 0; i < 100000; i++) { + for (i = 0; i < 2000000; i++) { state = smsm_get_state(SMSM_MODEM_STATE); if (((state & wait_state_all_set) == wait_state_all_set) && ((~state & wait_state_all_clear) == wait_state_all_clear) && @@ -285,10 +285,12 @@ static int msm_sleep(int sleep_mode, uint32_t sleep_delay, } ret = msm_pm_wait_state(enter_wait_set, enter_wait_clear, 0, 0); if (ret) { - printk(KERN_INFO "msm_sleep(): " - "msm_pm_wait_state failed, %x\n", - smsm_get_state(SMSM_MODEM_STATE)); - goto enter_failed; + printk(KERN_EMERG "msm_sleep(): power collapse entry " + "timed out waiting for Modem's response " + "-- resetting chip\n"); + msm_proc_comm(PCOM_RESET_CHIP_IMM, NULL, NULL); + for (;;) + ; } } if (msm_irq_enter_sleep2(!!enter_state, from_idle)) @@ -387,7 +389,14 @@ enter_failed: writel(0x00, A11S_CLK_SLEEP_EN); writel(0, A11S_PWRDOWN); smsm_change_state(SMSM_APPS_STATE, enter_state, exit_state); - msm_pm_wait_state(exit_wait_set, exit_wait_clear, 0, 0); + if (msm_pm_wait_state(exit_wait_set, exit_wait_clear, 0, 0)) { + printk(KERN_EMERG "msm_sleep(): power collapse exit " + "timed out waiting for Modem's response " + "-- resetting chip\n"); + msm_proc_comm(PCOM_RESET_CHIP_IMM, NULL, NULL); + for (;;) + ; + } if (msm_pm_debug_mask & MSM_PM_DEBUG_STATE) printk(KERN_INFO "msm_sleep(): sleep exit " "A11S_CLK_SLEEP_EN %x, A11S_PWRDOWN %x, " @@ -406,7 +415,6 @@ enter_failed: msm_pm_sma.int_info->aArm_interrupts_pending); if (enter_state) { smsm_change_state(SMSM_APPS_STATE, exit_state, SMSM_RUN); - msm_pm_wait_state(SMSM_RUN, 0, 0, 0); if (msm_pm_debug_mask & MSM_PM_DEBUG_STATE) printk(KERN_INFO "msm_sleep(): sleep exit " "A11S_CLK_SLEEP_EN %x, A11S_PWRDOWN %x, " -- cgit v1.2.3 From f0a3c030fa14351680ae714a17a05199c5d04c49 Mon Sep 17 00:00:00 2001 From: Abhijeet Dharmapurikar Date: Tue, 21 Jul 2009 18:15:34 -0700 Subject: [ARM] msm: moved cpufreq to late_initcall The cpufreq driver calls pmic before it is initialized. This change moved the cpufreq to late_initcall (level 7) so that it will call pmic after it is initialised. CRs-fixed: 184897 Signed-off-by: Bryan Huntsman --- arch/arm/mach-msm/cpufreq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/cpufreq.c b/arch/arm/mach-msm/cpufreq.c index a0b1a06263c1..0dffaa2fa4cb 100644 --- a/arch/arm/mach-msm/cpufreq.c +++ b/arch/arm/mach-msm/cpufreq.c @@ -123,5 +123,5 @@ static int __init msm_cpufreq_register(void) return cpufreq_register_driver(&msm_cpufreq_driver); } -device_initcall(msm_cpufreq_register); +late_initcall(msm_cpufreq_register); #endif -- cgit v1.2.3 From f468c906f634dc83f05e832256e34d0885006209 Mon Sep 17 00:00:00 2001 From: Dave Estes Date: Wed, 22 Jul 2009 12:26:30 -0400 Subject: [ARM] msm: Update residencies and latencies for the sleep modes on 8x50. Update residencies and latencies for the sleep modes based on tests performed on 8k hardware. This improves power and performance. Signed-off-by: Dave Estes --- arch/arm/mach-msm/board-comet.c | 14 +++++++------- arch/arm/mach-msm/board-qsd8x50.c | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/board-comet.c b/arch/arm/mach-msm/board-comet.c index ed60f274a992..d99b1babe59e 100644 --- a/arch/arm/mach-msm/board-comet.c +++ b/arch/arm/mach-msm/board-comet.c @@ -966,26 +966,26 @@ static struct msm_pm_platform_data msm_pm_data[MSM_PM_SLEEP_MODE_NR] = { [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].supported = 1, [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].suspend_enabled = 1, [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].idle_enabled = 1, - [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].latency = 16000, - [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].residency = 20000, + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].latency = 8594, + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].residency = 23740, [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].supported = 1, [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].suspend_enabled = 1, [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].idle_enabled = 1, - [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].latency = 12000, - [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].residency = 20000, + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].latency = 4594, + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].residency = 23740, [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].supported = 1, [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].suspend_enabled = 1, [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].idle_enabled = 0, - [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].latency = 2000, - [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].residency = 10000, + [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].latency = 443, + [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].residency = 1098, [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].supported = 1, [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].suspend_enabled = 1, [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].idle_enabled = 1, - [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].latency = 500, + [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].latency = 2, [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].residency = 0, }; diff --git a/arch/arm/mach-msm/board-qsd8x50.c b/arch/arm/mach-msm/board-qsd8x50.c index 37fe6710ecc0..b74e62a96ca0 100644 --- a/arch/arm/mach-msm/board-qsd8x50.c +++ b/arch/arm/mach-msm/board-qsd8x50.c @@ -1310,26 +1310,26 @@ static struct msm_pm_platform_data msm_pm_data[MSM_PM_SLEEP_MODE_NR] = { [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].supported = 1, [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].suspend_enabled = 1, [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].idle_enabled = 1, - [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].latency = 16000, - [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].residency = 20000, + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].latency = 8594, + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].residency = 23740, [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].supported = 1, [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].suspend_enabled = 1, [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].idle_enabled = 1, - [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].latency = 12000, - [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].residency = 20000, + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].latency = 4594, + [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].residency = 23740, [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].supported = 1, [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].suspend_enabled = 1, [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].idle_enabled = 0, - [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].latency = 2000, - [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].residency = 10000, + [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].latency = 443, + [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].residency = 1098, [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].supported = 1, [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].suspend_enabled = 1, [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].idle_enabled = 1, - [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].latency = 500, + [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].latency = 2, [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].residency = 0, }; -- cgit v1.2.3 From 50d60b825b183f2a29c139d039dd07ca406d4292 Mon Sep 17 00:00:00 2001 From: Saravana Kannan Date: Wed, 22 Jul 2009 12:57:51 -0700 Subject: [ARM] msm: pm: Fix up existing workaround to enable code refactoring. An already existing temporary workaround includes and uses restricted APIs to go around the clock driver. That prevents refactoring of the clock code. So, change the workaround to not use the #defines that will be refactored. The workaround is expected to be removed soon. Signed-off-by: Saravana Kannan --- arch/arm/mach-msm/pm.c | 9 +++++++-- arch/arm/mach-msm/pm2.c | 9 +++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/pm.c b/arch/arm/mach-msm/pm.c index 1ca40dd25951..d8a6c78b57cd 100644 --- a/arch/arm/mach-msm/pm.c +++ b/arch/arm/mach-msm/pm.c @@ -321,7 +321,11 @@ static int msm_sleep(int sleep_mode, uint32_t sleep_delay, } if (sleep_mode < MSM_PM_SLEEP_MODE_APPS_SLEEP) { #ifdef CONFIG_MSM_ADM_OFF_AT_POWER_COLLAPSE - unsigned id = ADM_CLK; + /* XXX: Temp workaround that needs to be removed soon. The + * right fix will probably involve the DMA driver taking + * ownership of the ADM clock. */ + /* id is set to denote ADM clock. */ + unsigned id = 1; msm_proc_comm(PCOM_CLKCTL_RPC_DISABLE, &id, NULL); #endif if (msm_pm_debug_mask & MSM_PM_DEBUG_SMSM_STATE) @@ -356,7 +360,8 @@ static int msm_sleep(int sleep_mode, uint32_t sleep_delay, msm_pm_sma.int_info->aArm_wakeup_reason, msm_pm_sma.int_info->aArm_interrupts_pending); #ifdef CONFIG_MSM_ADM_OFF_AT_POWER_COLLAPSE - id = ADM_CLK; + /* id is set to denote ADM clock. */ + id = 1; if (msm_proc_comm(PCOM_CLKCTL_RPC_ENABLE, &id, NULL) < 0 || id < 0) printk(KERN_ERR diff --git a/arch/arm/mach-msm/pm2.c b/arch/arm/mach-msm/pm2.c index 1f015e827e0c..8ec295426f70 100644 --- a/arch/arm/mach-msm/pm2.c +++ b/arch/arm/mach-msm/pm2.c @@ -944,7 +944,11 @@ static int msm_pm_power_collapse } #ifdef CONFIG_MSM_ADM_OFF_AT_POWER_COLLAPSE - id = ADM_CLK; + /* XXX: Temp workaround that needs to be removed soon. The + * right fix will probably involve the DMA driver taking + * ownership of the ADM clock. */ + /* id is set to denote ADM clock. */ + id = 1; msm_proc_comm(PCOM_CLKCTL_RPC_DISABLE, &id, NULL); #endif @@ -1010,7 +1014,8 @@ static int msm_pm_power_collapse __func__, saved_acpuclk_rate); #ifdef CONFIG_MSM_ADM_OFF_AT_POWER_COLLAPSE - id = ADM_CLK; + /* id is set to denote ADM clock. */ + id = 1; if (msm_proc_comm(PCOM_CLKCTL_RPC_ENABLE, &id, NULL) < 0 || id < 0) printk(KERN_ERR "%s(): failed to turn on ADM clock\n", __func__); -- cgit v1.2.3 From 93ea75b9bcf8be4de27aa958048bf3f85d8fcef6 Mon Sep 17 00:00:00 2001 From: Saravana Kannan Date: Tue, 14 Jul 2009 19:57:50 -0700 Subject: [ARM] msm: clock: Refactor code to allow SoC specific implementation. Each clock now has a list of function pointers that are used to enact the standard clock APIs on that clock. So, clocks that need SoC specific code will have their "clock_ops" function pointers initialized differently. Signed-off-by: Saravana Kannan --- arch/arm/mach-msm/Makefile | 2 +- arch/arm/mach-msm/clock-pcom.c | 105 +++++++++++++ arch/arm/mach-msm/clock-pcom.h | 131 ++++++++++++++++ arch/arm/mach-msm/clock.c | 106 ++----------- arch/arm/mach-msm/clock.h | 78 ++-------- arch/arm/mach-msm/devices.c | 338 +++++++++++++++++++++-------------------- 6 files changed, 433 insertions(+), 327 deletions(-) create mode 100644 arch/arm/mach-msm/clock-pcom.c create mode 100644 arch/arm/mach-msm/clock-pcom.h (limited to 'arch') diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 5917887300f6..109be8266be3 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -3,7 +3,7 @@ obj-y += devices.o obj-y += proc_comm.o obj-y += vreg.o mpp.o obj-y += vreg.o -obj-y += clock.o +obj-y += clock.o clock-pcom.o obj-y += gpio.o generic_gpio.o obj-y += nand_partitions.o obj-y += remote_spinlock.o modem_notifier.o diff --git a/arch/arm/mach-msm/clock-pcom.c b/arch/arm/mach-msm/clock-pcom.c new file mode 100644 index 000000000000..b22b3a71db09 --- /dev/null +++ b/arch/arm/mach-msm/clock-pcom.c @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2007-2009, Code Aurora Forum. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 "proc_comm.h" +#include "clock.h" + +/* + * glue for the proc_comm interface + */ +int pc_clk_enable(unsigned id) +{ + int rc = msm_proc_comm(PCOM_CLKCTL_RPC_ENABLE, &id, NULL); + if (rc < 0) + return rc; + else + return (int)id < 0 ? -EINVAL : 0; +} + +void pc_clk_disable(unsigned id) +{ + msm_proc_comm(PCOM_CLKCTL_RPC_DISABLE, &id, NULL); +} + +int pc_clk_set_rate(unsigned id, unsigned rate) +{ + /* The rate _might_ be rounded off to the nearest KHz value by the + * remote function. So a return value of 0 doesn't necessarily mean + * that the exact rate was set successfully. + */ + int rc = msm_proc_comm(PCOM_CLKCTL_RPC_SET_RATE, &id, &rate); + if (rc < 0) + return rc; + else + return (int)id < 0 ? -EINVAL : 0; +} + +int pc_clk_set_min_rate(unsigned id, unsigned rate) +{ + int rc = msm_proc_comm(PCOM_CLKCTL_RPC_MIN_RATE, &id, &rate); + if (rc < 0) + return rc; + else + return (int)id < 0 ? -EINVAL : 0; +} + +int pc_clk_set_max_rate(unsigned id, unsigned rate) +{ + int rc = msm_proc_comm(PCOM_CLKCTL_RPC_MAX_RATE, &id, &rate); + if (rc < 0) + return rc; + else + return (int)id < 0 ? -EINVAL : 0; +} + +int pc_clk_set_flags(unsigned id, unsigned flags) +{ + int rc = msm_proc_comm(PCOM_CLKCTL_RPC_SET_FLAGS, &id, &flags); + if (rc < 0) + return rc; + else + return (int)id < 0 ? -EINVAL : 0; +} + +unsigned pc_clk_get_rate(unsigned id) +{ + if (msm_proc_comm(PCOM_CLKCTL_RPC_RATE, &id, NULL)) + return 0; + else + return id; +} + +unsigned pc_clk_is_enabled(unsigned id) +{ + if (msm_proc_comm(PCOM_CLKCTL_RPC_ENABLED, &id, NULL)) + return 0; + else + return id; +} + +struct clk_ops clk_ops_pcom = { + .enable = pc_clk_enable, + .disable = pc_clk_disable, + .set_rate = pc_clk_set_rate, + .set_min_rate = pc_clk_set_min_rate, + .set_max_rate = pc_clk_set_max_rate, + .set_flags = pc_clk_set_flags, + .get_rate = pc_clk_get_rate, + .is_enabled = pc_clk_is_enabled, +}; diff --git a/arch/arm/mach-msm/clock-pcom.h b/arch/arm/mach-msm/clock-pcom.h new file mode 100644 index 000000000000..4799deb1e634 --- /dev/null +++ b/arch/arm/mach-msm/clock-pcom.h @@ -0,0 +1,131 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef __ARCH_ARM_MACH_MSM_CLOCK_PCOM_H +#define __ARCH_ARM_MACH_MSM_CLOCK_PCOM_H + +/* clock IDs used by the modem processor */ + +#define P_ACPU_CLK 0 /* Applications processor clock */ +#define P_ADM_CLK 1 /* Applications data mover clock */ +#define P_ADSP_CLK 2 /* ADSP clock */ +#define P_EBI1_CLK 3 /* External bus interface 1 clock */ +#define P_EBI2_CLK 4 /* External bus interface 2 clock */ +#define P_ECODEC_CLK 5 /* External CODEC clock */ +#define P_EMDH_CLK 6 /* External MDDI host clock */ +#define P_GP_CLK 7 /* General purpose clock */ +#define P_GRP_CLK 8 /* Graphics clock */ +#define P_I2C_CLK 9 /* I2C clock */ +#define P_ICODEC_RX_CLK 10 /* Internal CODEX RX clock */ +#define P_ICODEC_TX_CLK 11 /* Internal CODEX TX clock */ +#define P_IMEM_CLK 12 /* Internal graphics memory clock */ +#define P_MDC_CLK 13 /* MDDI client clock */ +#define P_MDP_CLK 14 /* Mobile display processor clock */ +#define P_PBUS_CLK 15 /* Peripheral bus clock */ +#define P_PCM_CLK 16 /* PCM clock */ +#define P_PMDH_CLK 17 /* Primary MDDI host clock */ +#define P_SDAC_CLK 18 /* Stereo DAC clock */ +#define P_SDC1_CLK 19 /* Secure Digital Card clocks */ +#define P_SDC1_PCLK 20 +#define P_SDC2_CLK 21 +#define P_SDC2_PCLK 22 +#define P_SDC3_CLK 23 +#define P_SDC3_PCLK 24 +#define P_SDC4_CLK 25 +#define P_SDC4_PCLK 26 +#define P_TSIF_CLK 27 /* Transport Stream Interface clocks */ +#define P_TSIF_REF_CLK 28 +#define P_TV_DAC_CLK 29 /* TV clocks */ +#define P_TV_ENC_CLK 30 +#define P_UART1_CLK 31 /* UART clocks */ +#define P_UART2_CLK 32 +#define P_UART3_CLK 33 +#define P_UART1DM_CLK 34 +#define P_UART2DM_CLK 35 +#define P_USB_HS_CLK 36 /* High speed USB core clock */ +#define P_USB_HS_PCLK 37 /* High speed USB pbus clock */ +#define P_USB_OTG_CLK 38 /* Full speed USB clock */ +#define P_VDC_CLK 39 /* Video controller clock */ +#define P_VFE_MDC_CLK 40 /* Camera / Video Front End clock */ +#define P_VFE_CLK 41 /* VFE MDDI client clock */ +#define P_MDP_LCDC_PCLK_CLK 42 +#define P_MDP_LCDC_PAD_PCLK_CLK 43 +#define P_MDP_VSYNC_CLK 44 +#define P_SPI_CLK 45 +#define P_VFE_AXI_CLK 46 +#define P_USB_HS2_CLK 47 /* High speed USB 2 core clock */ +#define P_USB_HS2_PCLK 48 /* High speed USB 2 pbus clock */ +#define P_USB_HS3_CLK 49 /* High speed USB 3 core clock */ +#define P_USB_HS3_PCLK 50 /* High speed USB 3 pbus clock */ +#define P_GRP_PCLK 51 /* Graphics pbus clock */ +#define P_USB_PHY_CLK 52 /* USB PHY clock */ + +#define P_NR_CLKS 53 + +struct clk_ops; +extern struct clk_ops clk_ops_pcom; + +#define CLK_PCOM(clk_name, clk_id, clk_dev, clk_flags) { \ + .name = clk_name, \ + .id = P_##clk_id, \ + .ops = &clk_ops_pcom, \ + .flags = clk_flags, \ + .dev = clk_dev, \ + .dbg_name = #clk_id, \ + } + +#endif diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c index 33fa6388186b..ca2ece0c2d53 100644 --- a/arch/arm/mach-msm/clock.c +++ b/arch/arm/mach-msm/clock.c @@ -45,90 +45,6 @@ static DECLARE_BITMAP(clock_map_enabled, NR_CLKS); static DEFINE_SPINLOCK(clock_map_lock); static struct notifier_block axi_freq_notifier_block; -/* - * glue for the proc_comm interface - */ -static inline int pc_clk_enable(unsigned id) -{ - int rc = msm_proc_comm(PCOM_CLKCTL_RPC_ENABLE, &id, NULL); - if (rc < 0) - return rc; - else - return (int)id < 0 ? -EINVAL : 0; -} - -static inline void pc_clk_disable(unsigned id) -{ - msm_proc_comm(PCOM_CLKCTL_RPC_DISABLE, &id, NULL); -} - -static inline int pc_clk_set_rate(unsigned id, unsigned rate) -{ - /* The rate _might_ be rounded off to the nearest KHz value by the - * remote function. So a return value of 0 doesn't necessarily mean - * that the exact rate was set successfully. - */ - int rc = msm_proc_comm(PCOM_CLKCTL_RPC_SET_RATE, &id, &rate); - if (rc < 0) - return rc; - else - return (int)id < 0 ? -EINVAL : 0; -} - -int pc_clk_set_min_rate(unsigned id, unsigned rate) -{ - int rc = msm_proc_comm(PCOM_CLKCTL_RPC_MIN_RATE, &id, &rate); - if (rc < 0) - return rc; - else - return (int)id < 0 ? -EINVAL : 0; -} - -static inline int pc_clk_set_max_rate(unsigned id, unsigned rate) -{ - int rc = msm_proc_comm(PCOM_CLKCTL_RPC_MAX_RATE, &id, &rate); - if (rc < 0) - return rc; - else - return (int)id < 0 ? -EINVAL : 0; -} - -static inline int pc_clk_set_flags(unsigned id, unsigned flags) -{ - int rc = msm_proc_comm(PCOM_CLKCTL_RPC_SET_FLAGS, &id, &flags); - if (rc < 0) - return rc; - else - return (int)id < 0 ? -EINVAL : 0; -} - -static inline unsigned pc_clk_get_rate(unsigned id) -{ - if (msm_proc_comm(PCOM_CLKCTL_RPC_RATE, &id, NULL)) - return 0; - else - return id; -} - -static inline unsigned pc_clk_is_enabled(unsigned id) -{ - if (msm_proc_comm(PCOM_CLKCTL_RPC_ENABLED, &id, NULL)) - return 0; - else - return id; -} - -static inline int pc_pll_request(unsigned id, unsigned on) -{ - int rc; - on = !!on; - rc = msm_proc_comm(PCOM_CLKCTL_RPC_PLL_REQUEST, &id, &on); - if (rc < 0) - return rc; - else - return (int)id < 0 ? -EINVAL : 0; -} - /* * Standard clock functions defined in include/linux/clk.h */ @@ -164,7 +80,7 @@ int clk_enable(struct clk *clk) spin_lock_irqsave(&clocks_lock, flags); clk->count++; if (clk->count == 1) { - pc_clk_enable(clk->id); + clk->ops->enable(clk->id); spin_lock(&clock_map_lock); clock_map_enabled[BIT_WORD(clk->id)] |= BIT_MASK(clk->id); spin_unlock(&clock_map_lock); @@ -181,7 +97,7 @@ void clk_disable(struct clk *clk) BUG_ON(clk->count == 0); clk->count--; if (clk->count == 0) { - pc_clk_disable(clk->id); + clk->ops->disable(clk->id); spin_lock(&clock_map_lock); clock_map_enabled[BIT_WORD(clk->id)] &= ~BIT_MASK(clk->id); spin_unlock(&clock_map_lock); @@ -192,25 +108,25 @@ EXPORT_SYMBOL(clk_disable); unsigned long clk_get_rate(struct clk *clk) { - return pc_clk_get_rate(clk->id); + return clk->ops->get_rate(clk->id); } EXPORT_SYMBOL(clk_get_rate); int clk_set_rate(struct clk *clk, unsigned long rate) { - return pc_clk_set_rate(clk->id, rate); + return clk->ops->set_rate(clk->id, rate); } EXPORT_SYMBOL(clk_set_rate); int clk_set_min_rate(struct clk *clk, unsigned long rate) { - return pc_clk_set_min_rate(clk->id, rate); + return clk->ops->set_min_rate(clk->id, rate); } EXPORT_SYMBOL(clk_set_min_rate); int clk_set_max_rate(struct clk *clk, unsigned long rate) { - return pc_clk_set_max_rate(clk->id, rate); + return clk->ops->set_max_rate(clk->id, rate); } EXPORT_SYMBOL(clk_set_max_rate); @@ -230,7 +146,7 @@ int clk_set_flags(struct clk *clk, unsigned long flags) { if (clk == NULL || IS_ERR(clk)) return -EINVAL; - return pc_clk_set_flags(clk->id, flags); + return clk->ops->set_flags(clk->id, flags); } EXPORT_SYMBOL(clk_set_flags); @@ -398,9 +314,9 @@ static int clock_debug_enable_set(void *data, u64 val) int rc = 0; if (val) - rc = pc_clk_enable(clock->id); + rc = clock->ops->enable(clock->id); else - pc_clk_disable(clock->id); + clock->ops->disable(clock->id); return rc; } @@ -409,7 +325,7 @@ static int clock_debug_enable_get(void *data, u64 *val) { struct clk *clock = data; - *val = pc_clk_is_enabled(clock->id); + *val = clock->ops->is_enabled(clock->id); return 0; } @@ -466,7 +382,7 @@ static int __init clock_late_init(void) spin_lock_irqsave(&clocks_lock, flags); if (!clk->count) { count++; - pc_clk_disable(clk->id); + clk->ops->disable(clk->id); } spin_unlock_irqrestore(&clocks_lock, flags); } diff --git a/arch/arm/mach-msm/clock.h b/arch/arm/mach-msm/clock.h index 4cb65ac834b4..194d319b62b0 100644 --- a/arch/arm/mach-msm/clock.h +++ b/arch/arm/mach-msm/clock.h @@ -19,6 +19,8 @@ #include +#include "clock-pcom.h" + #define CLKFLAG_INVERT 0x00000001 #define CLKFLAG_NOINVERT 0x00000002 #define CLKFLAG_NONEST 0x00000004 @@ -29,14 +31,24 @@ #define CLKFLAG_MIN 0x00000400 #define CLKFLAG_MAX 0x00000800 +struct clk_ops { + int (*enable)(unsigned id); + void (*disable)(unsigned id); + int (*set_rate)(unsigned id, unsigned rate); + int (*set_min_rate)(unsigned id, unsigned rate); + int (*set_max_rate)(unsigned id, unsigned rate); + int (*set_flags)(unsigned id, unsigned flags); + unsigned (*get_rate)(unsigned id); + unsigned (*is_enabled)(unsigned id); +}; + struct clk { uint32_t id; uint32_t count; uint32_t flags; const char *name; -#ifdef CONFIG_DEBUG_FS + struct clk_ops *ops; const char *dbg_name; -#endif struct list_head list; struct device *dev; }; @@ -45,67 +57,6 @@ struct clk { #define A11S_CLK_SEL_ADDR (MSM_CSR_BASE + 0x104) #define A11S_VDD_SVS_PLEVEL_ADDR (MSM_CSR_BASE + 0x124) -/* clock IDs used by the modem processor */ - -#define ACPU_CLK 0 /* Applications processor clock */ -#define ADM_CLK 1 /* Applications data mover clock */ -#define ADSP_CLK 2 /* ADSP clock */ -#define EBI1_CLK 3 /* External bus interface 1 clock */ -#define EBI2_CLK 4 /* External bus interface 2 clock */ -#define ECODEC_CLK 5 /* External CODEC clock */ -#define EMDH_CLK 6 /* External MDDI host clock */ -#define GP_CLK 7 /* General purpose clock */ -#define GRP_CLK 8 /* Graphics clock */ -#define I2C_CLK 9 /* I2C clock */ -#define ICODEC_RX_CLK 10 /* Internal CODEX RX clock */ -#define ICODEC_TX_CLK 11 /* Internal CODEX TX clock */ -#define IMEM_CLK 12 /* Internal graphics memory clock */ -#define MDC_CLK 13 /* MDDI client clock */ -#define MDP_CLK 14 /* Mobile display processor clock */ -#define PBUS_CLK 15 /* Peripheral bus clock */ -#define PCM_CLK 16 /* PCM clock */ -#define PMDH_CLK 17 /* Primary MDDI host clock */ -#define SDAC_CLK 18 /* Stereo DAC clock */ -#define SDC1_CLK 19 /* Secure Digital Card clocks */ -#define SDC1_PCLK 20 -#define SDC2_CLK 21 -#define SDC2_PCLK 22 -#define SDC3_CLK 23 -#define SDC3_PCLK 24 -#define SDC4_CLK 25 -#define SDC4_PCLK 26 -#define TSIF_CLK 27 /* Transport Stream Interface clocks */ -#define TSIF_REF_CLK 28 -#define TV_DAC_CLK 29 /* TV clocks */ -#define TV_ENC_CLK 30 -#define UART1_CLK 31 /* UART clocks */ -#define UART2_CLK 32 -#define UART3_CLK 33 -#define UART1DM_CLK 34 -#define UART2DM_CLK 35 -#define USB_HS_CLK 36 /* High speed USB core clock */ -#define USB_HS_PCLK 37 /* High speed USB pbus clock */ -#define USB_OTG_CLK 38 /* Full speed USB clock */ -#define VDC_CLK 39 /* Video controller clock */ -#define VFE_MDC_CLK 40 /* Camera / Video Front End clock */ -#define VFE_CLK 41 /* VFE MDDI client clock */ - -#define MDP_LCDC_PCLK_CLK 42 -#define MDP_LCDC_PAD_PCLK_CLK 43 -#define MDP_VSYNC_CLK 44 - -#define SPI_CLK 45 -#define VFE_AXI_CLK 46 - -#define USB_HS2_CLK 47 /* High speed USB 2 core clock */ -#define USB_HS2_PCLK 48 /* High speed USB 2 pbus clock */ -#define USB_HS3_CLK 49 /* High speed USB 3 core clock */ -#define USB_HS3_PCLK 50 /* High speed USB 3 pbus clock */ - -#define GRP_PCLK 51 /* Graphics pbus clock */ - -#define NR_CLKS 52 - #ifdef CONFIG_DEBUG_FS #define CLOCK_DBG_NAME(x) .dbg_name = x, #else @@ -124,6 +75,7 @@ struct clk { #define CLK_MIN CLKFLAG_MIN #define CLK_MAX CLKFLAG_MAX #define CLK_MINMAX (CLK_MIN | CLK_MAX) +#define NR_CLKS P_NR_CLKS enum clkvote_client { CLKVOTE_ACPUCLK = 0, diff --git a/arch/arm/mach-msm/devices.c b/arch/arm/mach-msm/devices.c index fd51b134a6a6..04d19b3d098d 100644 --- a/arch/arm/mach-msm/devices.c +++ b/arch/arm/mach-msm/devices.c @@ -402,189 +402,191 @@ void __init msm_camera_register_device(void *res, uint32_t num, } struct clk msm_clocks_7x01a[] = { - CLOCK("adm_clk", ADM_CLK, NULL, 0), - CLOCK("adsp_clk", ADSP_CLK, NULL, 0), - CLOCK("ebi1_clk", EBI1_CLK, NULL, CLK_MIN), - CLOCK("ebi2_clk", EBI2_CLK, NULL, 0), - CLOCK("ecodec_clk", ECODEC_CLK, NULL, 0), - CLOCK("emdh_clk", EMDH_CLK, NULL, OFF | CLK_MINMAX), - CLOCK("gp_clk", GP_CLK, NULL, 0), - CLOCK("grp_clk", GRP_CLK, NULL, OFF), - CLOCK("i2c_clk", I2C_CLK, &msm_device_i2c.dev, 0), - CLOCK("icodec_rx_clk", ICODEC_RX_CLK, NULL, 0), - CLOCK("icodec_tx_clk", ICODEC_TX_CLK, NULL, 0), - CLOCK("imem_clk", IMEM_CLK, NULL, OFF), - CLOCK("mdc_clk", MDC_CLK, NULL, 0), - CLOCK("mdp_clk", MDP_CLK, NULL, OFF), - CLOCK("pbus_clk", PBUS_CLK, NULL, CLK_MIN), - CLOCK("pcm_clk", PCM_CLK, NULL, 0), - CLOCK("mddi_clk", PMDH_CLK, NULL, OFF | CLK_MINMAX), - CLOCK("sdac_clk", SDAC_CLK, NULL, OFF), - CLOCK("sdc_clk", SDC1_CLK, &msm_device_sdc1.dev, OFF), - CLOCK("sdc_pclk", SDC1_PCLK, &msm_device_sdc1.dev, OFF), - CLOCK("sdc_clk", SDC2_CLK, &msm_device_sdc2.dev, OFF), - CLOCK("sdc_pclk", SDC2_PCLK, &msm_device_sdc2.dev, OFF), - CLOCK("sdc_clk", SDC3_CLK, &msm_device_sdc3.dev, OFF), - CLOCK("sdc_pclk", SDC3_PCLK, &msm_device_sdc3.dev, OFF), - CLOCK("sdc_clk", SDC4_CLK, &msm_device_sdc4.dev, OFF), - CLOCK("sdc_pclk", SDC4_PCLK, &msm_device_sdc4.dev, OFF), - CLOCK("tsif_clk", TSIF_CLK, NULL, 0), - CLOCK("tsif_ref_clk", TSIF_REF_CLK, NULL, 0), - CLOCK("tv_dac_clk", TV_DAC_CLK, NULL, 0), - CLOCK("tv_enc_clk", TV_ENC_CLK, NULL, 0), - CLOCK("uart_clk", UART1_CLK, &msm_device_uart1.dev, OFF), - CLOCK("uart_clk", UART2_CLK, &msm_device_uart2.dev, 0), - CLOCK("uart_clk", UART3_CLK, &msm_device_uart3.dev, OFF), - CLOCK("uartdm_clk", UART1DM_CLK, &msm_device_uart_dm1.dev, OFF), - CLOCK("uartdm_clk", UART2DM_CLK, &msm_device_uart_dm2.dev, 0), - CLOCK("usb_hs_clk", USB_HS_CLK, NULL, OFF), - CLOCK("usb_hs_pclk", USB_HS_PCLK, NULL, OFF), - CLOCK("usb_otg_clk", USB_OTG_CLK, NULL, 0), - CLOCK("vdc_clk", VDC_CLK, NULL, OFF | CLK_MIN), - CLOCK("vfe_clk", VFE_CLK, NULL, OFF), - CLOCK("vfe_mdc_clk", VFE_MDC_CLK, NULL, OFF), + CLK_PCOM("adm_clk", ADM_CLK, NULL, 0), + CLK_PCOM("adsp_clk", ADSP_CLK, NULL, 0), + CLK_PCOM("ebi1_clk", EBI1_CLK, NULL, CLK_MIN), + CLK_PCOM("ebi2_clk", EBI2_CLK, NULL, 0), + CLK_PCOM("ecodec_clk", ECODEC_CLK, NULL, 0), + CLK_PCOM("emdh_clk", EMDH_CLK, NULL, OFF | CLK_MINMAX), + CLK_PCOM("gp_clk", GP_CLK, NULL, 0), + CLK_PCOM("grp_clk", GRP_CLK, NULL, OFF), + CLK_PCOM("i2c_clk", I2C_CLK, &msm_device_i2c.dev, 0), + CLK_PCOM("icodec_rx_clk", ICODEC_RX_CLK, NULL, 0), + CLK_PCOM("icodec_tx_clk", ICODEC_TX_CLK, NULL, 0), + CLK_PCOM("imem_clk", IMEM_CLK, NULL, OFF), + CLK_PCOM("mdc_clk", MDC_CLK, NULL, 0), + CLK_PCOM("mdp_clk", MDP_CLK, NULL, OFF), + CLK_PCOM("pbus_clk", PBUS_CLK, NULL, CLK_MIN), + CLK_PCOM("pcm_clk", PCM_CLK, NULL, 0), + CLK_PCOM("mddi_clk", PMDH_CLK, NULL, OFF | CLK_MINMAX), + CLK_PCOM("sdac_clk", SDAC_CLK, NULL, OFF), + CLK_PCOM("sdc_clk", SDC1_CLK, &msm_device_sdc1.dev, OFF), + CLK_PCOM("sdc_pclk", SDC1_PCLK, &msm_device_sdc1.dev, OFF), + CLK_PCOM("sdc_clk", SDC2_CLK, &msm_device_sdc2.dev, OFF), + CLK_PCOM("sdc_pclk", SDC2_PCLK, &msm_device_sdc2.dev, OFF), + CLK_PCOM("sdc_clk", SDC3_CLK, &msm_device_sdc3.dev, OFF), + CLK_PCOM("sdc_pclk", SDC3_PCLK, &msm_device_sdc3.dev, OFF), + CLK_PCOM("sdc_clk", SDC4_CLK, &msm_device_sdc4.dev, OFF), + CLK_PCOM("sdc_pclk", SDC4_PCLK, &msm_device_sdc4.dev, OFF), + CLK_PCOM("tsif_clk", TSIF_CLK, NULL, 0), + CLK_PCOM("tsif_ref_clk", TSIF_REF_CLK, NULL, 0), + CLK_PCOM("tv_dac_clk", TV_DAC_CLK, NULL, 0), + CLK_PCOM("tv_enc_clk", TV_ENC_CLK, NULL, 0), + CLK_PCOM("uart_clk", UART1_CLK, &msm_device_uart1.dev, OFF), + CLK_PCOM("uart_clk", UART2_CLK, &msm_device_uart2.dev, 0), + CLK_PCOM("uart_clk", UART3_CLK, &msm_device_uart3.dev, OFF), + CLK_PCOM("uartdm_clk", UART1DM_CLK, &msm_device_uart_dm1.dev, OFF), + CLK_PCOM("uartdm_clk", UART2DM_CLK, &msm_device_uart_dm2.dev, 0), + CLK_PCOM("usb_hs_clk", USB_HS_CLK, NULL, OFF), + CLK_PCOM("usb_hs_pclk", USB_HS_PCLK, NULL, OFF), + CLK_PCOM("usb_otg_clk", USB_OTG_CLK, NULL, 0), + CLK_PCOM("vdc_clk", VDC_CLK, NULL, OFF | CLK_MIN), + CLK_PCOM("vfe_clk", VFE_CLK, NULL, OFF), + CLK_PCOM("vfe_mdc_clk", VFE_MDC_CLK, NULL, OFF), + CLK_PCOM("grp_pclk", GRP_PCLK, NULL, 0), }; unsigned msm_num_clocks_7x01a = ARRAY_SIZE(msm_clocks_7x01a); struct clk msm_clocks_7x25[] = { - CLOCK("adm_clk", ADM_CLK, NULL, 0), - CLOCK("adsp_clk", ADSP_CLK, NULL, 0), - CLOCK("ebi1_clk", EBI1_CLK, NULL, CLK_MIN), - CLOCK("ebi2_clk", EBI2_CLK, NULL, 0), - CLOCK("ecodec_clk", ECODEC_CLK, NULL, 0), - CLOCK("gp_clk", GP_CLK, NULL, 0), - CLOCK("i2c_clk", I2C_CLK, &msm_device_i2c.dev, 0), - CLOCK("icodec_rx_clk", ICODEC_RX_CLK, NULL, 0), - CLOCK("icodec_tx_clk", ICODEC_TX_CLK, NULL, 0), - CLOCK("imem_clk", IMEM_CLK, NULL, OFF), - CLOCK("mdc_clk", MDC_CLK, NULL, 0), - CLOCK("mdp_clk", MDP_CLK, NULL, OFF), - CLOCK("mdp_lcdc_pclk_clk", MDP_LCDC_PCLK_CLK, NULL, 0), - CLOCK("mdp_lcdc_pad_pclk_clk", MDP_LCDC_PAD_PCLK_CLK, NULL, 0), - CLOCK("mdp_vsync_clk", MDP_VSYNC_CLK, NULL, 0), - CLOCK("pbus_clk", PBUS_CLK, NULL, CLK_MIN), - CLOCK("pcm_clk", PCM_CLK, NULL, 0), - CLOCK("mddi_clk", PMDH_CLK, NULL, OFF | CLK_MINMAX), - CLOCK("sdac_clk", SDAC_CLK, NULL, OFF), - CLOCK("sdc_clk", SDC1_CLK, &msm_device_sdc1.dev, OFF), - CLOCK("sdc_pclk", SDC1_PCLK, &msm_device_sdc1.dev, OFF), - CLOCK("sdc_clk", SDC2_CLK, &msm_device_sdc2.dev, OFF), - CLOCK("sdc_pclk", SDC2_PCLK, &msm_device_sdc2.dev, OFF), - CLOCK("sdc_clk", SDC3_CLK, &msm_device_sdc3.dev, OFF), - CLOCK("sdc_pclk", SDC3_PCLK, &msm_device_sdc3.dev, OFF), - CLOCK("sdc_clk", SDC4_CLK, &msm_device_sdc4.dev, OFF), - CLOCK("sdc_pclk", SDC4_PCLK, &msm_device_sdc4.dev, OFF), - CLOCK("uart_clk", UART1_CLK, &msm_device_uart1.dev, OFF), - CLOCK("uart_clk", UART2_CLK, &msm_device_uart2.dev, 0), - CLOCK("uart_clk", UART3_CLK, &msm_device_uart3.dev, OFF), - CLOCK("uartdm_clk", UART1DM_CLK, &msm_device_uart_dm1.dev, OFF), - CLOCK("uartdm_clk", UART2DM_CLK, &msm_device_uart_dm2.dev, 0), - CLOCK("usb_hs_clk", USB_HS_CLK, NULL, OFF), - CLOCK("usb_hs_pclk", USB_HS_PCLK, NULL, OFF), - CLOCK("usb_otg_clk", USB_OTG_CLK, NULL, 0), - CLOCK("vdc_clk", VDC_CLK, NULL, OFF | CLK_MIN), - CLOCK("vfe_clk", VFE_CLK, NULL, OFF), - CLOCK("vfe_mdc_clk", VFE_MDC_CLK, NULL, OFF), + CLK_PCOM("adm_clk", ADM_CLK, NULL, 0), + CLK_PCOM("adsp_clk", ADSP_CLK, NULL, 0), + CLK_PCOM("ebi1_clk", EBI1_CLK, NULL, CLK_MIN), + CLK_PCOM("ebi2_clk", EBI2_CLK, NULL, 0), + CLK_PCOM("ecodec_clk", ECODEC_CLK, NULL, 0), + CLK_PCOM("gp_clk", GP_CLK, NULL, 0), + CLK_PCOM("i2c_clk", I2C_CLK, &msm_device_i2c.dev, 0), + CLK_PCOM("icodec_rx_clk", ICODEC_RX_CLK, NULL, 0), + CLK_PCOM("icodec_tx_clk", ICODEC_TX_CLK, NULL, 0), + CLK_PCOM("imem_clk", IMEM_CLK, NULL, OFF), + CLK_PCOM("mdc_clk", MDC_CLK, NULL, 0), + CLK_PCOM("mdp_clk", MDP_CLK, NULL, OFF), + CLK_PCOM("mdp_lcdc_pclk_clk", MDP_LCDC_PCLK_CLK, NULL, 0), + CLK_PCOM("mdp_lcdc_pad_pclk_clk", MDP_LCDC_PAD_PCLK_CLK, NULL, 0), + CLK_PCOM("mdp_vsync_clk", MDP_VSYNC_CLK, NULL, 0), + CLK_PCOM("pbus_clk", PBUS_CLK, NULL, CLK_MIN), + CLK_PCOM("pcm_clk", PCM_CLK, NULL, 0), + CLK_PCOM("mddi_clk", PMDH_CLK, NULL, OFF | CLK_MINMAX), + CLK_PCOM("sdac_clk", SDAC_CLK, NULL, OFF), + CLK_PCOM("sdc_clk", SDC1_CLK, &msm_device_sdc1.dev, OFF), + CLK_PCOM("sdc_pclk", SDC1_PCLK, &msm_device_sdc1.dev, OFF), + CLK_PCOM("sdc_clk", SDC2_CLK, &msm_device_sdc2.dev, OFF), + CLK_PCOM("sdc_pclk", SDC2_PCLK, &msm_device_sdc2.dev, OFF), + CLK_PCOM("sdc_clk", SDC3_CLK, &msm_device_sdc3.dev, OFF), + CLK_PCOM("sdc_pclk", SDC3_PCLK, &msm_device_sdc3.dev, OFF), + CLK_PCOM("sdc_clk", SDC4_CLK, &msm_device_sdc4.dev, OFF), + CLK_PCOM("sdc_pclk", SDC4_PCLK, &msm_device_sdc4.dev, OFF), + CLK_PCOM("uart_clk", UART1_CLK, &msm_device_uart1.dev, OFF), + CLK_PCOM("uart_clk", UART2_CLK, &msm_device_uart2.dev, 0), + CLK_PCOM("uart_clk", UART3_CLK, &msm_device_uart3.dev, OFF), + CLK_PCOM("uartdm_clk", UART1DM_CLK, &msm_device_uart_dm1.dev, OFF), + CLK_PCOM("uartdm_clk", UART2DM_CLK, &msm_device_uart_dm2.dev, 0), + CLK_PCOM("usb_hs_clk", USB_HS_CLK, NULL, OFF), + CLK_PCOM("usb_hs_pclk", USB_HS_PCLK, NULL, OFF), + CLK_PCOM("usb_otg_clk", USB_OTG_CLK, NULL, 0), + CLK_PCOM("vdc_clk", VDC_CLK, NULL, OFF | CLK_MIN), + CLK_PCOM("vfe_clk", VFE_CLK, NULL, OFF), + CLK_PCOM("vfe_mdc_clk", VFE_MDC_CLK, NULL, OFF), + CLK_PCOM("grp_pclk", GRP_PCLK, NULL, 0), }; unsigned msm_num_clocks_7x25 = ARRAY_SIZE(msm_clocks_7x25); struct clk msm_clocks_7x27[] = { - CLOCK("adm_clk", ADM_CLK, NULL, 0), - CLOCK("adsp_clk", ADSP_CLK, NULL, 0), - CLOCK("ebi1_clk", EBI1_CLK, NULL, CLK_MIN), - CLOCK("ebi2_clk", EBI2_CLK, NULL, 0), - CLOCK("ecodec_clk", ECODEC_CLK, NULL, 0), - CLOCK("gp_clk", GP_CLK, NULL, 0), - CLOCK("grp_clk", GRP_CLK, NULL, 0), - CLOCK("i2c_clk", I2C_CLK, &msm_device_i2c.dev, 0), - CLOCK("icodec_rx_clk", ICODEC_RX_CLK, NULL, 0), - CLOCK("icodec_tx_clk", ICODEC_TX_CLK, NULL, 0), - CLOCK("imem_clk", IMEM_CLK, NULL, OFF), - CLOCK("mdc_clk", MDC_CLK, NULL, 0), - CLOCK("mdp_clk", MDP_CLK, NULL, OFF), - CLOCK("mdp_lcdc_pclk_clk", MDP_LCDC_PCLK_CLK, NULL, 0), - CLOCK("mdp_lcdc_pad_pclk_clk", MDP_LCDC_PAD_PCLK_CLK, NULL, 0), - CLOCK("mdp_vsync_clk", MDP_VSYNC_CLK, NULL, 0), - CLOCK("pbus_clk", PBUS_CLK, NULL, CLK_MIN), - CLOCK("pcm_clk", PCM_CLK, NULL, 0), - CLOCK("mddi_clk", PMDH_CLK, NULL, OFF | CLK_MINMAX), - CLOCK("sdac_clk", SDAC_CLK, NULL, OFF), - CLOCK("sdc_clk", SDC1_CLK, &msm_device_sdc1.dev, OFF), - CLOCK("sdc_pclk", SDC1_PCLK, &msm_device_sdc1.dev, OFF), - CLOCK("sdc_clk", SDC2_CLK, &msm_device_sdc2.dev, OFF), - CLOCK("sdc_pclk", SDC2_PCLK, &msm_device_sdc2.dev, OFF), - CLOCK("sdc_clk", SDC3_CLK, &msm_device_sdc3.dev, OFF), - CLOCK("sdc_pclk", SDC3_PCLK, &msm_device_sdc3.dev, OFF), - CLOCK("sdc_clk", SDC4_CLK, &msm_device_sdc4.dev, OFF), - CLOCK("sdc_pclk", SDC4_PCLK, &msm_device_sdc4.dev, OFF), - CLOCK("uart_clk", UART1_CLK, &msm_device_uart1.dev, OFF), - CLOCK("uart_clk", UART2_CLK, &msm_device_uart2.dev, 0), - CLOCK("uart_clk", UART3_CLK, &msm_device_uart3.dev, OFF), - CLOCK("uartdm_clk", UART1DM_CLK, &msm_device_uart_dm1.dev, OFF), - CLOCK("uartdm_clk", UART2DM_CLK, &msm_device_uart_dm2.dev, 0), - CLOCK("usb_hs_clk", USB_HS_CLK, NULL, OFF), - CLOCK("usb_hs_pclk", USB_HS_PCLK, NULL, OFF), - CLOCK("usb_otg_clk", USB_OTG_CLK, NULL, 0), - CLOCK("vdc_clk", VDC_CLK, NULL, OFF | CLK_MIN), - CLOCK("vfe_clk", VFE_CLK, NULL, OFF), - CLOCK("vfe_mdc_clk", VFE_MDC_CLK, NULL, OFF), - CLOCK("grp_pclk", GRP_PCLK, NULL, 0), + CLK_PCOM("adm_clk", ADM_CLK, NULL, 0), + CLK_PCOM("adsp_clk", ADSP_CLK, NULL, 0), + CLK_PCOM("ebi1_clk", EBI1_CLK, NULL, CLK_MIN), + CLK_PCOM("ebi2_clk", EBI2_CLK, NULL, 0), + CLK_PCOM("ecodec_clk", ECODEC_CLK, NULL, 0), + CLK_PCOM("gp_clk", GP_CLK, NULL, 0), + CLK_PCOM("grp_clk", GRP_CLK, NULL, 0), + CLK_PCOM("i2c_clk", I2C_CLK, &msm_device_i2c.dev, 0), + CLK_PCOM("icodec_rx_clk", ICODEC_RX_CLK, NULL, 0), + CLK_PCOM("icodec_tx_clk", ICODEC_TX_CLK, NULL, 0), + CLK_PCOM("imem_clk", IMEM_CLK, NULL, OFF), + CLK_PCOM("mdc_clk", MDC_CLK, NULL, 0), + CLK_PCOM("mdp_clk", MDP_CLK, NULL, OFF), + CLK_PCOM("mdp_lcdc_pclk_clk", MDP_LCDC_PCLK_CLK, NULL, 0), + CLK_PCOM("mdp_lcdc_pad_pclk_clk", MDP_LCDC_PAD_PCLK_CLK, NULL, 0), + CLK_PCOM("mdp_vsync_clk", MDP_VSYNC_CLK, NULL, 0), + CLK_PCOM("pbus_clk", PBUS_CLK, NULL, CLK_MIN), + CLK_PCOM("pcm_clk", PCM_CLK, NULL, 0), + CLK_PCOM("mddi_clk", PMDH_CLK, NULL, OFF | CLK_MINMAX), + CLK_PCOM("sdac_clk", SDAC_CLK, NULL, OFF), + CLK_PCOM("sdc_clk", SDC1_CLK, &msm_device_sdc1.dev, OFF), + CLK_PCOM("sdc_pclk", SDC1_PCLK, &msm_device_sdc1.dev, OFF), + CLK_PCOM("sdc_clk", SDC2_CLK, &msm_device_sdc2.dev, OFF), + CLK_PCOM("sdc_pclk", SDC2_PCLK, &msm_device_sdc2.dev, OFF), + CLK_PCOM("sdc_clk", SDC3_CLK, &msm_device_sdc3.dev, OFF), + CLK_PCOM("sdc_pclk", SDC3_PCLK, &msm_device_sdc3.dev, OFF), + CLK_PCOM("sdc_clk", SDC4_CLK, &msm_device_sdc4.dev, OFF), + CLK_PCOM("sdc_pclk", SDC4_PCLK, &msm_device_sdc4.dev, OFF), + CLK_PCOM("uart_clk", UART1_CLK, &msm_device_uart1.dev, OFF), + CLK_PCOM("uart_clk", UART2_CLK, &msm_device_uart2.dev, 0), + CLK_PCOM("uart_clk", UART3_CLK, &msm_device_uart3.dev, OFF), + CLK_PCOM("uartdm_clk", UART1DM_CLK, &msm_device_uart_dm1.dev, OFF), + CLK_PCOM("uartdm_clk", UART2DM_CLK, &msm_device_uart_dm2.dev, 0), + CLK_PCOM("usb_hs_clk", USB_HS_CLK, NULL, OFF), + CLK_PCOM("usb_hs_pclk", USB_HS_PCLK, NULL, OFF), + CLK_PCOM("usb_otg_clk", USB_OTG_CLK, NULL, 0), + CLK_PCOM("vdc_clk", VDC_CLK, NULL, OFF | CLK_MIN), + CLK_PCOM("vfe_clk", VFE_CLK, NULL, OFF), + CLK_PCOM("vfe_mdc_clk", VFE_MDC_CLK, NULL, OFF), }; unsigned msm_num_clocks_7x27 = ARRAY_SIZE(msm_clocks_7x27); struct clk msm_clocks_8x50[] = { - CLOCK("adm_clk", ADM_CLK, NULL, 0), - CLOCK("ebi1_clk", EBI1_CLK, NULL, CLK_MIN), - CLOCK("ebi2_clk", EBI2_CLK, NULL, 0), - CLOCK("ecodec_clk", ECODEC_CLK, NULL, 0), - CLOCK("emdh_clk", EMDH_CLK, NULL, OFF | CLK_MINMAX), - CLOCK("gp_clk", GP_CLK, NULL, 0), - CLOCK("grp_clk", GRP_CLK, NULL, 0), - CLOCK("i2c_clk", I2C_CLK, &msm_device_i2c.dev, 0), - CLOCK("icodec_rx_clk", ICODEC_RX_CLK, NULL, 0), - CLOCK("icodec_tx_clk", ICODEC_TX_CLK, NULL, 0), - CLOCK("imem_clk", IMEM_CLK, NULL, OFF), - CLOCK("mdc_clk", MDC_CLK, NULL, 0), - CLOCK("mddi_clk", PMDH_CLK, NULL, OFF | CLK_MINMAX), - CLOCK("mdp_clk", MDP_CLK, NULL, OFF), - CLOCK("mdp_lcdc_pclk_clk", MDP_LCDC_PCLK_CLK, NULL, 0), - CLOCK("mdp_lcdc_pad_pclk_clk", MDP_LCDC_PAD_PCLK_CLK, NULL, 0), - CLOCK("mdp_vsync_clk", MDP_VSYNC_CLK, NULL, 0), - CLOCK("pbus_clk", PBUS_CLK, NULL, CLK_MIN), - CLOCK("pcm_clk", PCM_CLK, NULL, 0), - CLOCK("sdac_clk", SDAC_CLK, NULL, OFF), - CLOCK("sdc_clk", SDC1_CLK, &msm_device_sdc1.dev, OFF), - CLOCK("sdc_pclk", SDC1_PCLK, &msm_device_sdc1.dev, OFF), - CLOCK("sdc_clk", SDC2_CLK, &msm_device_sdc2.dev, OFF), - CLOCK("sdc_pclk", SDC2_PCLK, &msm_device_sdc2.dev, OFF), - CLOCK("sdc_clk", SDC3_CLK, &msm_device_sdc3.dev, OFF), - CLOCK("sdc_pclk", SDC3_PCLK, &msm_device_sdc3.dev, OFF), - CLOCK("sdc_clk", SDC4_CLK, &msm_device_sdc4.dev, OFF), - CLOCK("sdc_pclk", SDC4_PCLK, &msm_device_sdc4.dev, OFF), - CLOCK("spi_clk", SPI_CLK, NULL, 0), - CLOCK("tsif_clk", TSIF_CLK, NULL, 0), - CLOCK("tsif_ref_clk", TSIF_REF_CLK, NULL, 0), - CLOCK("tv_dac_clk", TV_DAC_CLK, NULL, 0), - CLOCK("tv_enc_clk", TV_ENC_CLK, NULL, 0), - CLOCK("uart_clk", UART1_CLK, &msm_device_uart1.dev, OFF), - CLOCK("uart_clk", UART2_CLK, &msm_device_uart2.dev, 0), - CLOCK("uart_clk", UART3_CLK, &msm_device_uart3.dev, OFF), - CLOCK("uartdm_clk", UART1DM_CLK, &msm_device_uart_dm1.dev, OFF), - CLOCK("uartdm_clk", UART2DM_CLK, &msm_device_uart_dm2.dev, 0), - CLOCK("usb_hs_clk", USB_HS_CLK, NULL, OFF), - CLOCK("usb_hs_pclk", USB_HS_PCLK, NULL, OFF), - CLOCK("usb_otg_clk", USB_OTG_CLK, NULL, 0), - CLOCK("vdc_clk", VDC_CLK, NULL, OFF | CLK_MIN), - CLOCK("vfe_clk", VFE_CLK, NULL, OFF), - CLOCK("vfe_mdc_clk", VFE_MDC_CLK, NULL, OFF), - CLOCK("vfe_axi_clk", VFE_AXI_CLK, NULL, OFF), - CLOCK("usb_hs2_clk", USB_HS2_CLK, NULL, OFF), - CLOCK("usb_hs2_pclk", USB_HS2_PCLK, NULL, OFF), - CLOCK("usb_hs3_clk", USB_HS3_CLK, NULL, OFF), - CLOCK("usb_hs3_pclk", USB_HS3_PCLK, NULL, OFF), + CLK_PCOM("adm_clk", ADM_CLK, NULL, 0), + CLK_PCOM("ebi1_clk", EBI1_CLK, NULL, CLK_MIN), + CLK_PCOM("ebi2_clk", EBI2_CLK, NULL, 0), + CLK_PCOM("ecodec_clk", ECODEC_CLK, NULL, 0), + CLK_PCOM("emdh_clk", EMDH_CLK, NULL, OFF | CLK_MINMAX), + CLK_PCOM("gp_clk", GP_CLK, NULL, 0), + CLK_PCOM("grp_clk", GRP_CLK, NULL, 0), + CLK_PCOM("i2c_clk", I2C_CLK, &msm_device_i2c.dev, 0), + CLK_PCOM("icodec_rx_clk", ICODEC_RX_CLK, NULL, 0), + CLK_PCOM("icodec_tx_clk", ICODEC_TX_CLK, NULL, 0), + CLK_PCOM("imem_clk", IMEM_CLK, NULL, OFF), + CLK_PCOM("mdc_clk", MDC_CLK, NULL, 0), + CLK_PCOM("mddi_clk", PMDH_CLK, NULL, OFF | CLK_MINMAX), + CLK_PCOM("mdp_clk", MDP_CLK, NULL, OFF), + CLK_PCOM("mdp_lcdc_pclk_clk", MDP_LCDC_PCLK_CLK, NULL, 0), + CLK_PCOM("mdp_lcdc_pad_pclk_clk", MDP_LCDC_PAD_PCLK_CLK, NULL, 0), + CLK_PCOM("mdp_vsync_clk", MDP_VSYNC_CLK, NULL, 0), + CLK_PCOM("pbus_clk", PBUS_CLK, NULL, CLK_MIN), + CLK_PCOM("pcm_clk", PCM_CLK, NULL, 0), + CLK_PCOM("sdac_clk", SDAC_CLK, NULL, OFF), + CLK_PCOM("sdc_clk", SDC1_CLK, &msm_device_sdc1.dev, OFF), + CLK_PCOM("sdc_pclk", SDC1_PCLK, &msm_device_sdc1.dev, OFF), + CLK_PCOM("sdc_clk", SDC2_CLK, &msm_device_sdc2.dev, OFF), + CLK_PCOM("sdc_pclk", SDC2_PCLK, &msm_device_sdc2.dev, OFF), + CLK_PCOM("sdc_clk", SDC3_CLK, &msm_device_sdc3.dev, OFF), + CLK_PCOM("sdc_pclk", SDC3_PCLK, &msm_device_sdc3.dev, OFF), + CLK_PCOM("sdc_clk", SDC4_CLK, &msm_device_sdc4.dev, OFF), + CLK_PCOM("sdc_pclk", SDC4_PCLK, &msm_device_sdc4.dev, OFF), + CLK_PCOM("spi_clk", SPI_CLK, NULL, 0), + CLK_PCOM("tsif_clk", TSIF_CLK, NULL, 0), + CLK_PCOM("tsif_ref_clk", TSIF_REF_CLK, NULL, 0), + CLK_PCOM("tv_dac_clk", TV_DAC_CLK, NULL, 0), + CLK_PCOM("tv_enc_clk", TV_ENC_CLK, NULL, 0), + CLK_PCOM("uart_clk", UART1_CLK, &msm_device_uart1.dev, OFF), + CLK_PCOM("uart_clk", UART2_CLK, &msm_device_uart2.dev, 0), + CLK_PCOM("uart_clk", UART3_CLK, &msm_device_uart3.dev, OFF), + CLK_PCOM("uartdm_clk", UART1DM_CLK, &msm_device_uart_dm1.dev, OFF), + CLK_PCOM("uartdm_clk", UART2DM_CLK, &msm_device_uart_dm2.dev, 0), + CLK_PCOM("usb_hs_clk", USB_HS_CLK, NULL, OFF), + CLK_PCOM("usb_hs_pclk", USB_HS_PCLK, NULL, OFF), + CLK_PCOM("usb_otg_clk", USB_OTG_CLK, NULL, 0), + CLK_PCOM("vdc_clk", VDC_CLK, NULL, OFF | CLK_MIN), + CLK_PCOM("vfe_clk", VFE_CLK, NULL, OFF), + CLK_PCOM("vfe_mdc_clk", VFE_MDC_CLK, NULL, OFF), + CLK_PCOM("vfe_axi_clk", VFE_AXI_CLK, NULL, OFF), + CLK_PCOM("usb_hs2_clk", USB_HS2_CLK, NULL, OFF), + CLK_PCOM("usb_hs2_pclk", USB_HS2_PCLK, NULL, OFF), + CLK_PCOM("usb_hs3_clk", USB_HS3_CLK, NULL, OFF), + CLK_PCOM("usb_hs3_pclk", USB_HS3_PCLK, NULL, OFF), + CLK_PCOM("usb_phy_clk", USB_PHY_CLK, NULL, 0), }; unsigned msm_num_clocks_8x50 = ARRAY_SIZE(msm_clocks_8x50); -- cgit v1.2.3 From e5a500e6e189ddcf8c737dbf3d3d3951e24be159 Mon Sep 17 00:00:00 2001 From: Saravana Kannan Date: Thu, 16 Jul 2009 12:48:11 -0700 Subject: [ARM] msm: clock: Add new list of supported clocks for 7x30. The list of clocks is just a preliminary list and will change soon. Signed-off-by: Saravana Kannan --- arch/arm/mach-msm/board-msm7x30.c | 2 +- arch/arm/mach-msm/devices.c | 56 ++++++++++++++++++++++++++++++++++----- arch/arm/mach-msm/devices.h | 3 +++ 3 files changed, 54 insertions(+), 7 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c index 18957b816a9e..88fe3238f46d 100644 --- a/arch/arm/mach-msm/board-msm7x30.c +++ b/arch/arm/mach-msm/board-msm7x30.c @@ -146,7 +146,7 @@ static void __init msm7x30_map_io(void) { msm_shared_ram_phys = 0x00100000; msm_map_msm7x30_io(); - msm_clock_init(msm_clocks_8x50, msm_num_clocks_8x50); + msm_clock_init(msm_clocks_7x30, msm_num_clocks_7x30); } MACHINE_START(MSM7X30_SURF, "QCT MSM7X30 SURF") diff --git a/arch/arm/mach-msm/devices.c b/arch/arm/mach-msm/devices.c index 04d19b3d098d..edf5f520a102 100644 --- a/arch/arm/mach-msm/devices.c +++ b/arch/arm/mach-msm/devices.c @@ -408,7 +408,7 @@ struct clk msm_clocks_7x01a[] = { CLK_PCOM("ebi2_clk", EBI2_CLK, NULL, 0), CLK_PCOM("ecodec_clk", ECODEC_CLK, NULL, 0), CLK_PCOM("emdh_clk", EMDH_CLK, NULL, OFF | CLK_MINMAX), - CLK_PCOM("gp_clk", GP_CLK, NULL, 0), + CLK_PCOM("gp_clk", GP_CLK, NULL, 0), CLK_PCOM("grp_clk", GRP_CLK, NULL, OFF), CLK_PCOM("i2c_clk", I2C_CLK, &msm_device_i2c.dev, 0), CLK_PCOM("icodec_rx_clk", ICODEC_RX_CLK, NULL, 0), @@ -454,7 +454,7 @@ struct clk msm_clocks_7x25[] = { CLK_PCOM("ebi1_clk", EBI1_CLK, NULL, CLK_MIN), CLK_PCOM("ebi2_clk", EBI2_CLK, NULL, 0), CLK_PCOM("ecodec_clk", ECODEC_CLK, NULL, 0), - CLK_PCOM("gp_clk", GP_CLK, NULL, 0), + CLK_PCOM("gp_clk", GP_CLK, NULL, 0), CLK_PCOM("i2c_clk", I2C_CLK, &msm_device_i2c.dev, 0), CLK_PCOM("icodec_rx_clk", ICODEC_RX_CLK, NULL, 0), CLK_PCOM("icodec_tx_clk", ICODEC_TX_CLK, NULL, 0), @@ -463,7 +463,7 @@ struct clk msm_clocks_7x25[] = { CLK_PCOM("mdp_clk", MDP_CLK, NULL, OFF), CLK_PCOM("mdp_lcdc_pclk_clk", MDP_LCDC_PCLK_CLK, NULL, 0), CLK_PCOM("mdp_lcdc_pad_pclk_clk", MDP_LCDC_PAD_PCLK_CLK, NULL, 0), - CLK_PCOM("mdp_vsync_clk", MDP_VSYNC_CLK, NULL, 0), + CLK_PCOM("mdp_vsync_clk", MDP_VSYNC_CLK, NULL, 0), CLK_PCOM("pbus_clk", PBUS_CLK, NULL, CLK_MIN), CLK_PCOM("pcm_clk", PCM_CLK, NULL, 0), CLK_PCOM("mddi_clk", PMDH_CLK, NULL, OFF | CLK_MINMAX), @@ -498,7 +498,7 @@ struct clk msm_clocks_7x27[] = { CLK_PCOM("ebi1_clk", EBI1_CLK, NULL, CLK_MIN), CLK_PCOM("ebi2_clk", EBI2_CLK, NULL, 0), CLK_PCOM("ecodec_clk", ECODEC_CLK, NULL, 0), - CLK_PCOM("gp_clk", GP_CLK, NULL, 0), + CLK_PCOM("gp_clk", GP_CLK, NULL, 0), CLK_PCOM("grp_clk", GRP_CLK, NULL, 0), CLK_PCOM("i2c_clk", I2C_CLK, &msm_device_i2c.dev, 0), CLK_PCOM("icodec_rx_clk", ICODEC_RX_CLK, NULL, 0), @@ -508,7 +508,7 @@ struct clk msm_clocks_7x27[] = { CLK_PCOM("mdp_clk", MDP_CLK, NULL, OFF), CLK_PCOM("mdp_lcdc_pclk_clk", MDP_LCDC_PCLK_CLK, NULL, 0), CLK_PCOM("mdp_lcdc_pad_pclk_clk", MDP_LCDC_PAD_PCLK_CLK, NULL, 0), - CLK_PCOM("mdp_vsync_clk", MDP_VSYNC_CLK, NULL, 0), + CLK_PCOM("mdp_vsync_clk", MDP_VSYNC_CLK, NULL, 0), CLK_PCOM("pbus_clk", PBUS_CLK, NULL, CLK_MIN), CLK_PCOM("pcm_clk", PCM_CLK, NULL, 0), CLK_PCOM("mddi_clk", PMDH_CLK, NULL, OFF | CLK_MINMAX), @@ -536,13 +536,57 @@ struct clk msm_clocks_7x27[] = { unsigned msm_num_clocks_7x27 = ARRAY_SIZE(msm_clocks_7x27); +struct clk msm_clocks_7x30[] = { + CLK_PCOM("adm_clk", ADM_CLK, NULL, 0), + CLK_PCOM("adsp_clk", ADSP_CLK, NULL, 0), + CLK_PCOM("ebi1_clk", EBI1_CLK, NULL, CLK_MIN), + CLK_PCOM("ebi2_clk", EBI2_CLK, NULL, 0), + CLK_PCOM("ecodec_clk", ECODEC_CLK, NULL, 0), + CLK_PCOM("gp_clk", GP_CLK, NULL, 0), + CLK_PCOM("grp_clk", GRP_CLK, NULL, 0), + CLK_PCOM("i2c_clk", I2C_CLK, &msm_device_i2c.dev, 0), + CLK_PCOM("imem_clk", IMEM_CLK, NULL, OFF), + CLK_PCOM("mdc_clk", MDC_CLK, NULL, 0), + CLK_PCOM("mdp_clk", MDP_CLK, NULL, OFF), + CLK_PCOM("mdp_lcdc_pclk_clk", MDP_LCDC_PCLK_CLK, NULL, 0), + CLK_PCOM("mdp_lcdc_pad_pclk_clk", MDP_LCDC_PAD_PCLK_CLK, NULL, 0), + CLK_PCOM("mdp_vsync_clk", MDP_VSYNC_CLK, NULL, 0), + CLK_PCOM("pbus_clk", PBUS_CLK, NULL, CLK_MIN), + CLK_PCOM("pcm_clk", PCM_CLK, NULL, 0), + CLK_PCOM("mddi_clk", PMDH_CLK, NULL, OFF | CLK_MINMAX), + CLK_PCOM("sdac_clk", SDAC_CLK, NULL, OFF), + CLK_PCOM("sdc_clk", SDC1_CLK, &msm_device_sdc1.dev, OFF), + CLK_PCOM("sdc_pclk", SDC1_PCLK, &msm_device_sdc1.dev, OFF), + CLK_PCOM("sdc_clk", SDC2_CLK, &msm_device_sdc2.dev, OFF), + CLK_PCOM("sdc_pclk", SDC2_PCLK, &msm_device_sdc2.dev, OFF), + CLK_PCOM("sdc_clk", SDC3_CLK, &msm_device_sdc3.dev, OFF), + CLK_PCOM("sdc_pclk", SDC3_PCLK, &msm_device_sdc3.dev, OFF), + CLK_PCOM("sdc_clk", SDC4_CLK, &msm_device_sdc4.dev, OFF), + CLK_PCOM("sdc_pclk", SDC4_PCLK, &msm_device_sdc4.dev, OFF), + CLK_PCOM("uart_clk", UART1_CLK, &msm_device_uart1.dev, OFF), + CLK_PCOM("uart_clk", UART2_CLK, &msm_device_uart2.dev, 0), + CLK_PCOM("uart_clk", UART3_CLK, &msm_device_uart3.dev, OFF), + CLK_PCOM("uartdm_clk", UART1DM_CLK, &msm_device_uart_dm1.dev, OFF), + CLK_PCOM("uartdm_clk", UART2DM_CLK, &msm_device_uart_dm2.dev, 0), + CLK_PCOM("usb_hs_clk", USB_HS_CLK, NULL, OFF), + CLK_PCOM("usb_hs_pclk", USB_HS_PCLK, NULL, OFF), + CLK_PCOM("usb_otg_clk", USB_OTG_CLK, NULL, 0), + CLK_PCOM("vdc_clk", VDC_CLK, NULL, OFF | CLK_MIN), + CLK_PCOM("vfe_clk", VFE_CLK, NULL, OFF), + CLK_PCOM("vfe_mdc_clk", VFE_MDC_CLK, NULL, OFF), + CLK_PCOM("grp_pclk", GRP_PCLK, NULL, 0), + CLK_PCOM("usb_phy_clk", USB_PHY_CLK, NULL, 0), +}; + +unsigned msm_num_clocks_7x30 = ARRAY_SIZE(msm_clocks_7x30); + struct clk msm_clocks_8x50[] = { CLK_PCOM("adm_clk", ADM_CLK, NULL, 0), CLK_PCOM("ebi1_clk", EBI1_CLK, NULL, CLK_MIN), CLK_PCOM("ebi2_clk", EBI2_CLK, NULL, 0), CLK_PCOM("ecodec_clk", ECODEC_CLK, NULL, 0), CLK_PCOM("emdh_clk", EMDH_CLK, NULL, OFF | CLK_MINMAX), - CLK_PCOM("gp_clk", GP_CLK, NULL, 0), + CLK_PCOM("gp_clk", GP_CLK, NULL, 0), CLK_PCOM("grp_clk", GRP_CLK, NULL, 0), CLK_PCOM("i2c_clk", I2C_CLK, &msm_device_i2c.dev, 0), CLK_PCOM("icodec_rx_clk", ICODEC_RX_CLK, NULL, 0), diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h index 5a42b009afff..e8d3b8d6e96b 100644 --- a/arch/arm/mach-msm/devices.h +++ b/arch/arm/mach-msm/devices.h @@ -47,6 +47,9 @@ extern unsigned msm_num_clocks_7x25; extern struct clk msm_clocks_7x27[]; extern unsigned msm_num_clocks_7x27; +extern struct clk msm_clocks_7x30[]; +extern unsigned msm_num_clocks_7x30; + extern struct clk msm_clocks_8x50[]; extern unsigned msm_num_clocks_8x50; -- cgit v1.2.3 From a9e675e8a1aed20d465927d4b0849c874e43cd01 Mon Sep 17 00:00:00 2001 From: Neil Leeder Date: Thu, 23 Jul 2009 12:39:26 -0400 Subject: [ARM] msm: enable SPI accelerometer on Comet2 Turn off the accelerometer i2c enable and power monitor SPI enable, both of which conflict with the use of the accelerometer on SPI on Comet2. Signed-off-by: Neil Leeder --- arch/arm/mach-msm/board-comet.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/board-comet.c b/arch/arm/mach-msm/board-comet.c index d99b1babe59e..370fb6bd9cba 100644 --- a/arch/arm/mach-msm/board-comet.c +++ b/arch/arm/mach-msm/board-comet.c @@ -137,11 +137,11 @@ static struct comet_cpld_t { [1] = { .per_reset_all_reset = 0x00BF, .ext_per_reset_all_reset = 0x0007, - .i2c_enable = 0x07FF, + .i2c_enable = 0x07F7, /* enable all peripherals except microphones and */ /* displays */ .per_enable_all = 0xF9B8, - .ext_per_enable_all = 0x007F, + .ext_per_enable_all = 0x007D, .bt_reset_reg = 0x0048, .bt_reset_mask = 0x0004, }, -- cgit v1.2.3 From a47dee44b2c907d7bc4a7e9a4b4b7034e3359c72 Mon Sep 17 00:00:00 2001 From: Ai Li Date: Wed, 22 Jul 2009 18:36:38 -0600 Subject: [ARM] msm: idle: add memory barriers, cache flush, TLB invalidation The 1:1 MMU mapping code is missing cache flushes, TLB invalidations, and branch predictor invalidations, which are required when changing MMU mappings. The missing TLB invalidation, in particular, causes the Android framework to crash randomly. The patch also adds data, instruction memory barriers as needed, and moves SWFI to a separate function so that the error return path of power collapse correctly restores registers. CRs-Fixed: 188703 Signed-off-by: Ai Li --- arch/arm/mach-msm/idle-v6.S | 63 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 50 insertions(+), 13 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/idle-v6.S b/arch/arm/mach-msm/idle-v6.S index 33157734a078..1c74c6436a4e 100644 --- a/arch/arm/mach-msm/idle-v6.S +++ b/arch/arm/mach-msm/idle-v6.S @@ -19,9 +19,30 @@ #include #include +ENTRY(msm_arch_idle) + mov r0, #0 + mcr p15, 0, r0, c7, c10, 0 /* flush entire data cache */ + mrc p15, 0, r1, c1, c0, 0 /* read current CR */ + bic r0, r1, #(1 << 2) /* clear dcache bit */ + bic r0, r0, #(1 << 12) /* clear icache bit */ + mcr p15, 0, r0, c1, c0, 0 /* disable d/i cache */ + + mov r0, #0 + mcr p15, 0, r0, c7, c10, 4 /* dsb */ + mcr p15, 0, r0, c7, c0, 4 /* wait for interrupt */ + + mcr p15, 0, r1, c1, c0, 0 /* restore d/i cache */ + mcr p15, 0, r0, c7, c5, 4 /* isb */ + + mov pc, lr + ENTRY(msm_pm_collapse) ldr r0, =saved_state stmia r0!, {r4-r14} + +#if defined(CONFIG_MSM_FIQ_SUPPORT) + cpsid f +#endif mrc p15, 0, r1, c1, c0, 0 /* MMU control */ mrc p15, 0, r2, c2, c0, 0 /* ttb */ mrc p15, 0, r3, c3, c0, 0 /* dacr */ @@ -36,28 +57,28 @@ ENTRY(msm_pm_collapse) #endif mrc p15, 0, r1, c1, c0, 2 /* read CACR */ stmia r0!, {r1} - /* fall though */ -ENTRY(msm_arch_idle) -#if defined(CONFIG_MSM_FIQ_SUPPORT) - cpsid f -#endif - mcr p15, 0, r0, c7, c10, 0 /* flush the cache */ + + mov r0, #0 + mcr p15, 0, r0, c7, c10, 0 /* flush entire data cache */ mrc p15, 0, r1, c1, c0, 0 /* read current CR */ bic r0, r1, #(1 << 2) /* clear dcache bit */ bic r0, r0, #(1 << 12) /* clear icache bit */ mcr p15, 0, r0, c1, c0, 0 /* disable d/i cache */ - mov r0, #0 /* prepare wfi value - * also used as return value from - * msm_pm_collapse */ - - mcr p15, 0, r0, c7, c10, 4 /* memory barrier */ + mov r0, #0 + mcr p15, 0, r0, c7, c10, 4 /* dsb */ mcr p15, 0, r0, c7, c0, 4 /* wait for interrupt */ mcr p15, 0, r1, c1, c0, 0 /* restore d/i cache */ + mcr p15, 0, r0, c7, c5, 4 /* isb */ + #if defined(CONFIG_MSM_FIQ_SUPPORT) cpsie f #endif + + ldr r0, =saved_state /* restore registers */ + ldmfd r0, {r4-r14} + mov r0, #0 /* return power collapse failed */ mov pc, lr ENTRY(msm_pm_collapse_exit) @@ -89,6 +110,8 @@ ENTRY(msm_pm_collapse_exit) mcr p15, 0, r4, c3, c0, 0 /* dacr */ mcr p15, 0, r3, c2, c0, 0 /* ttb */ mcr p15, 0, r5, c13, c0, 1 /* context ID */ + mov r0, #0 + mcr p15, 0, r0, c7, c5, 4 /* isb */ ldmdb r1!, {r4-r14} /* Add 1:1 map in the PMD to allow smooth switch when turning on MMU */ @@ -104,8 +127,10 @@ ENTRY(msm_pm_collapse_exit) orr r0, r0, #0x400 /* PMD_SECT_AP_WRITE */ orr r0, r0, #0x2 /* PMD_TYPE_SECT|PMD_DOMAIN(DOMAIN_KERNEL) */ str r0, [r3] /* put new entry into the MMU table */ - mcr p15, 0, r3, c7, c10, 1 /* flush_pmd */ + mov r0, #0 + mcr p15, 0, r0, c7, c10, 4 /* dsb */ mcr p15, 0, r2, c1, c0, 0 /* MMU control */ + mcr p15, 0, r0, c7, c5, 4 /* isb */ msm_pm_mapped_pa: /* Switch to virtual */ adr r2, msm_pm_pa_to_va @@ -116,7 +141,19 @@ msm_pm_pa_to_va: /* Restore r1 in MMU table */ add r3, r3, r0 str r1, [r3] - mcr p15, 0, r3, c7, c10, 1 /* flush_pmd */ + + mov r0, #0 + mcr p15, 0, r0, c7, c10, 0 /* flush entire data cache */ + mcr p15, 0, r0, c7, c10, 4 /* dsb */ + mcr p15, 0, r0, c7, c5, 4 /* isb */ + mcr p15, 0, r0, c8, c7, 0 /* invalidate entire unified TLB */ + mcr p15, 0, r0, c7, c5, 6 /* invalidate entire branch target + * cache */ + mcr p15, 0, r0, c7, c7, 0 /* invalidate both data and instruction + * cache */ + mcr p15, 0, r0, c7, c10, 4 /* dsb */ + mcr p15, 0, r0, c7, c5, 4 /* isb */ + mov r0, #1 mov pc, lr nop -- cgit v1.2.3 From fba545c344cf9aed7aa7911a4ecd046514c02097 Mon Sep 17 00:00:00 2001 From: "Ruigrok, Richard" Date: Mon, 27 Jul 2009 14:19:16 -0600 Subject: [ARM] msm: add proc_comm commands for clkctl_rpc_reset assert/deassert New proc_comm commands: PCOM_CLKCTL_RPC_RESET_ASSERT PCOM_CLKCTL_RPC_RESET_DEASSERT Signed-off-by: Richard Ruigrok --- arch/arm/mach-msm/proc_comm.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/proc_comm.h b/arch/arm/mach-msm/proc_comm.h index b071379871a2..3ba013ed3aed 100644 --- a/arch/arm/mach-msm/proc_comm.h +++ b/arch/arm/mach-msm/proc_comm.h @@ -127,6 +127,8 @@ enum { PCOM_CHG_USB_IS_AVAILABLE, PCOM_CLK_REGIME_SEC_MSM_SEL_FREQ, PCOM_CLK_REGIME_SEC_SET_PCLK_AXI_POLICY, + PCOM_CLKCTL_RPC_RESET_ASSERT, + PCOM_CLKCTL_RPC_RESET_DEASSERT, PCOM_NUM_CMDS, }; -- cgit v1.2.3 From 2b01d9620dd28a999c796787af650e52a167cd87 Mon Sep 17 00:00:00 2001 From: "Vishwanathapura, Niranjana" Date: Mon, 22 Jun 2009 11:07:27 -0600 Subject: msm: Add more support in RPC Client Framework Add support to piggy back payload along with reply by providing msm_rpc_start_accepted_reply and msm_rpc_send_accepted_reply apis. Provide machanism/interface in framework for 'callback Id Vs Callback function' table for a client. Change msm_rpc_client_req to accept timeout value from user. Update the ping/handset/fsusb drivers as per RPC Client Framework change. Signed-off-by: Niranjana Vishwanathapura --- arch/arm/mach-msm/include/mach/msm_rpcrouter.h | 29 ++- arch/arm/mach-msm/rpc_server_handset.c | 16 +- arch/arm/mach-msm/smd_rpc_ping.c | 62 +++-- arch/arm/mach-msm/smd_rpcrouter_clients.c | 298 ++++++++++++++++++++++--- 4 files changed, 332 insertions(+), 73 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/include/mach/msm_rpcrouter.h b/arch/arm/mach-msm/include/mach/msm_rpcrouter.h index 0851a405da03..5b5644eecde2 100644 --- a/arch/arm/mach-msm/include/mach/msm_rpcrouter.h +++ b/arch/arm/mach-msm/include/mach/msm_rpcrouter.h @@ -198,12 +198,18 @@ struct msm_rpc_client { wait_queue_head_t cb_wait; int cb_avail; + atomic_t next_cb_id; + struct mutex cb_list_lock; + struct list_head cb_list; + uint32_t exit_flag; struct completion complete; struct completion cb_complete; struct mutex req_lock; - char req[MSM_RPC_MSGSIZE_MAX]; + struct mutex reply_lock; + char *req; + char *reply; }; struct msm_rpc_client *msm_rpc_register_client( @@ -215,12 +221,21 @@ struct msm_rpc_client *msm_rpc_register_client( int msm_rpc_unregister_client(struct msm_rpc_client *client); int msm_rpc_client_req(struct msm_rpc_client *client, uint32_t proc, - int (*arg_func)(void *, void *), - int (*result_func)(void *, void *), - void *data); + int (*arg_func)(struct msm_rpc_client *, + void *, void *), void *arg_data, + int (*result_func)(struct msm_rpc_client *, + void *, void *), void *result_data, + long timeout); + +void *msm_rpc_start_accepted_reply(struct msm_rpc_client *client, + uint32_t xid, uint32_t accept_status); + +int msm_rpc_send_accepted_reply(struct msm_rpc_client *client, uint32_t size); + +int msm_rpc_add_cb_func(struct msm_rpc_client *client, void *cb_func); + +void *msm_rpc_get_cb_func(struct msm_rpc_client *client, uint32_t cb_id); -int msm_rpc_send_accepted_reply(struct msm_rpc_client *client, - uint32_t xid, uint32_t accept_status, - char *buf, uint32_t size); +void msm_rpc_remove_cb_func(struct msm_rpc_client *client, void *cb_func); #endif diff --git a/arch/arm/mach-msm/rpc_server_handset.c b/arch/arm/mach-msm/rpc_server_handset.c index d44574361d02..38cc38cabaea 100644 --- a/arch/arm/mach-msm/rpc_server_handset.c +++ b/arch/arm/mach-msm/rpc_server_handset.c @@ -265,7 +265,8 @@ static void process_hs_rpc_request(uint32_t proc, void *data) pr_err("%s: unknown rpc proc %d\n", __func__, proc); } -static int hs_rpc_register_subs_arg(void *buffer, void *data) +static int hs_rpc_register_subs_arg(struct msm_rpc_client *client, + void *buffer, void *data) { struct hs_subs_rpc_req { uint32_t hs_subs_ptr; @@ -293,7 +294,8 @@ static int hs_rpc_register_subs_arg(void *buffer, void *data) return sizeof(*req); } -static int hs_rpc_register_subs_res(void *buffer, void *data) +static int hs_rpc_register_subs_res(struct msm_rpc_client *client, + void *buffer, void *data) { uint32_t result; @@ -329,8 +331,9 @@ static int hs_cb_func(struct msm_rpc_client *client, void *buffer, int in_size) process_hs_rpc_request(hdr->procedure, (void *) (hdr + 1)); - rc = msm_rpc_send_accepted_reply(client, hdr->xid, - RPC_ACCEPTSTAT_SUCCESS, NULL, 0); + msm_rpc_start_accepted_reply(client, hdr->xid, + RPC_ACCEPTSTAT_SUCCESS); + rc = msm_rpc_send_accepted_reply(client, 0); if (rc) { pr_err("%s: sending reply failed: %d\n", __func__, rc); return rc; @@ -353,9 +356,8 @@ static int __init hs_rpc_cb_init(void) } rc = msm_rpc_client_req(rpc_client, HS_SUBSCRIBE_SRVC_PROC, - hs_rpc_register_subs_arg, - hs_rpc_register_subs_res, - NULL); + hs_rpc_register_subs_arg, NULL, + hs_rpc_register_subs_res, NULL, -1); if (rc) { pr_err("%s: couldn't send rpc client request\n", __func__); msm_rpc_unregister_client(rpc_client); diff --git a/arch/arm/mach-msm/smd_rpc_ping.c b/arch/arm/mach-msm/smd_rpc_ping.c index 60858f555437..17058412c0c0 100644 --- a/arch/arm/mach-msm/smd_rpc_ping.c +++ b/arch/arm/mach-msm/smd_rpc_ping.c @@ -146,8 +146,9 @@ static void ping_mdm_register_cb(struct msm_rpc_client *client, buf += sizeof(int32_t); pr_info("%s: received cb_id %d, val = %d\n", __func__, cb_id, num); - rc = msm_rpc_send_accepted_reply(client, be32_to_cpu(req->xid), - RPC_ACCEPTSTAT_SUCCESS, NULL, 0); + msm_rpc_start_accepted_reply(client, be32_to_cpu(req->xid), + RPC_ACCEPTSTAT_SUCCESS); + rc = msm_rpc_send_accepted_reply(client, 0); if (rc) { pr_err("%s: sending reply failed: %d\n", __func__, rc); return; @@ -171,9 +172,9 @@ static void ping_mdm_data_cb(struct msm_rpc_client *client, { struct rpc_request_hdr *req; int rc, i; - void *buf; + void *buf, *reply; uint32_t cb_id = 0; - uint32_t size, *data, req_size, sum, my_sum, my_data; + uint32_t size, *data, req_size, sum, my_sum; struct ping_mdm_cb_item *cb_item; req = (struct rpc_request_hdr *)buffer; @@ -199,10 +200,10 @@ static void ping_mdm_data_cb(struct msm_rpc_client *client, if (sum != my_sum) pr_err("%s: sum mismatch\n", __func__); - my_data = cpu_to_be32(1); - rc = msm_rpc_send_accepted_reply(client, be32_to_cpu(req->xid), - RPC_ACCEPTSTAT_SUCCESS, - (char *)&my_data, sizeof(my_data)); + reply = msm_rpc_start_accepted_reply(client, be32_to_cpu(req->xid), + RPC_ACCEPTSTAT_SUCCESS); + *(uint32_t *)reply = cpu_to_be32(1); + rc = msm_rpc_send_accepted_reply(client, sizeof(uint32_t)); if (rc) pr_err("%s: sending reply failed: %d\n", __func__, rc); @@ -291,7 +292,8 @@ static void ping_mdm_destroy_cb_item(struct ping_mdm_cb_item *cb_item) kfree(cb_item); } -static int ping_mdm_data_cb_register_arg(void *buf, void *data) +static int ping_mdm_data_cb_register_arg(struct msm_rpc_client *client, + void *buf, void *data) { int size = 0; @@ -318,13 +320,15 @@ static int ping_mdm_data_cb_register_arg(void *buf, void *data) return size; } -static int ping_mdm_data_cb_register_arg_unreg(void *buf, void *data) +static int ping_mdm_data_cb_register_arg_unreg(struct msm_rpc_client *client, + void *buf, void *data) { *((uint32_t *)buf) = cpu_to_be32((uint32_t)data); return sizeof(uint32_t); } -static int ping_mdm_data_cb_register_result(void *buf, void *data) +static int ping_mdm_data_cb_register_result(struct msm_rpc_client *client, + void *buf, void *data) { uint32_t result; @@ -354,8 +358,9 @@ static int ping_mdm_data_cb_register_test(void) rc = msm_rpc_client_req(client, PING_MDM_REGISTER_DATA_CB_PROC, ping_mdm_data_cb_register_arg, + (void *)(cb_item->cb_id), ping_mdm_data_cb_register_result, - (void *)(cb_item->cb_id)); + NULL, -1); if (rc) goto free_and_release_client; @@ -364,8 +369,9 @@ static int ping_mdm_data_cb_register_test(void) rc = msm_rpc_client_req(client, PING_MDM_UNREGISTER_DATA_CB_PROC, ping_mdm_data_cb_register_arg_unreg, + (void *)(cb_item->cb_id), ping_mdm_data_cb_register_result, - (void *)(cb_item->cb_id)); + NULL, -1); free_and_release_client: @@ -377,7 +383,8 @@ static int ping_mdm_data_cb_register_test(void) return rc; } -static int ping_mdm_data_register_arg(void *buf, void *data) +static int ping_mdm_data_register_arg(struct msm_rpc_client *client, + void *buf, void *data) { int i, size = 0; @@ -396,7 +403,8 @@ static int ping_mdm_data_register_arg(void *buf, void *data) return size; } -static int ping_mdm_data_register_result(void *buf, void *data) +static int ping_mdm_data_register_result(struct msm_rpc_client *client, + void *buf, void *data) { uint32_t result; @@ -422,8 +430,8 @@ static int ping_mdm_data_register_test(void) rc = msm_rpc_client_req(client, PING_MDM_REGISTER_DATA_PROC, - ping_mdm_data_register_arg, - ping_mdm_data_register_result, &my_sum); + ping_mdm_data_register_arg, &my_sum, + ping_mdm_data_register_result, &my_sum, -1); if (client != rpc_client) msm_rpc_unregister_client(client); @@ -431,7 +439,8 @@ static int ping_mdm_data_register_test(void) return rc; } -static int ping_mdm_register_arg(void *buf, void *data) +static int ping_mdm_register_arg(struct msm_rpc_client *client, + void *buf, void *data) { int num, size = 0; @@ -447,13 +456,15 @@ static int ping_mdm_register_arg(void *buf, void *data) return size; } -static int ping_mdm_register_arg_unreg(void *buf, void *data) +static int ping_mdm_register_arg_unreg(struct msm_rpc_client *client, + void *buf, void *data) { *((uint32_t *)buf) = cpu_to_be32((uint32_t)data); return sizeof(uint32_t); } -static int ping_mdm_register_result(void *buf, void *data) +static int ping_mdm_register_result(struct msm_rpc_client *client, + void *buf, void *data) { uint32_t result; @@ -483,8 +494,9 @@ static int ping_mdm_register_test(void) rc = msm_rpc_client_req(client, PING_MDM_REGISTER_PROC, ping_mdm_register_arg, + (void *)(cb_item->cb_id), ping_mdm_register_result, - (void *)(cb_item->cb_id)); + NULL, -1); if (rc) goto free_and_release_client; @@ -493,8 +505,9 @@ static int ping_mdm_register_test(void) rc = msm_rpc_client_req(client, PING_MDM_UNREGISTER_PROC, ping_mdm_register_arg_unreg, + (void *)(cb_item->cb_id), ping_mdm_register_result, - (void *)(cb_item->cb_id)); + NULL, -1); free_and_release_client: ping_mdm_destroy_cb_item(cb_item); @@ -514,7 +527,8 @@ static int ping_mdm_null_test(void) if (IS_ERR(client)) return PTR_ERR(client); - rc = msm_rpc_client_req(client, PING_MDM_NULL_PROC, NULL, NULL, NULL); + rc = msm_rpc_client_req(client, PING_MDM_NULL_PROC, NULL, NULL, + NULL, NULL, -1); if (client != rpc_client) msm_rpc_unregister_client(client); @@ -682,4 +696,4 @@ module_init(ping_test_init); module_exit(ping_test_exit); MODULE_DESCRIPTION("PING TEST Driver"); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/arch/arm/mach-msm/smd_rpcrouter_clients.c b/arch/arm/mach-msm/smd_rpcrouter_clients.c index 01afe99a3628..50b867fded54 100644 --- a/arch/arm/mach-msm/smd_rpcrouter_clients.c +++ b/arch/arm/mach-msm/smd_rpcrouter_clients.c @@ -1,16 +1,72 @@ -/* - * Copyright (c) 2009, Code Aurora Forum. All rights reserved. +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. * - * SMD RPCROUTER CLIENTS module. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. * */ +/* + * SMD RPCROUTER CLIENTS module. + */ + #include #include #include #include "smd_rpcrouter.h" +#define MSM_RPC_CLIENT_NULL_CB_ID 0xffffffff + struct msm_rpc_client_cb_item { struct list_head list; @@ -18,6 +74,13 @@ struct msm_rpc_client_cb_item { int size; }; +struct msm_rpc_cb_table_item { + struct list_head list; + + uint32_t cb_id; + void *cb_func; +}; + static int rpc_clients_cb_thread(void *data) { struct msm_rpc_client_cb_item *cb_item; @@ -117,8 +180,22 @@ static struct msm_rpc_client *msm_rpc_create_client(void) if (!client) return ERR_PTR(-ENOMEM); + client->req = kmalloc(MSM_RPC_MSGSIZE_MAX, GFP_KERNEL); + if (!client->req) { + kfree(client); + return ERR_PTR(-ENOMEM); + } + + client->reply = kmalloc(MSM_RPC_MSGSIZE_MAX, GFP_KERNEL); + if (!client->reply) { + kfree(client->req); + kfree(client); + return ERR_PTR(-ENOMEM); + } + init_waitqueue_head(&client->reply_wait); mutex_init(&client->req_lock); + mutex_init(&client->reply_lock); client->buf = NULL; client->read_avail = 0; client->cb_buf = NULL; @@ -130,10 +207,26 @@ static struct msm_rpc_client *msm_rpc_create_client(void) mutex_init(&client->cb_item_list_lock); client->cb_avail = 0; init_waitqueue_head(&client->cb_wait); + INIT_LIST_HEAD(&client->cb_list); + mutex_init(&client->cb_list_lock); + atomic_set(&client->next_cb_id, 1); return client; } +void msm_rpc_remove_all_cb_func(struct msm_rpc_client *client) +{ + struct msm_rpc_cb_table_item *cb_item, *tmp_cb_item; + + mutex_lock(&client->cb_list_lock); + list_for_each_entry_safe(cb_item, tmp_cb_item, + &client->cb_list, list) { + list_del(&cb_item->list); + kfree(cb_item); + } + mutex_unlock(&client->cb_list_lock); +} + /* * Interface to be used to register the client. * @@ -234,6 +327,9 @@ int msm_rpc_unregister_client(struct msm_rpc_client *client) wait_for_completion(&client->complete); msm_rpc_close(client->ept); + msm_rpc_remove_all_cb_func(client); + kfree(client->req); + kfree(client->reply); kfree(client); return 0; } @@ -241,28 +337,38 @@ EXPORT_SYMBOL(msm_rpc_unregister_client); /* * Interface to be used to send a client request. - * If the request takes any arguments or expects any results, the user - * should handle it in 'arg_func' and 'result_func' respectively. + * If the request takes any arguments or expects any return, the user + * should handle it in 'arg_func' and 'ret_func' respectively. * Marshaling and Unmarshaling should be handled by the user in argument - * and result functions. + * and return functions. * * client: pointer to client data sturcture * * proc: procedure being requested * - * arg_func: argument function pointer + * arg_func: argument function pointer. 'buf' is where arguments needs to + * be filled. 'data' is arg_data. * - * result_func: result function pointer + * ret_func: return function pointer. 'buf' is where returned data should + * be read from. 'data' is ret_data. * - * data: passed as an input parameter to argument and result functions. + * arg_data: passed as an input parameter to argument function. + * + * ret_data: passed as an input parameter to return function. + * + * timeout: timeout for reply wait in jiffies. If negative timeout is + * specified a default timeout of 10s is used. * * Return Value: * 0 on success, otherwise an error code is returned. */ int msm_rpc_client_req(struct msm_rpc_client *client, uint32_t proc, - int (*arg_func)(void *buf, void *data), - int (*result_func)(void *buf, void *data), - void *data) + int (*arg_func)(struct msm_rpc_client *client, + void *buf, void *data), + void *arg_data, + int (*ret_func)(struct msm_rpc_client *client, + void *buf, void *data), + void *ret_data, long timeout) { int size = 0; struct rpc_reply_hdr *rpc_rsp; @@ -274,9 +380,14 @@ int msm_rpc_client_req(struct msm_rpc_client *client, uint32_t proc, client->ver, proc); size = sizeof(struct rpc_request_hdr); - if (arg_func) - size += arg_func((void *)((struct rpc_request_hdr *) - client->req + 1), data); + if (arg_func) { + rc = arg_func(client, (void *)((struct rpc_request_hdr *) + client->req + 1), arg_data); + if (rc < 0) + goto release_locks; + else + size += rc; + } rc = msm_rpc_write(client->ept, client->req, size); if (rc < 0) { @@ -285,8 +396,11 @@ int msm_rpc_client_req(struct msm_rpc_client *client, uint32_t proc, } else rc = 0; + if (timeout < 0) + timeout = msecs_to_jiffies(10000); + rc = wait_event_timeout(client->reply_wait, - client->read_avail, msecs_to_jiffies(10000)); + client->read_avail, timeout); if (rc == 0) { rc = -ETIMEDOUT; goto release_locks; @@ -311,8 +425,8 @@ int msm_rpc_client_req(struct msm_rpc_client *client, uint32_t proc, goto free_and_release; } - if (result_func) - result_func((void *)(rpc_rsp + 1), data); + if (ret_func) + rc = ret_func(client, (void *)(rpc_rsp + 1), ret_data); free_and_release: kfree(client->buf); @@ -323,9 +437,10 @@ int msm_rpc_client_req(struct msm_rpc_client *client, uint32_t proc, EXPORT_SYMBOL(msm_rpc_client_req); /* - * Interface to be used to send accepted reply required in callback handling. - * Additional payload may be passed in through the 'buf' and 'size'. - * Marshaling should be handled by user for the payload. + * Interface to be used to start accepted reply message required in + * callback handling. Returns the buffer pointer to attach any + * payload. Should call msm_rpc_send_accepted_reply to complete + * sending reply. Marshaling should be handled by user for the payload. * * client: pointer to client data structure * @@ -333,23 +448,17 @@ EXPORT_SYMBOL(msm_rpc_client_req); * * accept_status: acceptance status * - * buf: additional payload - * - * size: additional payload size - * * Return Value: - * 0 on success, otherwise returns an error code. + * pointer to buffer to attach the payload. */ -int msm_rpc_send_accepted_reply(struct msm_rpc_client *client, - uint32_t xid, uint32_t accept_status, - char *buf, uint32_t size) +void *msm_rpc_start_accepted_reply(struct msm_rpc_client *client, + uint32_t xid, uint32_t accept_status) { - int rc = 0; struct rpc_reply_hdr *reply; - reply = kmalloc(sizeof(struct rpc_reply_hdr) + size, GFP_KERNEL); - if (!reply) - return -ENOMEM; + mutex_lock(&client->reply_lock); + + reply = (struct rpc_reply_hdr *)client->reply; reply->xid = cpu_to_be32(xid); reply->type = cpu_to_be32(1); /* reply */ @@ -359,12 +468,131 @@ int msm_rpc_send_accepted_reply(struct msm_rpc_client *client, reply->data.acc_hdr.verf_flavor = 0; reply->data.acc_hdr.verf_length = 0; - memcpy((char *)(reply + 1), buf, size); + return reply + 1; +} +EXPORT_SYMBOL(msm_rpc_start_accepted_reply); + +/* + * Interface to be used to send accepted reply required in callback handling. + * msm_rpc_start_accepted_reply should have been called before. + * Marshaling should be handled by user for the payload. + * + * client: pointer to client data structure + * + * size: additional payload size + * + * Return Value: + * 0 on success, otherwise returns an error code. + */ +int msm_rpc_send_accepted_reply(struct msm_rpc_client *client, uint32_t size) +{ + int rc = 0; + size += sizeof(struct rpc_reply_hdr); - rc = msm_rpc_write(client->ept, reply, size); + rc = msm_rpc_write(client->ept, client->reply, size); if (rc > 0) rc = 0; + mutex_unlock(&client->reply_lock); return rc; } EXPORT_SYMBOL(msm_rpc_send_accepted_reply); + +/* + * Interface to be used to add a callback function. + * If the call back function is already in client's 'cb_id - cb_func' + * table, then that cb_id is returned. otherwise, new entry + * is added to the above table and corresponding cb_id is returned. + * + * client: pointer to client data structure + * + * cb_func: callback function + * + * Return Value: + * callback ID on success, otherwise returns an error code. + */ +int msm_rpc_add_cb_func(struct msm_rpc_client *client, void *cb_func) +{ + struct msm_rpc_cb_table_item *cb_item; + + if (cb_func == NULL) + return MSM_RPC_CLIENT_NULL_CB_ID; + + mutex_lock(&client->cb_list_lock); + list_for_each_entry(cb_item, &client->cb_list, list) { + if (cb_item->cb_func == cb_func) { + mutex_unlock(&client->cb_list_lock); + return cb_item->cb_id; + } + } + mutex_unlock(&client->cb_list_lock); + + cb_item = kmalloc(sizeof(struct msm_rpc_cb_table_item), GFP_KERNEL); + if (!cb_item) + return -ENOMEM; + + INIT_LIST_HEAD(&cb_item->list); + cb_item->cb_id = atomic_add_return(1, &client->next_cb_id); + cb_item->cb_func = cb_func; + + mutex_lock(&client->cb_list_lock); + list_add_tail(&cb_item->list, &client->cb_list); + mutex_unlock(&client->cb_list_lock); + + return cb_item->cb_id; +} +EXPORT_SYMBOL(msm_rpc_add_cb_func); + +/* + * Interface to be used to get a callback function from a callback ID. + * If no entry is found, NULL is returned. + * + * client: pointer to client data structure + * + * cb_id: callback ID + * + * Return Value: + * callback function pointer if entry with given cb_id is found, + * otherwise returns NULL. + */ +void *msm_rpc_get_cb_func(struct msm_rpc_client *client, uint32_t cb_id) +{ + struct msm_rpc_cb_table_item *cb_item; + + mutex_lock(&client->cb_list_lock); + list_for_each_entry(cb_item, &client->cb_list, list) { + if (cb_item->cb_id == cb_id) { + mutex_unlock(&client->cb_list_lock); + return cb_item->cb_func; + } + } + mutex_unlock(&client->cb_list_lock); + return NULL; +} +EXPORT_SYMBOL(msm_rpc_get_cb_func); + +/* + * Interface to be used to remove a callback function. + * + * client: pointer to client data structure + * + * cb_func: callback function + * + */ +void msm_rpc_remove_cb_func(struct msm_rpc_client *client, void *cb_func) +{ + struct msm_rpc_cb_table_item *cb_item, *tmp_cb_item; + + mutex_lock(&client->cb_list_lock); + list_for_each_entry_safe(cb_item, tmp_cb_item, + &client->cb_list, list) { + if (cb_item->cb_func == cb_func) { + list_del(&cb_item->list); + kfree(cb_item); + mutex_unlock(&client->cb_list_lock); + return; + } + } + mutex_unlock(&client->cb_list_lock); +} +EXPORT_SYMBOL(msm_rpc_remove_cb_func); -- cgit v1.2.3 From bb0e6ebad1e5b0d734a708ec0c98a0cfde6d7711 Mon Sep 17 00:00:00 2001 From: "Vishwanathapura, Niranjana" Date: Mon, 22 Jun 2009 11:17:09 -0600 Subject: msm: Cleanup Ping MDM client driver Change name to ping_mdm_rpc_client.c Cleanup Ping MDM Client driver to a well formatted structure. Remove ioctl debug interface as read/write is enough to run tests. Signed-off-by: Niranjana Vishwanathapura --- arch/arm/mach-msm/Kconfig | 4 +- arch/arm/mach-msm/Makefile | 2 +- arch/arm/mach-msm/ping_mdm_rpc_client.c | 772 ++++++++++++++++++++++++++++++++ arch/arm/mach-msm/smd_rpc_ping.c | 699 ----------------------------- 4 files changed, 775 insertions(+), 702 deletions(-) create mode 100644 arch/arm/mach-msm/ping_mdm_rpc_client.c delete mode 100644 arch/arm/mach-msm/smd_rpc_ping.c (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index 5598ace3f4bc..92f0198c46c9 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -429,11 +429,11 @@ config MSM_RPCSERVERS none config MSM_RPC_PING - depends on MSM_ONCRPCROUTER + depends on MSM_ONCRPCROUTER && DEBUG_FS default m bool "MSM rpc ping" help - Implements MSM rpc ping module. + Implements MSM rpc ping test module. config MSM_RPCSERVER_HANDSET depends on MSM_ONCRPCROUTER diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 109be8266be3..8572b5d62db5 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -30,7 +30,7 @@ obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter.o obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_device.o obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_servers.o obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_clients.o -obj-$(CONFIG_MSM_RPC_PING) += smd_rpc_ping.o +obj-$(CONFIG_MSM_RPC_PING) += ping_mdm_rpc_client.o obj-$(CONFIG_MSM_RPCSERVERS) += rpc_server_dog_keepalive.o obj-$(CONFIG_MSM_RPCSERVERS) += rpc_server_time_remote.o obj-$(CONFIG_MSM_DALRPC) += dal.o diff --git a/arch/arm/mach-msm/ping_mdm_rpc_client.c b/arch/arm/mach-msm/ping_mdm_rpc_client.c new file mode 100644 index 000000000000..1401679f03fd --- /dev/null +++ b/arch/arm/mach-msm/ping_mdm_rpc_client.c @@ -0,0 +1,772 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* + * SMD RPC PING MODEM Driver + */ + +#include +#include +#include +#include +#include +#include +#include + +#define PING_TEST_BASE 0x31 + +#define PTIOC_NULL_TEST _IO(PING_TEST_BASE, 1) +#define PTIOC_REG_TEST _IO(PING_TEST_BASE, 2) +#define PTIOC_DATA_REG_TEST _IO(PING_TEST_BASE, 3) +#define PTIOC_DATA_CB_REG_TEST _IO(PING_TEST_BASE, 4) + +#define PING_MDM_PROG 0x30000081 +#define PING_MDM_VERS 0x00010001 +#define PING_MDM_CB_PROG 0x31000081 +#define PING_MDM_CB_VERS 0x00010001 + +#define PING_MDM_NULL_PROC 0 +#define PING_MDM_RPC_GLUE_CODE_INFO_REMOTE_PROC 1 +#define PING_MDM_REGISTER_PROC 2 +#define PING_MDM_UNREGISTER_PROC 3 +#define PING_MDM_REGISTER_DATA_PROC 4 +#define PING_MDM_UNREGISTER_DATA_CB_PROC 5 +#define PING_MDM_REGISTER_DATA_CB_PROC 6 + +#define PING_MDM_DATA_CB_PROC 1 +#define PING_MDM_CB_PROC 2 + +static struct msm_rpc_client *rpc_client; +static uint32_t open_count; +static DEFINE_MUTEX(ping_mdm_lock); + +struct ping_mdm_register_cb_arg { + uint32_t cb_id; + int val; +}; + +struct ping_mdm_register_data_cb_cb_arg { + uint32_t cb_id; + uint32_t *data; + uint32_t size; + uint32_t sum; +}; + +struct ping_mdm_register_data_cb_cb_ret { + uint32_t result; +}; + +static int ping_mdm_register_cb(struct msm_rpc_client *client, + void *buffer, int in_size) +{ + int rc; + uint32_t accept_status; + struct rpc_request_hdr *req; + struct ping_mdm_register_cb_arg arg, *buf_ptr; + void *cb_func; + + req = (struct rpc_request_hdr *)buffer; + buf_ptr = (struct ping_mdm_register_cb_arg *)(req + 1); + + arg.cb_id = be32_to_cpu(buf_ptr->cb_id); + arg.val = be32_to_cpu(buf_ptr->val); + + cb_func = msm_rpc_get_cb_func(client, arg.cb_id); + if (cb_func) { + rc = ((int (*)(struct ping_mdm_register_cb_arg *, void *)) + cb_func)(&arg, NULL); + if (rc) + accept_status = RPC_ACCEPTSTAT_SYSTEM_ERR; + else + accept_status = RPC_ACCEPTSTAT_SUCCESS; + } else + accept_status = RPC_ACCEPTSTAT_SYSTEM_ERR; + + msm_rpc_start_accepted_reply(client, be32_to_cpu(req->xid), + accept_status); + rc = msm_rpc_send_accepted_reply(client, 0); + if (rc) + pr_err("%s: send accepted reply failed: %d\n", __func__, rc); + + return rc; +} + +static int ping_mdm_data_cb(struct msm_rpc_client *client, + void *buffer, int in_size) +{ + struct rpc_request_hdr *req; + int rc, i; + void *buf, *cb_func, *reply; + uint32_t size, accept_status; + struct ping_mdm_register_data_cb_cb_arg arg; + struct ping_mdm_register_data_cb_cb_ret ret; + + req = (struct rpc_request_hdr *)buffer; + buf = (void *)(req + 1); + + arg.cb_id = be32_to_cpu(*(uint32_t *)buf); + buf += sizeof(uint32_t); + + size = be32_to_cpu(*(uint32_t *)buf); + buf += sizeof(uint32_t); + if (size) { + arg.data = kmalloc((size * sizeof(*arg.data)), GFP_KERNEL); + if (arg.data) + for (i = 0; i < size; i++) + arg.data[i] = + be32_to_cpu(*((uint32_t *)buf + i)); + } + buf += sizeof(uint32_t) * size; + + arg.size = be32_to_cpu(*(uint32_t *)buf); + buf += sizeof(uint32_t); + + arg.sum = be32_to_cpu(*(uint32_t *)buf); + + cb_func = msm_rpc_get_cb_func(client, arg.cb_id); + if (cb_func) { + rc = ((int (*) + (struct ping_mdm_register_data_cb_cb_arg *, + struct ping_mdm_register_data_cb_cb_ret *)) + cb_func)(&arg, &ret); + if (rc) + accept_status = RPC_ACCEPTSTAT_SUCCESS; + else + accept_status = RPC_ACCEPTSTAT_SYSTEM_ERR; + } else + accept_status = RPC_ACCEPTSTAT_SYSTEM_ERR; + + reply = msm_rpc_start_accepted_reply(client, be32_to_cpu(req->xid), + accept_status); + + size = 0; + if (accept_status == RPC_ACCEPTSTAT_SUCCESS) { + *(uint32_t *)reply = cpu_to_be32(ret.result); + size = sizeof(uint32_t); + } + rc = msm_rpc_send_accepted_reply(client, size); + if (rc) + pr_err("%s: send accepted reply failed: %d\n", __func__, rc); + + return rc; +} + +static int ping_mdm_cb_func(struct msm_rpc_client *client, + void *buffer, int in_size) +{ + int rc = 0; + struct rpc_request_hdr *req; + + req = (struct rpc_request_hdr *)buffer; + + switch (be32_to_cpu(req->procedure)) { + case PING_MDM_CB_PROC: + rc = ping_mdm_register_cb(client, buffer, in_size); + break; + case PING_MDM_DATA_CB_PROC: + rc = ping_mdm_data_cb(client, buffer, in_size); + break; + default: + pr_err("%s: procedure not supported %d\n", __func__, + be32_to_cpu(req->procedure)); + msm_rpc_start_accepted_reply(client, be32_to_cpu(req->xid), + RPC_ACCEPTSTAT_PROC_UNAVAIL); + rc = msm_rpc_send_accepted_reply(client, 0); + if (rc) + pr_err("%s: sending reply failed: %d\n", __func__, rc); + break; + } + return rc; +} + +struct ping_mdm_unregister_data_cb_arg { + int (*cb_func)( + struct ping_mdm_register_data_cb_cb_arg *arg, + struct ping_mdm_register_data_cb_cb_ret *ret); +}; + +struct ping_mdm_register_data_cb_arg { + int (*cb_func)( + struct ping_mdm_register_data_cb_cb_arg *arg, + struct ping_mdm_register_data_cb_cb_ret *ret); + uint32_t num; + uint32_t size; + uint32_t interval_ms; + uint32_t num_tasks; +}; + +struct ping_mdm_register_data_cb_ret { + uint32_t result; +}; + +struct ping_mdm_unregister_data_cb_ret { + uint32_t result; +}; + +static int ping_mdm_data_cb_register_arg(struct msm_rpc_client *client, + void *buf, void *data) +{ + struct ping_mdm_register_data_cb_arg *arg; + int cb_id, size = 0; + + arg = (struct ping_mdm_register_data_cb_arg *)data; + + cb_id = msm_rpc_add_cb_func(client, (void *)arg->cb_func); + if (cb_id < 0) + return cb_id; + + *((uint32_t *)buf) = cpu_to_be32((uint32_t)cb_id); + size += sizeof(uint32_t); + buf += sizeof(uint32_t); + + *((uint32_t *)buf) = cpu_to_be32(arg->num); + size += sizeof(uint32_t); + buf += sizeof(uint32_t); + + *((uint32_t *)buf) = cpu_to_be32(arg->size); + size += sizeof(uint32_t); + buf += sizeof(uint32_t); + + *((uint32_t *)buf) = cpu_to_be32(arg->interval_ms); + size += sizeof(uint32_t); + buf += sizeof(uint32_t); + + *((uint32_t *)buf) = cpu_to_be32(arg->num_tasks); + size += sizeof(uint32_t); + + return size; +} + +static int ping_mdm_data_cb_unregister_arg(struct msm_rpc_client *client, + void *buf, void *data) +{ + struct ping_mdm_unregister_data_cb_arg *arg; + int cb_id; + + arg = (struct ping_mdm_unregister_data_cb_arg *)data; + + cb_id = msm_rpc_add_cb_func(client, (void *)arg->cb_func); + if (cb_id < 0) + return cb_id; + + *((uint32_t *)buf) = cpu_to_be32((uint32_t)cb_id); + + return sizeof(uint32_t); +} + +static int ping_mdm_data_cb_register_ret(struct msm_rpc_client *client, + void *buf, void *data) +{ + struct ping_mdm_register_data_cb_ret *data_ptr, *buf_ptr; + + data_ptr = (struct ping_mdm_register_data_cb_ret *)data; + buf_ptr = (struct ping_mdm_register_data_cb_ret *)buf; + + data_ptr->result = be32_to_cpu(buf_ptr->result); + return 0; +} + +static int ping_mdm_register_data_cb( + struct msm_rpc_client *client, + struct ping_mdm_register_data_cb_arg *arg, + struct ping_mdm_register_data_cb_ret *ret) +{ + return msm_rpc_client_req(client, + PING_MDM_REGISTER_DATA_CB_PROC, + ping_mdm_data_cb_register_arg, arg, + ping_mdm_data_cb_register_ret, ret, -1); +} + +static int ping_mdm_unregister_data_cb( + struct msm_rpc_client *client, + struct ping_mdm_unregister_data_cb_arg *arg, + struct ping_mdm_unregister_data_cb_ret *ret) +{ + return msm_rpc_client_req(client, + PING_MDM_UNREGISTER_DATA_CB_PROC, + ping_mdm_data_cb_unregister_arg, arg, + ping_mdm_data_cb_register_ret, ret, -1); +} + +struct ping_mdm_data_arg { + uint32_t *data; + uint32_t size; +}; + +struct ping_mdm_data_ret { + uint32_t result; +}; + +static int ping_mdm_data_register_arg(struct msm_rpc_client *client, + void *buf, void *data) +{ + int i; + struct ping_mdm_data_arg *data_ptr; + + data_ptr = (struct ping_mdm_data_arg *)data; + + *((uint32_t *)buf) = cpu_to_be32(data_ptr->size); + buf += sizeof(data_ptr->size); + for (i = 0; i < data_ptr->size; i++) { + *((uint32_t *)buf) = cpu_to_be32(data_ptr->data[i]); + buf += sizeof(*data_ptr->data); + } + + *((uint32_t *)buf) = cpu_to_be32(data_ptr->size); + + return (data_ptr->size * sizeof(uint32_t)) + + (sizeof(data_ptr->size) * 2); +} + +static int ping_mdm_data_register_ret(struct msm_rpc_client *client, + void *buf, void *data) +{ + struct ping_mdm_data_ret *data_ptr, *buf_ptr; + + data_ptr = (struct ping_mdm_data_ret *)data; + buf_ptr = (struct ping_mdm_data_ret *)buf; + + data_ptr->result = be32_to_cpu(buf_ptr->result); + return 0; +} + +static int ping_mdm_data_register( + struct msm_rpc_client *client, + struct ping_mdm_data_arg *arg, + struct ping_mdm_data_ret *ret) +{ + return msm_rpc_client_req(client, + PING_MDM_REGISTER_DATA_PROC, + ping_mdm_data_register_arg, arg, + ping_mdm_data_register_ret, ret, -1); +} + +struct ping_mdm_register_arg { + int (*cb_func)(struct ping_mdm_register_cb_arg *, void *); + int num; +}; + +struct ping_mdm_unregister_arg { + int (*cb_func)(struct ping_mdm_register_cb_arg *, void *); +}; + +struct ping_mdm_register_ret { + uint32_t result; +}; + +struct ping_mdm_unregister_ret { + uint32_t result; +}; + +static int ping_mdm_register_arg(struct msm_rpc_client *client, + void *buf, void *data) +{ + struct ping_mdm_register_arg *arg; + int cb_id, size = 0; + + arg = (struct ping_mdm_register_arg *)data; + + cb_id = msm_rpc_add_cb_func(client, (void *)arg->cb_func); + if (cb_id < 0) + return cb_id; + + *((uint32_t *)buf) = cpu_to_be32((uint32_t)cb_id); + size += sizeof(uint32_t); + buf += sizeof(uint32_t); + + *((int32_t *)buf) = cpu_to_be32(arg->num); + size += sizeof(uint32_t); + + return size; +} + +static int ping_mdm_unregister_arg(struct msm_rpc_client *client, + void *buf, void *data) +{ + struct ping_mdm_unregister_arg *arg; + int cb_id; + + arg = (struct ping_mdm_unregister_arg *)data; + + cb_id = msm_rpc_add_cb_func(client, (void *)arg->cb_func); + if (cb_id < 0) + return cb_id; + + *((uint32_t *)buf) = cpu_to_be32((uint32_t)cb_id); + + return sizeof(uint32_t); +} + +static int ping_mdm_register_ret(struct msm_rpc_client *client, + void *buf, void *data) +{ + struct ping_mdm_register_ret *data_ptr, *buf_ptr; + + data_ptr = (struct ping_mdm_register_ret *)data; + buf_ptr = (struct ping_mdm_register_ret *)buf; + + data_ptr->result = be32_to_cpu(buf_ptr->result); + + return 0; +} + +static int ping_mdm_register( + struct msm_rpc_client *client, + struct ping_mdm_register_arg *arg, + struct ping_mdm_register_ret *ret) +{ + return msm_rpc_client_req(client, + PING_MDM_REGISTER_PROC, + ping_mdm_register_arg, arg, + ping_mdm_register_ret, ret, -1); +} + +static int ping_mdm_unregister( + struct msm_rpc_client *client, + struct ping_mdm_unregister_arg *arg, + struct ping_mdm_unregister_ret *ret) +{ + return msm_rpc_client_req(client, + PING_MDM_UNREGISTER_PROC, + ping_mdm_unregister_arg, arg, + ping_mdm_register_ret, ret, -1); +} + +static int ping_mdm_null(struct msm_rpc_client *client, + void *arg, void *ret) +{ + return msm_rpc_client_req(client, PING_MDM_NULL_PROC, + NULL, NULL, NULL, NULL, -1); +} + +static int ping_mdm_close(void) +{ + mutex_lock(&ping_mdm_lock); + if (--open_count == 0) { + msm_rpc_unregister_client(rpc_client); + pr_info("%s: disconnected from remote ping server\n", + __func__); + } + mutex_unlock(&ping_mdm_lock); + return 0; +} + +static struct msm_rpc_client *ping_mdm_init(void) +{ + mutex_lock(&ping_mdm_lock); + if (open_count == 0) { + rpc_client = msm_rpc_register_client("pingdef", + PING_MDM_PROG, + PING_MDM_VERS, 1, + ping_mdm_cb_func); + if (!IS_ERR(rpc_client)) + open_count++; + } + mutex_unlock(&ping_mdm_lock); + return rpc_client; +} + +static struct dentry *dent; + +static DEFINE_MUTEX(ping_mdm_cb_lock); +static LIST_HEAD(ping_mdm_cb_list); +static uint32_t test_res; + +static int reg_cb_num, reg_cb_num_req; +static int data_cb_num, data_cb_num_req; +static int reg_done_flag, data_cb_done_flag; +static DECLARE_WAIT_QUEUE_HEAD(reg_test_wait); +static DECLARE_WAIT_QUEUE_HEAD(data_cb_test_wait); + +static int ping_mdm_data_register_test(void) +{ + int i, rc = 0; + uint32_t my_data[64]; + uint32_t my_sum = 0; + struct ping_mdm_data_arg data_arg; + struct ping_mdm_data_ret data_ret; + + for (i = 0; i < 64; i++) { + my_data[i] = (42 + i); + my_sum ^= (42 + i); + } + + data_arg.data = my_data; + data_arg.size = 64; + + rc = ping_mdm_data_register(rpc_client, &data_arg, &data_ret); + if (rc) + return rc; + + if (my_sum != data_ret.result) { + pr_err("%s: sum mismatch %d %d\n", + __func__, my_sum, data_ret.result); + rc = -1; + } + + return rc; +} + +static int ping_mdm_test_register_data_cb( + struct ping_mdm_register_data_cb_cb_arg *arg, + struct ping_mdm_register_data_cb_cb_ret *ret) +{ + uint32_t i, sum = 0; + + pr_info("%s: received cb_id %d, size = %d, sum = %u\n", + __func__, arg->cb_id, arg->size, arg->sum); + + if (arg->data) + for (i = 0; i < arg->size; i++) + sum ^= arg->data[i]; + + if (sum != arg->sum) + pr_err("%s: sum mismatch %d %d\n", __func__, sum, arg->sum); + + data_cb_num++; + if (data_cb_num == data_cb_num_req) { + data_cb_done_flag = 1; + wake_up(&data_cb_test_wait); + } + + ret->result = 1; + return 0; +} + +static int ping_mdm_data_cb_register_test(void) +{ + int rc = 0; + struct ping_mdm_register_data_cb_arg reg_arg; + struct ping_mdm_unregister_data_cb_arg unreg_arg; + struct ping_mdm_register_data_cb_ret reg_ret; + struct ping_mdm_unregister_data_cb_ret unreg_ret; + + data_cb_num = 0; + data_cb_num_req = 10; + data_cb_done_flag = 0; + + reg_arg.cb_func = ping_mdm_test_register_data_cb; + reg_arg.num = 10; + reg_arg.size = 64; + reg_arg.interval_ms = 10; + reg_arg.num_tasks = 1; + + rc = ping_mdm_register_data_cb(rpc_client, ®_arg, ®_ret); + if (rc) + return rc; + + pr_info("%s: data_cb_register result: 0x%x\n", + __func__, reg_ret.result); + wait_event(data_cb_test_wait, data_cb_done_flag); + + unreg_arg.cb_func = reg_arg.cb_func; + rc = ping_mdm_unregister_data_cb(rpc_client, &unreg_arg, &unreg_ret); + if (rc) + return rc; + + pr_info("%s: data_cb_unregister result: 0x%x\n", + __func__, unreg_ret.result); + + return 0; +} + +static int ping_mdm_test_register_cb( + struct ping_mdm_register_cb_arg *arg, void *ret) +{ + pr_info("%s: received cb_id %d, val = %d\n", + __func__, arg->cb_id, arg->val); + + reg_cb_num++; + if (reg_cb_num == reg_cb_num_req) { + reg_done_flag = 1; + wake_up(®_test_wait); + } + return 0; +} + +static int ping_mdm_register_test(void) +{ + int rc = 0; + struct ping_mdm_register_arg reg_arg; + struct ping_mdm_unregister_arg unreg_arg; + struct ping_mdm_register_ret reg_ret; + struct ping_mdm_unregister_ret unreg_ret; + + reg_cb_num = 0; + reg_cb_num_req = 10; + reg_done_flag = 0; + + reg_arg.num = 10; + reg_arg.cb_func = ping_mdm_test_register_cb; + + rc = ping_mdm_register(rpc_client, ®_arg, ®_ret); + if (rc) + return rc; + + pr_info("%s: register result: 0x%x\n", + __func__, reg_ret.result); + + wait_event(reg_test_wait, reg_done_flag); + + unreg_arg.cb_func = ping_mdm_test_register_cb; + rc = ping_mdm_unregister(rpc_client, &unreg_arg, &unreg_ret); + if (rc) + return rc; + + pr_info("%s: unregister result: 0x%x\n", + __func__, unreg_ret.result); + + return 0; +} + +static int ping_mdm_null_test(void) +{ + return ping_mdm_null(rpc_client, NULL, NULL); +} + +static int ping_test_release(struct inode *ip, struct file *fp) +{ + return ping_mdm_close(); +} + +static int ping_test_open(struct inode *ip, struct file *fp) +{ + struct msm_rpc_client *client; + + client = ping_mdm_init(); + if (IS_ERR(client)) { + pr_err("%s: couldn't open ping client\n", __func__); + return PTR_ERR(client); + } else + pr_info("%s: connected to remote ping server\n", + __func__); + + return 0; +} + +static ssize_t ping_test_read(struct file *fp, char __user *buf, + size_t count, loff_t *pos) +{ + char _buf[16]; + + snprintf(_buf, sizeof(_buf), "%i\n", test_res); + + return simple_read_from_buffer(buf, count, pos, _buf, strlen(_buf)); +} + +static ssize_t ping_test_write(struct file *fp, const char __user *buf, + size_t count, loff_t *pos) +{ + unsigned char cmd[64]; + int len; + + if (count < 1) + return 0; + + len = count > 63 ? 63 : count; + + if (copy_from_user(cmd, buf, len)) + return -EFAULT; + + cmd[len] = 0; + + /* lazy */ + if (cmd[len-1] == '\n') { + cmd[len-1] = 0; + len--; + } + + if (!strncmp(cmd, "null_test", 64)) + test_res = ping_mdm_null_test(); + else if (!strncmp(cmd, "reg_test", 64)) + test_res = ping_mdm_register_test(); + else if (!strncmp(cmd, "data_reg_test", 64)) + test_res = ping_mdm_data_register_test(); + else if (!strncmp(cmd, "data_cb_reg_test", 64)) + test_res = ping_mdm_data_cb_register_test(); + else + test_res = -EINVAL; + + return count; +} + +static const struct file_operations debug_ops = { + .owner = THIS_MODULE, + .open = ping_test_open, + .read = ping_test_read, + .write = ping_test_write, + .release = ping_test_release, +}; + +static void __exit ping_test_exit(void) +{ + debugfs_remove(dent); +} + +static int __init ping_test_init(void) +{ + dent = debugfs_create_file("ping_mdm", 0444, 0, NULL, &debug_ops); + test_res = 0; + open_count = 0; + return 0; +} + +module_init(ping_test_init); +module_exit(ping_test_exit); + +MODULE_DESCRIPTION("PING TEST Driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/arch/arm/mach-msm/smd_rpc_ping.c b/arch/arm/mach-msm/smd_rpc_ping.c deleted file mode 100644 index 17058412c0c0..000000000000 --- a/arch/arm/mach-msm/smd_rpc_ping.c +++ /dev/null @@ -1,699 +0,0 @@ -/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Code Aurora Forum nor - * the names of its contributors may be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * Alternatively, provided that this notice is retained in full, this software - * may be relicensed by the recipient under the terms of the GNU General Public - * License version 2 ("GPL") and only version 2, in which case the provisions of - * the GPL apply INSTEAD OF those given above. If the recipient relicenses the - * software under the GPL, then the identification text in the MODULE_LICENSE - * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a - * recipient changes the license terms to the GPL, subsequent recipients shall - * not relicense under alternate licensing terms, including the BSD or dual - * BSD/GPL terms. In addition, the following license statement immediately - * below and between the words START and END shall also then apply when this - * software is relicensed under the GPL: - * - * START - * - * 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. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * END - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - */ - -/* - * SMD RPC PING MODEM Driver - */ - -#include -#include -#include -#include -#include -#include -#include - -#define PING_TEST_BASE 0x31 - -#define PTIOC_NULL_TEST _IO(PING_TEST_BASE, 1) -#define PTIOC_REG_TEST _IO(PING_TEST_BASE, 2) -#define PTIOC_DATA_REG_TEST _IO(PING_TEST_BASE, 3) -#define PTIOC_DATA_CB_REG_TEST _IO(PING_TEST_BASE, 4) -#define PTIOC_USE_MULTI_CLIENTS _IO(PING_TEST_BASE, 5) -#define PTIOC_USE_DEFAULT_CLIENT _IO(PING_TEST_BASE, 6) - -#define PING_MDM_PROG 0x30000081 -#define PING_MDM_VERS 0x00010001 -#define PING_MDM_CB_PROG 0x31000081 -#define PING_MDM_CB_VERS 0x00010001 - -#define PING_MDM_NULL_PROC 0 -#define PING_MDM_RPC_GLUE_CODE_INFO_REMOTE_PROC 1 -#define PING_MDM_REGISTER_PROC 2 -#define PING_MDM_UNREGISTER_PROC 3 -#define PING_MDM_REGISTER_DATA_PROC 4 -#define PING_MDM_UNREGISTER_DATA_CB_PROC 5 -#define PING_MDM_REGISTER_DATA_CB_PROC 6 - -#define PING_MDM_DATA_CB_PROC 1 -#define PING_MDM_CB_PROC 2 - -static struct msm_rpc_client *rpc_client; -static uint32_t test_res; -static uint32_t open_count; -static uint32_t ping_test_use_multi_clients; -static DEFINE_MUTEX(ping_mdm_lock); -static DEFINE_MUTEX(ping_mdm_cb_lock); -static LIST_HEAD(ping_mdm_cb_list); -static atomic_t next_cb_id = ATOMIC_INIT(1); - -struct ping_mdm_cb_item { - struct list_head list; - - uint32_t cb_id; - - wait_queue_head_t wait; - int done_flag; - - int num; - int num_req; -}; - -struct ping_mdm_cb_item *ping_mdm_get_cb_item(uint32_t cb_id) -{ - struct ping_mdm_cb_item *cb_item; - - mutex_lock(&ping_mdm_cb_lock); - list_for_each_entry(cb_item, &ping_mdm_cb_list, list) { - if (cb_item->cb_id == cb_id) { - mutex_unlock(&ping_mdm_cb_lock); - return cb_item; - } - } - mutex_unlock(&ping_mdm_cb_lock); - return NULL; -} - -static void ping_mdm_register_cb(struct msm_rpc_client *client, - void *buffer, int in_size) -{ - struct rpc_request_hdr *req; - int rc, num; - void *buf; - uint32_t cb_id; - struct ping_mdm_cb_item *cb_item; - - req = (struct rpc_request_hdr *)buffer; - buf = (void *)(req + 1); - - cb_id = be32_to_cpu(*(uint32_t *)buf); - buf += sizeof(uint32_t); - num = be32_to_cpu(*(int32_t *)buf); - buf += sizeof(int32_t); - pr_info("%s: received cb_id %d, val = %d\n", __func__, cb_id, num); - - msm_rpc_start_accepted_reply(client, be32_to_cpu(req->xid), - RPC_ACCEPTSTAT_SUCCESS); - rc = msm_rpc_send_accepted_reply(client, 0); - if (rc) { - pr_err("%s: sending reply failed: %d\n", __func__, rc); - return; - } - - cb_item = ping_mdm_get_cb_item(cb_id); - if (!cb_item) { - pr_err("%s: no cb item found\n", __func__); - return; - } - cb_item->num++; - - if (cb_item->num == cb_item->num_req) { - cb_item->done_flag = 1; - wake_up(&cb_item->wait); - } -} - -static void ping_mdm_data_cb(struct msm_rpc_client *client, - void *buffer, int in_size) -{ - struct rpc_request_hdr *req; - int rc, i; - void *buf, *reply; - uint32_t cb_id = 0; - uint32_t size, *data, req_size, sum, my_sum; - struct ping_mdm_cb_item *cb_item; - - req = (struct rpc_request_hdr *)buffer; - buf = (void *)(req + 1); - - my_sum = 0; - cb_id = be32_to_cpu(*(uint32_t *)buf); - buf += sizeof(uint32_t); - size = be32_to_cpu(*(uint32_t *)buf); - buf += sizeof(uint32_t); - data = (uint32_t *)buf; - buf += sizeof(uint32_t) * size; - for (i = 0; i < size; i++) - my_sum = be32_to_cpu(*(data + i)) ^ my_sum; - - req_size = be32_to_cpu(*(uint32_t *)buf); - buf += sizeof(uint32_t); - sum = be32_to_cpu(*(uint32_t *)buf); - pr_info("%s: received cb_id %d, xid = %d, size = %d," - "req_size = %d, sum = %u, my_sum = %u\n", __func__, - cb_id, be32_to_cpu(req->xid), size, req_size, sum, my_sum); - - if (sum != my_sum) - pr_err("%s: sum mismatch\n", __func__); - - reply = msm_rpc_start_accepted_reply(client, be32_to_cpu(req->xid), - RPC_ACCEPTSTAT_SUCCESS); - *(uint32_t *)reply = cpu_to_be32(1); - rc = msm_rpc_send_accepted_reply(client, sizeof(uint32_t)); - if (rc) - pr_err("%s: sending reply failed: %d\n", __func__, rc); - - cb_item = ping_mdm_get_cb_item(cb_id); - if (!cb_item) { - pr_err("%s: no cb item found\n", __func__); - return; - } - cb_item->num++; - - if (cb_item->num == cb_item->num_req) { - cb_item->done_flag = 1; - wake_up(&cb_item->wait); - } -} - -static int ping_mdm_cb_func(struct msm_rpc_client *client, - void *buffer, int in_size) -{ - struct rpc_request_hdr *req; - - req = (struct rpc_request_hdr *)buffer; - - switch (be32_to_cpu(req->procedure)) { - case PING_MDM_CB_PROC: - ping_mdm_register_cb(client, buffer, in_size); - break; - case PING_MDM_DATA_CB_PROC: - ping_mdm_data_cb(client, buffer, in_size); - break; - default: - pr_err("%s: procedure not supported %d\n", __func__, - be32_to_cpu(req->procedure)); - break; - } - return 0; -} - -static struct msm_rpc_client *ping_mdm_get_client(char *name) -{ - struct msm_rpc_client *client; - - if (ping_test_use_multi_clients) { - client = msm_rpc_register_client(name, - PING_MDM_PROG, - PING_MDM_VERS, 0, - ping_mdm_cb_func); - if (IS_ERR(client)) - pr_err("%s: could not open rpc client:%ld\n", - __func__, PTR_ERR(client)); - } else - client = rpc_client; - - return client; -} - -static struct ping_mdm_cb_item *ping_mdm_create_cb_item(uint32_t cb_id, - int num_req) -{ - struct ping_mdm_cb_item *cb_item; - - cb_item = kmalloc(sizeof(struct ping_mdm_cb_item), GFP_KERNEL); - if (!cb_item) - return ERR_PTR(-ENOMEM); - - INIT_LIST_HEAD(&cb_item->list); - cb_item->num_req = num_req; - cb_item->num = 0; - init_waitqueue_head(&cb_item->wait); - cb_item->done_flag = 0; - cb_item->cb_id = cb_id; - - mutex_lock(&ping_mdm_cb_lock); - list_add_tail(&cb_item->list, &ping_mdm_cb_list); - mutex_unlock(&ping_mdm_cb_lock); - - return cb_item; -} - -static void ping_mdm_destroy_cb_item(struct ping_mdm_cb_item *cb_item) -{ - mutex_lock(&ping_mdm_cb_lock); - list_del(&cb_item->list); - mutex_unlock(&ping_mdm_cb_lock); - - kfree(cb_item); -} - -static int ping_mdm_data_cb_register_arg(struct msm_rpc_client *client, - void *buf, void *data) -{ - int size = 0; - - *((uint32_t *)buf) = cpu_to_be32((uint32_t)data); - size += sizeof(uint32_t); - buf += sizeof(uint32_t); - - *((uint32_t *)buf) = cpu_to_be32(10); - size += sizeof(uint32_t); - buf += sizeof(uint32_t); - - *((uint32_t *)buf) = cpu_to_be32(64); - size += sizeof(uint32_t); - buf += sizeof(uint32_t); - - *((uint32_t *)buf) = cpu_to_be32(10); - size += sizeof(uint32_t); - buf += sizeof(uint32_t); - - *((uint32_t *)buf) = cpu_to_be32(1); - size += sizeof(uint32_t); - buf += sizeof(uint32_t); - - return size; -} - -static int ping_mdm_data_cb_register_arg_unreg(struct msm_rpc_client *client, - void *buf, void *data) -{ - *((uint32_t *)buf) = cpu_to_be32((uint32_t)data); - return sizeof(uint32_t); -} - -static int ping_mdm_data_cb_register_result(struct msm_rpc_client *client, - void *buf, void *data) -{ - uint32_t result; - - result = *((uint32_t *)buf); - pr_info("%s: request completed: 0x%x\n", __func__, result); - - return 0; -} - -static int ping_mdm_data_cb_register_test(void) -{ - int rc; - struct ping_mdm_cb_item *cb_item; - struct msm_rpc_client *client; - - client = ping_mdm_get_client("pingdatacb"); - if (IS_ERR(client)) - return PTR_ERR(client); - - cb_item = ping_mdm_create_cb_item(atomic_add_return(1, &next_cb_id), - 10); - if (IS_ERR(cb_item)) { - rc = PTR_ERR(cb_item); - goto release_client; - } - - rc = msm_rpc_client_req(client, - PING_MDM_REGISTER_DATA_CB_PROC, - ping_mdm_data_cb_register_arg, - (void *)(cb_item->cb_id), - ping_mdm_data_cb_register_result, - NULL, -1); - if (rc) - goto free_and_release_client; - - wait_event(cb_item->wait, cb_item->done_flag); - - rc = msm_rpc_client_req(client, - PING_MDM_UNREGISTER_DATA_CB_PROC, - ping_mdm_data_cb_register_arg_unreg, - (void *)(cb_item->cb_id), - ping_mdm_data_cb_register_result, - NULL, -1); - - - free_and_release_client: - ping_mdm_destroy_cb_item(cb_item); - release_client: - if (client != rpc_client) - msm_rpc_unregister_client(client); - - return rc; -} - -static int ping_mdm_data_register_arg(struct msm_rpc_client *client, - void *buf, void *data) -{ - int i, size = 0; - - *((uint32_t *)buf) = cpu_to_be32(64); - size += sizeof(uint32_t); - buf += size; - for (i = 0; i < 64; i++) { - *((uint32_t *)buf) = cpu_to_be32(42 + i); - size += sizeof(uint32_t); - buf += sizeof(uint32_t); - *(uint32_t *)data = (*(uint32_t *)data) ^ (42 | i); - } - *((uint32_t *)buf) = cpu_to_be32(64); - size += sizeof(uint32_t); - - return size; -} - -static int ping_mdm_data_register_result(struct msm_rpc_client *client, - void *buf, void *data) -{ - uint32_t result; - - result = *((uint32_t *)buf); - pr_info("%s: request completed: 0x%x\n", __func__, result); - - if (result != *(uint32_t *)data) - pr_err("%s: sum mismatch\n", __func__); - - return 0; -} - -static int ping_mdm_data_register_test(void) -{ - int rc = 0; - struct msm_rpc_client *client; - uint32_t my_sum = 0; - - client = ping_mdm_get_client("pingdata"); - if (IS_ERR(client)) - return PTR_ERR(client); - - - rc = msm_rpc_client_req(client, - PING_MDM_REGISTER_DATA_PROC, - ping_mdm_data_register_arg, &my_sum, - ping_mdm_data_register_result, &my_sum, -1); - - if (client != rpc_client) - msm_rpc_unregister_client(client); - - return rc; -} - -static int ping_mdm_register_arg(struct msm_rpc_client *client, - void *buf, void *data) -{ - int num, size = 0; - - /* revist to pass in num also through data */ - num = 10; - *((uint32_t *)buf) = cpu_to_be32((uint32_t)data); - size += sizeof(uint32_t); - buf += size; - - *((int *)buf) = cpu_to_be32(num); - size += sizeof(int); - - return size; -} - -static int ping_mdm_register_arg_unreg(struct msm_rpc_client *client, - void *buf, void *data) -{ - *((uint32_t *)buf) = cpu_to_be32((uint32_t)data); - return sizeof(uint32_t); -} - -static int ping_mdm_register_result(struct msm_rpc_client *client, - void *buf, void *data) -{ - uint32_t result; - - result = *((uint32_t *)buf); - pr_info("%s: request completed: 0x%x\n", __func__, result); - - return 0; -} - -static int ping_mdm_register_test(void) -{ - int rc; - struct ping_mdm_cb_item *cb_item; - struct msm_rpc_client *client; - - client = ping_mdm_get_client("pingreg"); - if (IS_ERR(client)) - return PTR_ERR(client); - - cb_item = ping_mdm_create_cb_item(atomic_add_return(1, &next_cb_id), - 10); - if (IS_ERR(cb_item)) { - rc = PTR_ERR(cb_item); - goto release_client; - } - - rc = msm_rpc_client_req(client, - PING_MDM_REGISTER_PROC, - ping_mdm_register_arg, - (void *)(cb_item->cb_id), - ping_mdm_register_result, - NULL, -1); - if (rc) - goto free_and_release_client; - - wait_event(cb_item->wait, cb_item->done_flag); - - rc = msm_rpc_client_req(client, - PING_MDM_UNREGISTER_PROC, - ping_mdm_register_arg_unreg, - (void *)(cb_item->cb_id), - ping_mdm_register_result, - NULL, -1); - - free_and_release_client: - ping_mdm_destroy_cb_item(cb_item); - release_client: - if (client != rpc_client) - msm_rpc_unregister_client(client); - - return rc; -} - -static int ping_mdm_null_test(void) -{ - int rc; - struct msm_rpc_client *client; - - client = ping_mdm_get_client("pingnull"); - if (IS_ERR(client)) - return PTR_ERR(client); - - rc = msm_rpc_client_req(client, PING_MDM_NULL_PROC, NULL, NULL, - NULL, NULL, -1); - - if (client != rpc_client) - msm_rpc_unregister_client(client); - - return rc; -} - -static int ping_test_release(struct inode *ip, struct file *fp) -{ - mutex_lock(&ping_mdm_lock); - if (--open_count == 0) { - msm_rpc_unregister_client(rpc_client); - pr_info("%s: disconnected from remote ping server\n", - __func__); - kfree(fp->private_data); - } - mutex_unlock(&ping_mdm_lock); - return 0; -} - -static int ping_test_open(struct inode *ip, struct file *fp) -{ - mutex_lock(&ping_mdm_lock); - if (open_count++ == 0) { - rpc_client = msm_rpc_register_client("pingdef", - PING_MDM_PROG, - PING_MDM_VERS, 1, - ping_mdm_cb_func); - if (IS_ERR(rpc_client)) { - pr_err("%s: couldn't open rpc client\n", __func__); - return PTR_ERR(rpc_client); - } - pr_info("%s: connected to remote ping server\n", __func__); - } - mutex_unlock(&ping_mdm_lock); - return 0; -} - -static int ping_test_ioctl(struct inode *ip, struct file *fp, - unsigned int cmd, unsigned long arg) -{ - int rc; - - switch (cmd) { - default: - return -ENOTTY; - - case PTIOC_NULL_TEST: - rc = ping_mdm_null_test(); - break; - case PTIOC_REG_TEST: - rc = ping_mdm_register_test(); - break; - case PTIOC_DATA_REG_TEST: - rc = ping_mdm_data_register_test(); - break; - case PTIOC_DATA_CB_REG_TEST: - rc = ping_mdm_data_cb_register_test(); - break; - case PTIOC_USE_MULTI_CLIENTS: - ping_test_use_multi_clients = 1; - pr_info("%s: tests to use multiple clients\n", __func__); - return 0; - case PTIOC_USE_DEFAULT_CLIENT: - ping_test_use_multi_clients = 0; - pr_info("%s: tests to use default client\n", __func__); - return 0; - } - - if (rc) - pr_info("%s: ping mdm test FAILed: %d\n", __func__, rc); - else - pr_info("%s: ping mdm test PASSed\n", __func__); - - return 0; -} - -static ssize_t ping_test_read(struct file *fp, char __user *buf, - size_t count, loff_t *pos) -{ - char _buf[16]; - - snprintf(_buf, sizeof(_buf), "%i\n", test_res); - - return simple_read_from_buffer(buf, count, pos, _buf, strlen(_buf)); -} - -static ssize_t ping_test_write(struct file *fp, const char __user *buf, - size_t count, loff_t *pos) -{ - unsigned char cmd[64]; - int len; - - if (count < 1) - return 0; - - len = count > 63 ? 63 : count; - - if (copy_from_user(cmd, buf, len)) - return -EFAULT; - - cmd[len] = 0; - - /* lazy */ - if (cmd[len-1] == '\n') { - cmd[len-1] = 0; - len--; - } - - if (!strncmp(cmd, "null_test", 64)) { - test_res = ping_mdm_null_test(); - } else if (!strncmp(cmd, "reg_test", 64)) { - test_res = ping_mdm_register_test(); - } else if (!strncmp(cmd, "data_reg_test", 64)) { - test_res = ping_mdm_data_register_test(); - } else if (!strncmp(cmd, "data_cb_reg_test", 64)) { - test_res = ping_mdm_data_cb_register_test(); - } else if (!strncmp(cmd, "use_multi_clients", 64)) { - ping_test_use_multi_clients = 1; - pr_info("%s: tests to use multiple clients\n", __func__); - } else if (!strncmp(cmd, "use_default_client", 64)) { - ping_test_use_multi_clients = 0; - pr_info("%s: tests to use default client\n", __func__); - } - - return count; -} - -static const struct file_operations ping_test_fops = { - .owner = THIS_MODULE, - .open = ping_test_open, - .read = ping_test_read, - .write = ping_test_write, - .release = ping_test_release, - .ioctl = ping_test_ioctl, -}; - -static struct miscdevice ping_test_device = { - .minor = MISC_DYNAMIC_MINOR, - .name = "ping_test", - .fops = &ping_test_fops, -}; - -static void __exit ping_test_exit(void) -{ - misc_deregister(&ping_test_device); -} - -static int __init ping_test_init(void) -{ - int rc = 0; - - test_res = 0; - open_count = 0; - ping_test_use_multi_clients = 0; - rc = misc_register(&ping_test_device); - if (rc) - pr_err("%s: ping_test_device reg fail\n", __func__); - - return rc; -} - - -module_init(ping_test_init); -module_exit(ping_test_exit); - -MODULE_DESCRIPTION("PING TEST Driver"); -MODULE_LICENSE("Dual BSD/GPL"); -- cgit v1.2.3 From 443f31874ba61ca5d1132facefd11824bb198a3c Mon Sep 17 00:00:00 2001 From: "Vishwanathapura, Niranjana" Date: Mon, 22 Jun 2009 11:23:38 -0600 Subject: msm: Add OEM RAPI RPC Client Driver. Add oem rapi rpc client module. This module implements the oem rapi client rpc apis and also provides open/close/read/write test access to the userspace. This module can be used by OEMs to implement their RPC client drivers in the kernel. Signed-off-by: Niranjana Vishwanathapura --- arch/arm/mach-msm/Kconfig | 7 + arch/arm/mach-msm/Makefile | 1 + arch/arm/mach-msm/include/mach/oem_rapi_client.h | 118 ++++++ arch/arm/mach-msm/oem_rapi_client.c | 474 +++++++++++++++++++++++ 4 files changed, 600 insertions(+) create mode 100644 arch/arm/mach-msm/include/mach/oem_rapi_client.h create mode 100644 arch/arm/mach-msm/oem_rapi_client.c (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index 92f0198c46c9..d4e860f5ba22 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -435,6 +435,13 @@ config MSM_RPC_PING help Implements MSM rpc ping test module. +config MSM_RPC_OEM_RAPI + depends on MSM_ONCRPCROUTER + default m + bool "MSM oem rapi" + help + Implements MSM oem rapi client module. + config MSM_RPCSERVER_HANDSET depends on MSM_ONCRPCROUTER default y diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 8572b5d62db5..2a65859efb6f 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -31,6 +31,7 @@ obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_device.o obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_servers.o obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_clients.o obj-$(CONFIG_MSM_RPC_PING) += ping_mdm_rpc_client.o +obj-$(CONFIG_MSM_RPC_OEM_RAPI) += oem_rapi_client.o obj-$(CONFIG_MSM_RPCSERVERS) += rpc_server_dog_keepalive.o obj-$(CONFIG_MSM_RPCSERVERS) += rpc_server_time_remote.o obj-$(CONFIG_MSM_DALRPC) += dal.o diff --git a/arch/arm/mach-msm/include/mach/oem_rapi_client.h b/arch/arm/mach-msm/include/mach/oem_rapi_client.h new file mode 100644 index 000000000000..3d48d884110e --- /dev/null +++ b/arch/arm/mach-msm/include/mach/oem_rapi_client.h @@ -0,0 +1,118 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * END + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __ASM__ARCH_OEM_RAPI_CLIENT_H +#define __ASM__ARCH_OEM_RAPI_CLIENT_H + +/* + * OEM RAPI CLIENT Driver header file + */ + +#include + +enum { + OEM_RAPI_CLIENT_EVENT_NONE = 0, + + /* + * list of oem rapi client events + */ + + OEM_RAPI_CLIENT_EVENT_MAX + +}; + +struct oem_rapi_client_streaming_func_cb_arg { + uint32_t event; + void *handle; + uint32_t in_len; + char *input; + uint32_t out_len_valid; + uint32_t output_valid; + uint32_t output_size; +}; + +struct oem_rapi_client_streaming_func_cb_ret { + uint32_t *out_len; + char *output; +}; + +struct oem_rapi_client_streaming_func_arg { + uint32_t event; + int (*cb_func)(struct oem_rapi_client_streaming_func_cb_arg *, + struct oem_rapi_client_streaming_func_cb_ret *); + void *handle; + uint32_t in_len; + char *input; + uint32_t out_len_valid; + uint32_t output_valid; + uint32_t output_size; +}; + +struct oem_rapi_client_streaming_func_ret { + uint32_t *out_len; + char *output; +}; + +int oem_rapi_client_streaming_function( + struct msm_rpc_client *client, + struct oem_rapi_client_streaming_func_arg *arg, + struct oem_rapi_client_streaming_func_ret *ret); + +int oem_rapi_client_close(void); + +struct msm_rpc_client *oem_rapi_client_init(void); + +#endif diff --git a/arch/arm/mach-msm/oem_rapi_client.c b/arch/arm/mach-msm/oem_rapi_client.c new file mode 100644 index 000000000000..77ba7508cb73 --- /dev/null +++ b/arch/arm/mach-msm/oem_rapi_client.c @@ -0,0 +1,474 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* + * OEM RAPI CLIENT Driver source file + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define OEM_RAPI_PROG 0x3000006B +#define OEM_RAPI_VERS 0x00010001 + +#define OEM_RAPI_NULL_PROC 0 +#define OEM_RAPI_RPC_GLUE_CODE_INFO_REMOTE_PROC 1 +#define OEM_RAPI_STREAMING_FUNCTION_PROC 2 + +#define OEM_RAPI_CLIENT_MAX_OUT_BUFF_SIZE 128 + +static struct msm_rpc_client *rpc_client; +static uint32_t open_count; +static DEFINE_MUTEX(oem_rapi_client_lock); + +static int oem_rapi_client_cb(struct msm_rpc_client *client, + void *buffer, int in_size) +{ + struct rpc_request_hdr *req; + void *buf, *cb_func, *reply; + uint32_t cb_id, accept_status, size; + int rc; + + struct oem_rapi_client_streaming_func_cb_arg arg; + struct oem_rapi_client_streaming_func_cb_ret ret; + + arg.input = NULL; + ret.out_len = NULL; + ret.output = NULL; + + req = (struct rpc_request_hdr *)buffer; + buf = (void *)(req + 1); + + /* cb_id */ + cb_id = be32_to_cpu(*(uint32_t *)buf); + buf += sizeof(uint32_t); + + /* enum */ + arg.event = be32_to_cpu(*(uint32_t *)buf); + buf += sizeof(uint32_t); + + /* handle */ + arg.handle = (void *)be32_to_cpu(*(uint32_t *)buf); + buf += sizeof(uint32_t); + + /* in_len */ + arg.in_len = be32_to_cpu(*(uint32_t *)buf); + buf += sizeof(uint32_t); + + /* input */ + size = be32_to_cpu(*(uint32_t *)buf); + buf += sizeof(uint32_t); + if (size) { + arg.input = kmalloc(size, GFP_KERNEL); + if (arg.input) + memcpy(arg.input, buf, size); + else { + accept_status = RPC_ACCEPTSTAT_SYSTEM_ERR; + goto oem_rapi_send_ack; + } + } + buf += size; + if (size & 0x3) + buf += 4 - (size & 0x3); + + /* out_len */ + arg.out_len_valid = be32_to_cpu(*(uint32_t *)buf); + buf += sizeof(uint32_t); + if (arg.out_len_valid) { + ret.out_len = kmalloc(sizeof(*ret.out_len), GFP_KERNEL); + if (!ret.out_len) { + accept_status = RPC_ACCEPTSTAT_SYSTEM_ERR; + goto oem_rapi_send_ack; + } + } + + /* out */ + arg.output_valid = be32_to_cpu(*(uint32_t *)buf); + buf += sizeof(uint32_t); + if (arg.output_valid) { + arg.output_size = be32_to_cpu(*(uint32_t *)buf); + buf += sizeof(uint32_t); + ret.output = kmalloc(arg.output_size, GFP_KERNEL); + if (!ret.output) { + accept_status = RPC_ACCEPTSTAT_SYSTEM_ERR; + goto oem_rapi_send_ack; + } + } + + cb_func = msm_rpc_get_cb_func(client, cb_id); + if (cb_func) { + rc = ((int (*)(struct oem_rapi_client_streaming_func_cb_arg *, + struct oem_rapi_client_streaming_func_cb_ret *)) + cb_func)(&arg, &ret); + if (rc) + accept_status = RPC_ACCEPTSTAT_SYSTEM_ERR; + else + accept_status = RPC_ACCEPTSTAT_SUCCESS; + } else + accept_status = RPC_ACCEPTSTAT_SYSTEM_ERR; + + oem_rapi_send_ack: + reply = msm_rpc_start_accepted_reply(client, be32_to_cpu(req->xid), + accept_status); + + size = 0; + if (accept_status == RPC_ACCEPTSTAT_SUCCESS) { + *(uint32_t *)reply = cpu_to_be32((uint32_t)(ret.out_len != 0)); + reply += sizeof(uint32_t); + size += sizeof(uint32_t); + + if (ret.out_len) { + *(uint32_t *)reply = cpu_to_be32(*ret.out_len); + reply += sizeof(uint32_t); + size += sizeof(uint32_t); + } + + if (ret.output && ret.out_len) { + *(uint32_t *)reply = + cpu_to_be32((uint32_t)(*ret.out_len)); + reply += sizeof(uint32_t); + size += sizeof(uint32_t); + + memcpy(reply, ret.output, *ret.out_len); + size += *ret.out_len; + } else { + *(uint32_t *)reply = cpu_to_be32(0); + reply += sizeof(uint32_t); + size += sizeof(uint32_t); + } + } + rc = msm_rpc_send_accepted_reply(client, size); + if (rc) + pr_err("%s: sending reply failed: %d\n", __func__, rc); + + kfree(arg.input); + kfree(ret.out_len); + kfree(ret.output); + + return 0; +} + +static int oem_rapi_client_streaming_function_arg(struct msm_rpc_client *client, + void *buf, void *data) +{ + int size = 0; + int cb_id; + struct oem_rapi_client_streaming_func_arg *arg = data; + + /* enum */ + *((uint32_t *)buf) = cpu_to_be32(arg->event); + size += sizeof(uint32_t); + buf += sizeof(uint32_t); + + /* cb_id */ + cb_id = msm_rpc_add_cb_func(client, (void *)arg->cb_func); + if (cb_id < 0) + return cb_id; + *((uint32_t *)buf) = cpu_to_be32((uint32_t)cb_id); + size += sizeof(uint32_t); + buf += sizeof(uint32_t); + + /* handle */ + *((uint32_t *)buf) = cpu_to_be32((uint32_t)arg->handle); + size += sizeof(uint32_t); + buf += sizeof(uint32_t); + + /* in_len */ + *((uint32_t *)buf) = cpu_to_be32(arg->in_len); + size += sizeof(uint32_t); + buf += sizeof(uint32_t); + + /* input */ + *((uint32_t *)buf) = cpu_to_be32(arg->in_len); + size += sizeof(uint32_t); + buf += sizeof(uint32_t); + memcpy(buf, arg->input, arg->in_len); + size += arg->in_len; + buf += arg->in_len; + + /* out_len */ + *((uint32_t *)buf) = cpu_to_be32((uint32_t)(arg->out_len_valid)); + size += sizeof(uint32_t); + buf += sizeof(uint32_t); + + /* output */ + *((uint32_t *)buf) = cpu_to_be32((uint32_t)(arg->output_valid)); + size += sizeof(uint32_t); + buf += sizeof(uint32_t); + *((uint32_t *)buf) = cpu_to_be32(arg->output_size); + size += sizeof(uint32_t); + buf += sizeof(uint32_t); + + return size; +} + +static int oem_rapi_client_streaming_function_ret(struct msm_rpc_client *client, + void *buf, void *data) +{ + uint32_t data_present, size; + struct oem_rapi_client_streaming_func_ret *ret = data; + + /* out_len */ + data_present = be32_to_cpu(*(uint32_t *)buf); + buf += sizeof(uint32_t); + if (data_present && ret->out_len) + *ret->out_len = be32_to_cpu(*(uint32_t *)buf); + + /* output */ + size = be32_to_cpu(*(uint32_t *)buf); + buf += sizeof(uint32_t); + if (size && ret->output) + memcpy(ret->output, buf, size); + buf += size; + if (size & 0x3) + buf += 4 - (size & 0x3); + + return 0; +} + +int oem_rapi_client_streaming_function( + struct msm_rpc_client *client, + struct oem_rapi_client_streaming_func_arg *arg, + struct oem_rapi_client_streaming_func_ret *ret) +{ + return msm_rpc_client_req(client, + OEM_RAPI_STREAMING_FUNCTION_PROC, + oem_rapi_client_streaming_function_arg, arg, + oem_rapi_client_streaming_function_ret, + ret, -1); +} +EXPORT_SYMBOL(oem_rapi_client_streaming_function); + +int oem_rapi_client_close(void) +{ + mutex_lock(&oem_rapi_client_lock); + if (--open_count == 0) { + msm_rpc_unregister_client(rpc_client); + pr_info("%s: disconnected from remote oem rapi server\n", + __func__); + } + mutex_unlock(&oem_rapi_client_lock); + return 0; +} +EXPORT_SYMBOL(oem_rapi_client_close); + +struct msm_rpc_client *oem_rapi_client_init(void) +{ + mutex_lock(&oem_rapi_client_lock); + if (open_count == 0) { + rpc_client = msm_rpc_register_client("oemrapiclient", + OEM_RAPI_PROG, + OEM_RAPI_VERS, 0, + oem_rapi_client_cb); + if (!IS_ERR(rpc_client)) + open_count++; + } + mutex_unlock(&oem_rapi_client_lock); + return rpc_client; +} +EXPORT_SYMBOL(oem_rapi_client_init); + +#if defined(CONFIG_DEBUG_FS) + +static struct dentry *dent; +static int oem_rapi_client_test_res; + +static int oem_rapi_client_null(struct msm_rpc_client *client, + void *arg, void *ret) +{ + return msm_rpc_client_req(client, OEM_RAPI_NULL_PROC, + NULL, NULL, NULL, NULL, -1); +} + +static int oem_rapi_client_test_streaming_cb_func( + struct oem_rapi_client_streaming_func_cb_arg *arg, + struct oem_rapi_client_streaming_func_cb_ret *ret) +{ + uint32_t size; + pr_info("oem rapi client test cb func\n"); + + size = (arg->in_len < OEM_RAPI_CLIENT_MAX_OUT_BUFF_SIZE) ? + arg->in_len : OEM_RAPI_CLIENT_MAX_OUT_BUFF_SIZE; + + if (ret->out_len != 0) + *ret->out_len = size; + + if (ret->output != 0) + memcpy(ret->output, arg->input, size); + + return 0; +} + +static ssize_t debug_read(struct file *fp, char __user *buf, + size_t count, loff_t *pos) +{ + char _buf[16]; + + snprintf(_buf, sizeof(_buf), "%i\n", oem_rapi_client_test_res); + + return simple_read_from_buffer(buf, count, pos, _buf, strlen(_buf)); +} + +static ssize_t debug_write(struct file *fp, const char __user *buf, + size_t count, loff_t *pos) +{ + char input[OEM_RAPI_CLIENT_MAX_OUT_BUFF_SIZE]; + char output[OEM_RAPI_CLIENT_MAX_OUT_BUFF_SIZE]; + uint32_t out_len; + struct oem_rapi_client_streaming_func_arg arg; + struct oem_rapi_client_streaming_func_ret ret; + + unsigned char cmd[64]; + int len; + + if (count < 1) + return 0; + + len = count > 63 ? 63 : count; + + if (copy_from_user(cmd, buf, len)) + return -EFAULT; + + cmd[len] = 0; + + if (cmd[len-1] == '\n') { + cmd[len-1] = 0; + len--; + } + + if (!strncmp(cmd, "null", 64)) { + oem_rapi_client_test_res = oem_rapi_client_null(rpc_client, + NULL, NULL); + } else if (!strncmp(cmd, "streaming_func", 64)) { + memset(input, 5, 16); + arg.event = 0; + arg.cb_func = oem_rapi_client_test_streaming_cb_func; + arg.handle = (void *)20; + arg.in_len = 16; + arg.input = input; + arg.out_len_valid = 1; + arg.output_valid = 1; + arg.output_size = OEM_RAPI_CLIENT_MAX_OUT_BUFF_SIZE; + + ret.out_len = &out_len; + ret.output = output; + oem_rapi_client_test_res = oem_rapi_client_streaming_function( + rpc_client, &arg, &ret); + } else + oem_rapi_client_test_res = -EINVAL; + + if (oem_rapi_client_test_res) + pr_err("oem rapi client test fail %d\n", + oem_rapi_client_test_res); + else + pr_info("oem rapi client test passed\n"); + + return count; +} + +static int debug_release(struct inode *ip, struct file *fp) +{ + return oem_rapi_client_close(); +} + +static int debug_open(struct inode *ip, struct file *fp) +{ + struct msm_rpc_client *client; + client = oem_rapi_client_init(); + if (IS_ERR(client)) { + pr_err("%s: couldn't open oem rapi client\n", __func__); + return PTR_ERR(client); + } else + pr_info("%s: connected to remote oem rapi server\n", __func__); + + return 0; +} + +static const struct file_operations debug_ops = { + .owner = THIS_MODULE, + .open = debug_open, + .release = debug_release, + .read = debug_read, + .write = debug_write, +}; + +static void __exit oem_rapi_client_mod_exit(void) +{ + debugfs_remove(dent); +} + +static int __init oem_rapi_client_mod_init(void) +{ + dent = debugfs_create_file("oem_rapi", 0444, 0, NULL, &debug_ops); + open_count = 0; + oem_rapi_client_test_res = -1; + return 0; +} + +module_init(oem_rapi_client_mod_init); +module_exit(oem_rapi_client_mod_exit); + +#endif + +MODULE_DESCRIPTION("OEM RAPI CLIENT Driver"); +MODULE_LICENSE("Dual BSD/GPL"); -- cgit v1.2.3 From 34ed27776f9f90b68cda178810a563c9bdc1dc96 Mon Sep 17 00:00:00 2001 From: Willie Ruan Date: Fri, 24 Jul 2009 17:21:21 -0700 Subject: [ARM] msm: add new vreg IDs for MSM7X30 Signed-off-by: Willie Ruan --- arch/arm/mach-msm/vreg.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/vreg.c b/arch/arm/mach-msm/vreg.c index 5a5c023e044f..53e9119ded4a 100644 --- a/arch/arm/mach-msm/vreg.c +++ b/arch/arm/mach-msm/vreg.c @@ -74,6 +74,23 @@ static struct vreg vregs[] = { VREG("s3", 29, 0, 0), VREG("rfubm", 30, 0, 0), VREG("ncp", 31, 0, 0), + VREG("gp7", 32, 0, 0), + VREG("gp8", 33, 0, 0), + VREG("gp9", 34, 0, 0), + VREG("gp10", 35, 0, 0), + VREG("gp11", 36, 0, 0), + VREG("gp12", 37, 0, 0), + VREG("gp13", 38, 0, 0), + VREG("gp14", 39, 0, 0), + VREG("gp15", 40, 0, 0), + VREG("gp16", 41, 0, 0), + VREG("gp17", 42, 0, 0), + VREG("s4", 43, 0, 0), + VREG("usb2", 44, 0, 0), + VREG("wlan2", 45, 0, 0), + VREG("xo_out", 46, 0, 0), + VREG("lvsw0", 47, 0, 0), + VREG("lvsw0", 48, 0, 0), }; struct vreg *vreg_get(struct device *dev, const char *id) -- cgit v1.2.3 From bdd8c12bc49cafbadca79ea48da87a520579d9ef Mon Sep 17 00:00:00 2001 From: Brent DeGraaf Date: Wed, 29 Jul 2009 20:12:04 -0400 Subject: msm: rpc: fix warnings when disabling MSM_ONCRPCROUTER_DEBUG Signed-off-by: Brent DeGraaf --- arch/arm/mach-msm/smd_rpcrouter.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/smd_rpcrouter.c b/arch/arm/mach-msm/smd_rpcrouter.c index a0766e353d28..2636f3b7b6dd 100644 --- a/arch/arm/mach-msm/smd_rpcrouter.c +++ b/arch/arm/mach-msm/smd_rpcrouter.c @@ -819,7 +819,9 @@ static void do_read_data(struct work_struct *work) struct rr_packet *pkt; struct rr_fragment *frag; struct msm_rpc_endpoint *ept; +#if defined(CONFIG_MSM_ONCRPCROUTER_DEBUG) struct rpc_request_hdr *rq; +#endif uint32_t pm, mid; unsigned long flags; @@ -1019,7 +1021,9 @@ static int msm_rpc_write_pkt( int last ) { +#if defined(CONFIG_MSM_ONCRPCROUTER_DEBUG) struct rpc_request_hdr *rq = buffer; +#endif uint32_t pacmark; unsigned long flags; int needed; -- cgit v1.2.3 From 52299603cd806c37613da1278411e7bf8924a954 Mon Sep 17 00:00:00 2001 From: Bryan Huntsman Date: Mon, 27 Jul 2009 18:30:44 -0700 Subject: arm: msm: fix BSD license statement in headers Signed-off-by: Bryan Huntsman --- arch/arm/mach-msm/clock-pcom.h | 49 +++++--------------- arch/arm/mach-msm/dal_remotetest.h | 49 +++++--------------- arch/arm/mach-msm/gpio.h | 49 +++++--------------- arch/arm/mach-msm/gpio_hw-8xxx.h | 49 +++++--------------- arch/arm/mach-msm/idle.h | 49 +++++--------------- arch/arm/mach-msm/include/mach/camera.h | 49 +++++--------------- arch/arm/mach-msm/include/mach/clk.h | 49 +++++--------------- arch/arm/mach-msm/include/mach/dal.h | 49 +++++--------------- arch/arm/mach-msm/include/mach/dma_test.h | 49 +++++--------------- arch/arm/mach-msm/include/mach/irqs-7x30.h | 49 +++++--------------- arch/arm/mach-msm/include/mach/irqs-8xxx.h | 49 +++++--------------- arch/arm/mach-msm/include/mach/mpp.h | 49 +++++--------------- arch/arm/mach-msm/include/mach/msm_i2ckbd.h | 49 +++++--------------- arch/arm/mach-msm/include/mach/msm_touchpad.h | 49 +++++--------------- arch/arm/mach-msm/include/mach/oem_rapi_client.h | 50 +++++---------------- arch/arm/mach-msm/include/mach/pmic.h | 49 +++++--------------- arch/arm/mach-msm/include/mach/remote_spinlock.h | 49 +++++--------------- arch/arm/mach-msm/include/mach/sirc.h | 49 +++++--------------- arch/arm/mach-msm/include/mach/smem_log.h | 49 +++++--------------- arch/arm/mach-msm/irq.h | 49 +++++--------------- arch/arm/mach-msm/jtag-v7.S | 57 ++++++------------------ arch/arm/mach-msm/modem_notifier.h | 49 +++++--------------- arch/arm/mach-msm/socinfo.h | 49 +++++--------------- arch/arm/mach-msm/timer.h | 49 +++++--------------- 24 files changed, 245 insertions(+), 940 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/clock-pcom.h b/arch/arm/mach-msm/clock-pcom.h index 4799deb1e634..2e578d3fee34 100644 --- a/arch/arm/mach-msm/clock-pcom.h +++ b/arch/arm/mach-msm/clock-pcom.h @@ -7,51 +7,22 @@ * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * * Neither the name of Code Aurora Forum nor + * * Neither the name of Code Aurora nor * the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written * permission. * - * Alternatively, provided that this notice is retained in full, this software - * may be relicensed by the recipient under the terms of the GNU General Public - * License version 2 ("GPL") and only version 2, in which case the provisions of - * the GPL apply INSTEAD OF those given above. If the recipient relicenses the - * software under the GPL, then the identification text in the MODULE_LICENSE - * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a - * recipient changes the license terms to the GPL, subsequent recipients shall - * not relicense under alternate licensing terms, including the BSD or dual - * BSD/GPL terms. In addition, the following license statement immediately - * below and between the words START and END shall also then apply when this - * software is relicensed under the GPL: - * - * START - * - * 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. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * END - * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ diff --git a/arch/arm/mach-msm/dal_remotetest.h b/arch/arm/mach-msm/dal_remotetest.h index 88c058e8f7c3..e24b480192ed 100644 --- a/arch/arm/mach-msm/dal_remotetest.h +++ b/arch/arm/mach-msm/dal_remotetest.h @@ -7,51 +7,22 @@ * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * * Neither the name of Code Aurora Forum nor + * * Neither the name of Code Aurora nor * the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written * permission. * - * Alternatively, provided that this notice is retained in full, this software - * may be relicensed by the recipient under the terms of the GNU General Public - * License version 2 ("GPL") and only version 2, in which case the provisions of - * the GPL apply INSTEAD OF those given above. If the recipient relicenses the - * software under the GPL, then the identification text in the MODULE_LICENSE - * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a - * recipient changes the license terms to the GPL, subsequent recipients shall - * not relicense under alternate licensing terms, including the BSD or dual - * BSD/GPL terms. In addition, the following license statement immediately - * below and between the words START and END shall also then apply when this - * software is relicensed under the GPL: - * - * START - * - * 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. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * END - * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ /* diff --git a/arch/arm/mach-msm/gpio.h b/arch/arm/mach-msm/gpio.h index 7c5e266dd939..b411bc1e3c8f 100644 --- a/arch/arm/mach-msm/gpio.h +++ b/arch/arm/mach-msm/gpio.h @@ -7,51 +7,22 @@ * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * * Neither the name of Code Aurora Forum nor + * * Neither the name of Code Aurora nor * the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written * permission. * - * Alternatively, provided that this notice is retained in full, this software - * may be relicensed by the recipient under the terms of the GNU General Public - * License version 2 ("GPL") and only version 2, in which case the provisions of - * the GPL apply INSTEAD OF those given above. If the recipient relicenses the - * software under the GPL, then the identification text in the MODULE_LICENSE - * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a - * recipient changes the license terms to the GPL, subsequent recipients shall - * not relicense under alternate licensing terms, including the BSD or dual - * BSD/GPL terms. In addition, the following license statement immediately - * below and between the words START and END shall also then apply when this - * software is relicensed under the GPL: - * - * START - * - * 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. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * END - * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ diff --git a/arch/arm/mach-msm/gpio_hw-8xxx.h b/arch/arm/mach-msm/gpio_hw-8xxx.h index d8e01e0efcfb..9275220bad09 100644 --- a/arch/arm/mach-msm/gpio_hw-8xxx.h +++ b/arch/arm/mach-msm/gpio_hw-8xxx.h @@ -7,51 +7,22 @@ * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * * Neither the name of Code Aurora Forum nor + * * Neither the name of Code Aurora nor * the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written * permission. * - * Alternatively, provided that this notice is retained in full, this software - * may be relicensed by the recipient under the terms of the GNU General Public - * License version 2 ("GPL") and only version 2, in which case the provisions of - * the GPL apply INSTEAD OF those given above. If the recipient relicenses the - * software under the GPL, then the identification text in the MODULE_LICENSE - * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a - * recipient changes the license terms to the GPL, subsequent recipients shall - * not relicense under alternate licensing terms, including the BSD or dual - * BSD/GPL terms. In addition, the following license statement immediately - * below and between the words START and END shall also then apply when this - * software is relicensed under the GPL: - * - * START - * - * 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. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * END - * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ diff --git a/arch/arm/mach-msm/idle.h b/arch/arm/mach-msm/idle.h index 46c76aea71cc..2e0371ed5b59 100644 --- a/arch/arm/mach-msm/idle.h +++ b/arch/arm/mach-msm/idle.h @@ -7,51 +7,22 @@ * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * * Neither the name of Code Aurora Forum nor + * * Neither the name of Code Aurora nor * the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written * permission. * - * Alternatively, provided that this notice is retained in full, this software - * may be relicensed by the recipient under the terms of the GNU General Public - * License version 2 ("GPL") and only version 2, in which case the provisions of - * the GPL apply INSTEAD OF those given above. If the recipient relicenses the - * software under the GPL, then the identification text in the MODULE_LICENSE - * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a - * recipient changes the license terms to the GPL, subsequent recipients shall - * not relicense under alternate licensing terms, including the BSD or dual - * BSD/GPL terms. In addition, the following license statement immediately - * below and between the words START and END shall also then apply when this - * software is relicensed under the GPL: - * - * START - * - * 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. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * END - * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ diff --git a/arch/arm/mach-msm/include/mach/camera.h b/arch/arm/mach-msm/include/mach/camera.h index 9facbecc0678..220fca53c7e5 100644 --- a/arch/arm/mach-msm/include/mach/camera.h +++ b/arch/arm/mach-msm/include/mach/camera.h @@ -7,51 +7,22 @@ * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * * Neither the name of Code Aurora Forum nor + * * Neither the name of Code Aurora nor * the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written * permission. * - * Alternatively, provided that this notice is retained in full, this software - * may be relicensed by the recipient under the terms of the GNU General Public - * License version 2 ("GPL") and only version 2, in which case the provisions of - * the GPL apply INSTEAD OF those given above. If the recipient relicenses the - * software under the GPL, then the identification text in the MODULE_LICENSE - * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a - * recipient changes the license terms to the GPL, subsequent recipients shall - * not relicense under alternate licensing terms, including the BSD or dual - * BSD/GPL terms. In addition, the following license statement immediately - * below and between the words START and END shall also then apply when this - * software is relicensed under the GPL: - * - * START - * - * 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. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * END - * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ diff --git a/arch/arm/mach-msm/include/mach/clk.h b/arch/arm/mach-msm/include/mach/clk.h index 6a1aded34ec6..32e014ae764b 100644 --- a/arch/arm/mach-msm/include/mach/clk.h +++ b/arch/arm/mach-msm/include/mach/clk.h @@ -7,51 +7,22 @@ * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * * Neither the name of Code Aurora Forum nor + * * Neither the name of Code Aurora nor * the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written * permission. * - * Alternatively, provided that this notice is retained in full, this software - * may be relicensed by the recipient under the terms of the GNU General Public - * License version 2 ("GPL") and only version 2, in which case the provisions of - * the GPL apply INSTEAD OF those given above. If the recipient relicenses the - * software under the GPL, then the identification text in the MODULE_LICENSE - * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a - * recipient changes the license terms to the GPL, subsequent recipients shall - * not relicense under alternate licensing terms, including the BSD or dual - * BSD/GPL terms. In addition, the following license statement immediately - * below and between the words START and END shall also then apply when this - * software is relicensed under the GPL: - * - * START - * - * 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. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * END - * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef __MACH_CLK_H diff --git a/arch/arm/mach-msm/include/mach/dal.h b/arch/arm/mach-msm/include/mach/dal.h index 1f0353583e7a..a864f1469063 100644 --- a/arch/arm/mach-msm/include/mach/dal.h +++ b/arch/arm/mach-msm/include/mach/dal.h @@ -7,51 +7,22 @@ * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * * Neither the name of Code Aurora Forum nor + * * Neither the name of Code Aurora nor * the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written * permission. * - * Alternatively, provided that this notice is retained in full, this software - * may be relicensed by the recipient under the terms of the GNU General Public - * License version 2 ("GPL") and only version 2, in which case the provisions of - * the GPL apply INSTEAD OF those given above. If the recipient relicenses the - * software under the GPL, then the identification text in the MODULE_LICENSE - * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a - * recipient changes the license terms to the GPL, subsequent recipients shall - * not relicense under alternate licensing terms, including the BSD or dual - * BSD/GPL terms. In addition, the following license statement immediately - * below and between the words START and END shall also then apply when this - * software is relicensed under the GPL: - * - * START - * - * 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. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * END - * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ diff --git a/arch/arm/mach-msm/include/mach/dma_test.h b/arch/arm/mach-msm/include/mach/dma_test.h index f2ccaa3a0031..7f7dfe38a350 100644 --- a/arch/arm/mach-msm/include/mach/dma_test.h +++ b/arch/arm/mach-msm/include/mach/dma_test.h @@ -7,51 +7,22 @@ * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * * Neither the name of Code Aurora Forum nor + * * Neither the name of Code Aurora nor * the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written * permission. * - * Alternatively, provided that this notice is retained in full, this software - * may be relicensed by the recipient under the terms of the GNU General Public - * License version 2 ("GPL") and only version 2, in which case the provisions of - * the GPL apply INSTEAD OF those given above. If the recipient relicenses the - * software under the GPL, then the identification text in the MODULE_LICENSE - * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a - * recipient changes the license terms to the GPL, subsequent recipients shall - * not relicense under alternate licensing terms, including the BSD or dual - * BSD/GPL terms. In addition, the following license statement immediately - * below and between the words START and END shall also then apply when this - * software is relicensed under the GPL: - * - * START - * - * 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. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * END - * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ diff --git a/arch/arm/mach-msm/include/mach/irqs-7x30.h b/arch/arm/mach-msm/include/mach/irqs-7x30.h index 5d3a7ac08f46..cd9b58572be3 100644 --- a/arch/arm/mach-msm/include/mach/irqs-7x30.h +++ b/arch/arm/mach-msm/include/mach/irqs-7x30.h @@ -7,51 +7,22 @@ * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * * Neither the name of Code Aurora Forum nor + * * Neither the name of Code Aurora nor * the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written * permission. * - * Alternatively, provided that this notice is retained in full, this software - * may be relicensed by the recipient under the terms of the GNU General Public - * License version 2 ("GPL") and only version 2, in which case the provisions of - * the GPL apply INSTEAD OF those given above. If the recipient relicenses the - * software under the GPL, then the identification text in the MODULE_LICENSE - * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a - * recipient changes the license terms to the GPL, subsequent recipients shall - * not relicense under alternate licensing terms, including the BSD or dual - * BSD/GPL terms. In addition, the following license statement immediately - * below and between the words START and END shall also then apply when this - * software is relicensed under the GPL: - * - * START - * - * 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. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * END - * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ diff --git a/arch/arm/mach-msm/include/mach/irqs-8xxx.h b/arch/arm/mach-msm/include/mach/irqs-8xxx.h index 53a732abf4d1..3ce01e9d01fa 100644 --- a/arch/arm/mach-msm/include/mach/irqs-8xxx.h +++ b/arch/arm/mach-msm/include/mach/irqs-8xxx.h @@ -7,51 +7,22 @@ * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * * Neither the name of Code Aurora Forum nor + * * Neither the name of Code Aurora nor * the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written * permission. * - * Alternatively, provided that this notice is retained in full, this software - * may be relicensed by the recipient under the terms of the GNU General Public - * License version 2 ("GPL") and only version 2, in which case the provisions of - * the GPL apply INSTEAD OF those given above. If the recipient relicenses the - * software under the GPL, then the identification text in the MODULE_LICENSE - * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a - * recipient changes the license terms to the GPL, subsequent recipients shall - * not relicense under alternate licensing terms, including the BSD or dual - * BSD/GPL terms. In addition, the following license statement immediately - * below and between the words START and END shall also then apply when this - * software is relicensed under the GPL: - * - * START - * - * 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. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * END - * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ diff --git a/arch/arm/mach-msm/include/mach/mpp.h b/arch/arm/mach-msm/include/mach/mpp.h index aa52baf26edb..b2f5c671babd 100644 --- a/arch/arm/mach-msm/include/mach/mpp.h +++ b/arch/arm/mach-msm/include/mach/mpp.h @@ -7,51 +7,22 @@ * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * * Neither the name of Code Aurora Forum nor + * * Neither the name of Code Aurora nor * the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written * permission. * - * Alternatively, provided that this notice is retained in full, this software - * may be relicensed by the recipient under the terms of the GNU General Public - * License version 2 ("GPL") and only version 2, in which case the provisions of - * the GPL apply INSTEAD OF those given above. If the recipient relicenses the - * software under the GPL, then the identification text in the MODULE_LICENSE - * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a - * recipient changes the license terms to the GPL, subsequent recipients shall - * not relicense under alternate licensing terms, including the BSD or dual - * BSD/GPL terms. In addition, the following license statement immediately - * below and between the words START and END shall also then apply when this - * software is relicensed under the GPL: - * - * START - * - * 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. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * END - * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ diff --git a/arch/arm/mach-msm/include/mach/msm_i2ckbd.h b/arch/arm/mach-msm/include/mach/msm_i2ckbd.h index 2b78ba842ffc..2ca51f261cac 100644 --- a/arch/arm/mach-msm/include/mach/msm_i2ckbd.h +++ b/arch/arm/mach-msm/include/mach/msm_i2ckbd.h @@ -7,51 +7,22 @@ * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * * Neither the name of Code Aurora Forum nor + * * Neither the name of Code Aurora nor * the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written * permission. * - * Alternatively, provided that this notice is retained in full, this software - * may be relicensed by the recipient under the terms of the GNU General Public - * License version 2 ("GPL") and only version 2, in which case the provisions of - * the GPL apply INSTEAD OF those given above. If the recipient relicenses the - * software under the GPL, then the identification text in the MODULE_LICENSE - * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a - * recipient changes the license terms to the GPL, subsequent recipients shall - * not relicense under alternate licensing terms, including the BSD or dual - * BSD/GPL terms. In addition, the following license statement immediately - * below and between the words START and END shall also then apply when this - * software is relicensed under the GPL: - * - * START - * - * 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. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * END - * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ diff --git a/arch/arm/mach-msm/include/mach/msm_touchpad.h b/arch/arm/mach-msm/include/mach/msm_touchpad.h index 7e62f0095a79..5c02f15c5ca5 100644 --- a/arch/arm/mach-msm/include/mach/msm_touchpad.h +++ b/arch/arm/mach-msm/include/mach/msm_touchpad.h @@ -7,51 +7,22 @@ * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * * Neither the name of Code Aurora Forum nor + * * Neither the name of Code Aurora nor * the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written * permission. * - * Alternatively, provided that this notice is retained in full, this software - * may be relicensed by the recipient under the terms of the GNU General Public - * License version 2 ("GPL") and only version 2, in which case the provisions of - * the GPL apply INSTEAD OF those given above. If the recipient relicenses the - * software under the GPL, then the identification text in the MODULE_LICENSE - * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a - * recipient changes the license terms to the GPL, subsequent recipients shall - * not relicense under alternate licensing terms, including the BSD or dual - * BSD/GPL terms. In addition, the following license statement immediately - * below and between the words START and END shall also then apply when this - * software is relicensed under the GPL: - * - * START - * - * 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. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * END - * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ /* diff --git a/arch/arm/mach-msm/include/mach/oem_rapi_client.h b/arch/arm/mach-msm/include/mach/oem_rapi_client.h index 3d48d884110e..8d7344e33de8 100644 --- a/arch/arm/mach-msm/include/mach/oem_rapi_client.h +++ b/arch/arm/mach-msm/include/mach/oem_rapi_client.h @@ -7,51 +7,23 @@ * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * * Neither the name of Code Aurora Forum nor + * * Neither the name of Code Aurora nor * the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written * permission. * - * Alternatively, provided that this notice is retained in full, this software - * may be relicensed by the recipient under the terms of the GNU General Public - * License version 2 ("GPL") and only version 2, in which case the provisions of - * the GPL apply INSTEAD OF those given above. If the recipient relicenses the - * software under the GPL, then the identification text in the MODULE_LICENSE - * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a - * recipient changes the license terms to the GPL, subsequent recipients shall - * not relicense under alternate licensing terms, including the BSD or dual - * BSD/GPL terms. In addition, the following license statement immediately - * below and between the words START and END shall also then apply when this - * software is relicensed under the GPL: - * - * START - * - * 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. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - - * END - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * */ #ifndef __ASM__ARCH_OEM_RAPI_CLIENT_H diff --git a/arch/arm/mach-msm/include/mach/pmic.h b/arch/arm/mach-msm/include/mach/pmic.h index 4722f108d46d..7b7b9bc35917 100644 --- a/arch/arm/mach-msm/include/mach/pmic.h +++ b/arch/arm/mach-msm/include/mach/pmic.h @@ -7,51 +7,22 @@ * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * * Neither the name of Code Aurora Forum nor + * * Neither the name of Code Aurora nor * the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written * permission. * - * Alternatively, provided that this notice is retained in full, this software - * may be relicensed by the recipient under the terms of the GNU General Public - * License version 2 ("GPL") and only version 2, in which case the provisions of - * the GPL apply INSTEAD OF those given above. If the recipient relicenses the - * software under the GPL, then the identification text in the MODULE_LICENSE - * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a - * recipient changes the license terms to the GPL, subsequent recipients shall - * not relicense under alternate licensing terms, including the BSD or dual - * BSD/GPL terms. In addition, the following license statement immediately - * below and between the words START and END shall also then apply when this - * software is relicensed under the GPL: - * - * START - * - * 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. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * END - * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ diff --git a/arch/arm/mach-msm/include/mach/remote_spinlock.h b/arch/arm/mach-msm/include/mach/remote_spinlock.h index 402888eaa56b..17be4eeb5450 100644 --- a/arch/arm/mach-msm/include/mach/remote_spinlock.h +++ b/arch/arm/mach-msm/include/mach/remote_spinlock.h @@ -7,51 +7,22 @@ * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * * Neither the name of Code Aurora Forum nor + * * Neither the name of Code Aurora nor * the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written * permission. * - * Alternatively, provided that this notice is retained in full, this software - * may be relicensed by the recipient under the terms of the GNU General Public - * License version 2 ("GPL") and only version 2, in which case the provisions of - * the GPL apply INSTEAD OF those given above. If the recipient relicenses the - * software under the GPL, then the identification text in the MODULE_LICENSE - * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a - * recipient changes the license terms to the GPL, subsequent recipients shall - * not relicense under alternate licensing terms, including the BSD or dual - * BSD/GPL terms. In addition, the following license statement immediately - * below and between the words START and END shall also then apply when this - * software is relicensed under the GPL: - * - * START - * - * 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. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * END - * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ diff --git a/arch/arm/mach-msm/include/mach/sirc.h b/arch/arm/mach-msm/include/mach/sirc.h index 19efd24cd367..133f37ef1546 100644 --- a/arch/arm/mach-msm/include/mach/sirc.h +++ b/arch/arm/mach-msm/include/mach/sirc.h @@ -7,51 +7,22 @@ * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * * Neither the name of Code Aurora Forum nor + * * Neither the name of Code Aurora nor * the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written * permission. * - * Alternatively, provided that this notice is retained in full, this software - * may be relicensed by the recipient under the terms of the GNU General Public - * License version 2 ("GPL") and only version 2, in which case the provisions of - * the GPL apply INSTEAD OF those given above. If the recipient relicenses the - * software under the GPL, then the identification text in the MODULE_LICENSE - * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a - * recipient changes the license terms to the GPL, subsequent recipients shall - * not relicense under alternate licensing terms, including the BSD or dual - * BSD/GPL terms. In addition, the following license statement immediately - * below and between the words START and END shall also then apply when this - * software is relicensed under the GPL: - * - * START - * - * 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. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * END - * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ diff --git a/arch/arm/mach-msm/include/mach/smem_log.h b/arch/arm/mach-msm/include/mach/smem_log.h index 0980670c4cb2..65a42a27f76f 100644 --- a/arch/arm/mach-msm/include/mach/smem_log.h +++ b/arch/arm/mach-msm/include/mach/smem_log.h @@ -7,51 +7,22 @@ * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * * Neither the name of Code Aurora Forum nor + * * Neither the name of Code Aurora nor * the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written * permission. * - * Alternatively, provided that this notice is retained in full, this software - * may be relicensed by the recipient under the terms of the GNU General Public - * License version 2 ("GPL") and only version 2, in which case the provisions of - * the GPL apply INSTEAD OF those given above. If the recipient relicenses the - * software under the GPL, then the identification text in the MODULE_LICENSE - * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a - * recipient changes the license terms to the GPL, subsequent recipients shall - * not relicense under alternate licensing terms, including the BSD or dual - * BSD/GPL terms. In addition, the following license statement immediately - * below and between the words START and END shall also then apply when this - * software is relicensed under the GPL: - * - * START - * - * 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. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * END - * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ diff --git a/arch/arm/mach-msm/irq.h b/arch/arm/mach-msm/irq.h index 2e1f68bd3d9a..ad4cb92ca570 100644 --- a/arch/arm/mach-msm/irq.h +++ b/arch/arm/mach-msm/irq.h @@ -7,51 +7,22 @@ * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * * Neither the name of Code Aurora Forum nor + * * Neither the name of Code Aurora nor * the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written * permission. * - * Alternatively, provided that this notice is retained in full, this software - * may be relicensed by the recipient under the terms of the GNU General Public - * License version 2 ("GPL") and only version 2, in which case the provisions of - * the GPL apply INSTEAD OF those given above. If the recipient relicenses the - * software under the GPL, then the identification text in the MODULE_LICENSE - * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a - * recipient changes the license terms to the GPL, subsequent recipients shall - * not relicense under alternate licensing terms, including the BSD or dual - * BSD/GPL terms. In addition, the following license statement immediately - * below and between the words START and END shall also then apply when this - * software is relicensed under the GPL: - * - * START - * - * 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. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * END - * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ diff --git a/arch/arm/mach-msm/jtag-v7.S b/arch/arm/mach-msm/jtag-v7.S index cd961109900b..ebac7b254549 100644 --- a/arch/arm/mach-msm/jtag-v7.S +++ b/arch/arm/mach-msm/jtag-v7.S @@ -1,7 +1,4 @@ -/* - * JTAG support functions for ARMv7-based Qualcomm SoCs. - * - * Copyright (c) 2009, Code Aurora Forum. All rights reserved. +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -10,54 +7,28 @@ * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * * Neither the name of Code Aurora Forum nor + * * Neither the name of Code Aurora nor * the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written * permission. * - * Alternatively, provided that this notice is retained in full, this software - * may be relicensed by the recipient under the terms of the GNU General Public - * License version 2 ("GPL") and only version 2, in which case the provisions of - * the GPL apply INSTEAD OF those given above. If the recipient relicenses the - * software under the GPL, then the identification text in the MODULE_LICENSE - * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a - * recipient changes the license terms to the GPL, subsequent recipients shall - * not relicense under alternate licensing terms, including the BSD or dual - * BSD/GPL terms. In addition, the following license statement immediately - * below and between the words START and END shall also then apply when this - * software is relicensed under the GPL: - * - * START - * - * 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. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * END - * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ +/* + * JTAG support functions for ARMv7-based Qualcomm SoCs. + */ #include #include diff --git a/arch/arm/mach-msm/modem_notifier.h b/arch/arm/mach-msm/modem_notifier.h index ceaabc95c560..627f5a142b73 100644 --- a/arch/arm/mach-msm/modem_notifier.h +++ b/arch/arm/mach-msm/modem_notifier.h @@ -7,51 +7,22 @@ * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * * Neither the name of Code Aurora Forum nor + * * Neither the name of Code Aurora nor * the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written * permission. * - * Alternatively, provided that this notice is retained in full, this software - * may be relicensed by the recipient under the terms of the GNU General Public - * License version 2 ("GPL") and only version 2, in which case the provisions of - * the GPL apply INSTEAD OF those given above. If the recipient relicenses the - * software under the GPL, then the identification text in the MODULE_LICENSE - * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a - * recipient changes the license terms to the GPL, subsequent recipients shall - * not relicense under alternate licensing terms, including the BSD or dual - * BSD/GPL terms. In addition, the following license statement immediately - * below and between the words START and END shall also then apply when this - * software is relicensed under the GPL: - * - * START - * - * 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. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * END - * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ /* diff --git a/arch/arm/mach-msm/socinfo.h b/arch/arm/mach-msm/socinfo.h index 60c24e00d776..523b4ac01373 100644 --- a/arch/arm/mach-msm/socinfo.h +++ b/arch/arm/mach-msm/socinfo.h @@ -7,51 +7,22 @@ * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * * Neither the name of Code Aurora Forum nor + * * Neither the name of Code Aurora nor * the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written * permission. * - * Alternatively, provided that this notice is retained in full, this software - * may be relicensed by the recipient under the terms of the GNU General Public - * License version 2 ("GPL") and only version 2, in which case the provisions of - * the GPL apply INSTEAD OF those given above. If the recipient relicenses the - * software under the GPL, then the identification text in the MODULE_LICENSE - * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a - * recipient changes the license terms to the GPL, subsequent recipients shall - * not relicense under alternate licensing terms, including the BSD or dual - * BSD/GPL terms. In addition, the following license statement immediately - * below and between the words START and END shall also then apply when this - * software is relicensed under the GPL: - * - * START - * - * 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. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * END - * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ diff --git a/arch/arm/mach-msm/timer.h b/arch/arm/mach-msm/timer.h index 43b1a17bf56c..196a3ebab874 100644 --- a/arch/arm/mach-msm/timer.h +++ b/arch/arm/mach-msm/timer.h @@ -7,51 +7,22 @@ * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * * Neither the name of Code Aurora Forum nor + * * Neither the name of Code Aurora nor * the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written * permission. * - * Alternatively, provided that this notice is retained in full, this software - * may be relicensed by the recipient under the terms of the GNU General Public - * License version 2 ("GPL") and only version 2, in which case the provisions of - * the GPL apply INSTEAD OF those given above. If the recipient relicenses the - * software under the GPL, then the identification text in the MODULE_LICENSE - * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a - * recipient changes the license terms to the GPL, subsequent recipients shall - * not relicense under alternate licensing terms, including the BSD or dual - * BSD/GPL terms. In addition, the following license statement immediately - * below and between the words START and END shall also then apply when this - * software is relicensed under the GPL: - * - * START - * - * 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. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * END - * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ -- cgit v1.2.3 From 0574187028cdb00022c067b7b519b700c44df96d Mon Sep 17 00:00:00 2001 From: Iliyan Malchev Date: Wed, 1 Apr 2009 17:29:08 -0700 Subject: [ARM] msm: AMSS >= 6350 swaps VFE_CLK and VFE_MDC_CLK Signed-off-by: Iliyan Malchev --- arch/arm/mach-msm/clock-pcom.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/clock-pcom.h b/arch/arm/mach-msm/clock-pcom.h index 2e578d3fee34..9d79a844a590 100644 --- a/arch/arm/mach-msm/clock-pcom.h +++ b/arch/arm/mach-msm/clock-pcom.h @@ -71,8 +71,14 @@ #define P_USB_HS_PCLK 37 /* High speed USB pbus clock */ #define P_USB_OTG_CLK 38 /* Full speed USB clock */ #define P_VDC_CLK 39 /* Video controller clock */ +#if CONFIG_MSM_AMSS_VERSION >= 6350 #define P_VFE_MDC_CLK 40 /* Camera / Video Front End clock */ #define P_VFE_CLK 41 /* VFE MDDI client clock */ +#else/* For radio code base others */ +#define P_VFE_MDC_CLK 41 /* VFE MDDI client clock */ +#define P_VFE_CLK 40 /* Camera / Video Front End clock */ +#endif + #define P_MDP_LCDC_PCLK_CLK 42 #define P_MDP_LCDC_PAD_PCLK_CLK 43 #define P_MDP_VSYNC_CLK 44 -- cgit v1.2.3 From 677cf2528ddb30dc136a429dad123bfc455e38bb Mon Sep 17 00:00:00 2001 From: Willie Ruan Date: Fri, 31 Jul 2009 16:07:54 -0700 Subject: msm: pmic: add HSED APIs Add HSED control APIs for 7x30 target using PMIC8058. Add the use of new RPC version to keep backward compatible. Signed-off-by: Willie Ruan --- arch/arm/mach-msm/include/mach/pmic.h | 100 ++++++++++++++++++++++++++++++++++ arch/arm/mach-msm/pmic.c | 64 +++++++++++++++++++++- 2 files changed, 161 insertions(+), 3 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/include/mach/pmic.h b/arch/arm/mach-msm/include/mach/pmic.h index 7b7b9bc35917..c339e743c032 100644 --- a/arch/arm/mach-msm/include/mach/pmic.h +++ b/arch/arm/mach-msm/include/mach/pmic.h @@ -386,6 +386,83 @@ enum rtc_alarm { PM_RTC_ALARM_1, }; +enum hsed_controller { + PM_HSED_CONTROLLER_0, + PM_HSED_CONTROLLER_1, + PM_HSED_CONTROLLER_2, +}; + +enum hsed_switch { + PM_HSED_SC_SWITCH_TYPE, + PM_HSED_OC_SWITCH_TYPE, +}; + +enum hsed_enable { + PM_HSED_ENABLE_OFF, + PM_HSED_ENABLE_TCXO, + PM_HSED_ENABLE_PWM_TCXO, + PM_HSED_ENABLE_ALWAYS, +}; + +enum hsed_hyst_pre_div { + PM_HSED_HYST_PRE_DIV_1, + PM_HSED_HYST_PRE_DIV_2, + PM_HSED_HYST_PRE_DIV_4, + PM_HSED_HYST_PRE_DIV_8, + PM_HSED_HYST_PRE_DIV_16, + PM_HSED_HYST_PRE_DIV_32, + PM_HSED_HYST_PRE_DIV_64, + PM_HSED_HYST_PRE_DIV_128, +}; + +enum hsed_hyst_time { + PM_HSED_HYST_TIME_1_CLK_CYCLES, + PM_HSED_HYST_TIME_2_CLK_CYCLES, + PM_HSED_HYST_TIME_3_CLK_CYCLES, + PM_HSED_HYST_TIME_4_CLK_CYCLES, + PM_HSED_HYST_TIME_5_CLK_CYCLES, + PM_HSED_HYST_TIME_6_CLK_CYCLES, + PM_HSED_HYST_TIME_7_CLK_CYCLES, + PM_HSED_HYST_TIME_8_CLK_CYCLES, + PM_HSED_HYST_TIME_9_CLK_CYCLES, + PM_HSED_HYST_TIME_10_CLK_CYCLES, + PM_HSED_HYST_TIME_11_CLK_CYCLES, + PM_HSED_HYST_TIME_12_CLK_CYCLES, + PM_HSED_HYST_TIME_13_CLK_CYCLES, + PM_HSED_HYST_TIME_14_CLK_CYCLES, + PM_HSED_HYST_TIME_15_CLK_CYCLES, + PM_HSED_HYST_TIME_16_CLK_CYCLES, +}; + +enum hsed_period_pre_div { + PM_HSED_PERIOD_PRE_DIV_2, + PM_HSED_PERIOD_PRE_DIV_4, + PM_HSED_PERIOD_PRE_DIV_8, + PM_HSED_PERIOD_PRE_DIV_16, + PM_HSED_PERIOD_PRE_DIV_32, + PM_HSED_PERIOD_PRE_DIV_64, + PM_HSED_PERIOD_PRE_DIV_128, + PM_HSED_PERIOD_PRE_DIV_256, +}; + +enum hsed_period_time { + PM_HSED_PERIOD_TIME_1_CLK_CYCLES, + PM_HSED_PERIOD_TIME_2_CLK_CYCLES, + PM_HSED_PERIOD_TIME_3_CLK_CYCLES, + PM_HSED_PERIOD_TIME_4_CLK_CYCLES, + PM_HSED_PERIOD_TIME_5_CLK_CYCLES, + PM_HSED_PERIOD_TIME_6_CLK_CYCLES, + PM_HSED_PERIOD_TIME_7_CLK_CYCLES, + PM_HSED_PERIOD_TIME_8_CLK_CYCLES, + PM_HSED_PERIOD_TIME_9_CLK_CYCLES, + PM_HSED_PERIOD_TIME_10_CLK_CYCLES, + PM_HSED_PERIOD_TIME_11_CLK_CYCLES, + PM_HSED_PERIOD_TIME_12_CLK_CYCLES, + PM_HSED_PERIOD_TIME_13_CLK_CYCLES, + PM_HSED_PERIOD_TIME_14_CLK_CYCLES, + PM_HSED_PERIOD_TIME_15_CLK_CYCLES, + PM_HSED_PERIOD_TIME_16_CLK_CYCLES, +}; int pmic_lp_mode_control(enum switch_cmd cmd, enum vreg_lp_id id); int pmic_vreg_set_level(enum vreg_id vreg, int level); @@ -454,4 +531,27 @@ int pmic_vid_en(uint enable); int pmic_vid_is_en(uint *enabled); int pmic_vid_load_detect_en(uint enable); +int pmic_hsed_set_period( + enum hsed_controller controller, + enum hsed_period_pre_div period_pre_div, + enum hsed_period_time period_time +); + +int pmic_hsed_set_hysteresis( + enum hsed_controller controller, + enum hsed_hyst_pre_div hyst_pre_div, + enum hsed_hyst_time hyst_time +); + +int pmic_hsed_set_current_threshold( + enum hsed_controller controller, + enum hsed_switch switch_hsed, + uint32_t current_threshold +); + +int pmic_hsed_enable( + enum hsed_controller controller, + enum hsed_enable enable +); + #endif diff --git a/arch/arm/mach-msm/pmic.c b/arch/arm/mach-msm/pmic.c index 19800ed7c9cb..a9eeb02b7003 100644 --- a/arch/arm/mach-msm/pmic.c +++ b/arch/arm/mach-msm/pmic.c @@ -137,6 +137,10 @@ #define SPKR_ADD_RIGHT_LEFT_CHAN_PROC 60 #define SPKR_SET_GAIN_PROC 61 #define SPKR_EN_PROC 62 +#define HSED_SET_PERIOD_PROC 63 +#define HSED_SET_HYSTERESIS_PROC 64 +#define HSED_SET_CURRENT_THRESHOLD_PROC 65 +#define HSED_ENABLE_PROC 66 /* rpc related */ @@ -144,7 +148,8 @@ #define PMIC_PDEV_NAME "rs00010001:00000000" #define PMIC_RPC_PROG 0x30000061 -#define PMIC_RPC_VER 0x00010001 +#define PMIC_RPC_VER_1_1 0x00010001 +#define PMIC_RPC_VER_2_1 0x00020001 /* error bit flags defined by modem side */ #define PM_ERR_FLAG__PAR1_OUT_OF_RANGE (0x0001) @@ -324,10 +329,16 @@ static int pmic_rpc_req_reply(struct pmic_buf *tbuf, struct pmic_buf *rbuf, if (pm->endpoint == NULL) { pm->endpoint = msm_rpc_connect(PMIC_RPC_PROG, - PMIC_RPC_VER, 0); + PMIC_RPC_VER_1_1, 0); if (pm->endpoint == NULL) { + pm->endpoint = msm_rpc_connect(PMIC_RPC_PROG, + PMIC_RPC_VER_2_1, 0); + } + + if (pm->endpoint == NULL) return -ENODEV; - } else if (IS_ERR(pm->endpoint)) { + + if (IS_ERR(pm->endpoint)) { ans = PTR_ERR(pm->endpoint); printk(KERN_ERR "%s: init rpc failed! ans = %d\n", __func__, ans); @@ -1039,3 +1050,50 @@ int pmic_spkr_is_stereo_en(uint *enabled) SPKR_IS_STEREO_EN_PROC); } EXPORT_SYMBOL(pmic_spkr_is_stereo_en); + +int pmic_hsed_set_period( + enum hsed_controller controller, + enum hsed_period_pre_div period_pre_div, + enum hsed_period_time period_time +) +{ + return pmic_rpc_set_only(controller, period_pre_div, period_time, 0, + 3, + HSED_SET_PERIOD_PROC); +} +EXPORT_SYMBOL(pmic_hsed_set_period); + +int pmic_hsed_set_hysteresis( + enum hsed_controller controller, + enum hsed_hyst_pre_div hyst_pre_div, + enum hsed_hyst_time hyst_time +) +{ + return pmic_rpc_set_only(controller, hyst_pre_div, hyst_time, 0, + 3, + HSED_SET_HYSTERESIS_PROC); +} +EXPORT_SYMBOL(pmic_hsed_set_hysteresis); + +int pmic_hsed_set_current_threshold( + enum hsed_controller controller, + enum hsed_switch switch_hsed, + uint32_t current_threshold +) +{ + return pmic_rpc_set_only(controller, switch_hsed, current_threshold, 0, + 3, + HSED_SET_CURRENT_THRESHOLD_PROC); +} +EXPORT_SYMBOL(pmic_hsed_set_current_threshold); + +int pmic_hsed_enable( + enum hsed_controller controller, + enum hsed_enable enable_hsed +) +{ + return pmic_rpc_set_only(controller, enable_hsed, 0, 0, + 2, + HSED_ENABLE_PROC); +} +EXPORT_SYMBOL(pmic_hsed_enable); -- cgit v1.2.3 From 9ce3d307d5e3a3a104cd4f85e4888f13781ad610 Mon Sep 17 00:00:00 2001 From: Neil Leeder Date: Wed, 3 Jun 2009 10:30:30 -0400 Subject: msm: move DRAM physical address for 8K QSD processors Several address constants are changed to match the new physical DRAM region which is now based at 0x20000000 CRs-fixed: 189579 Signed-off-by: Neil Leeder --- arch/arm/mach-msm/Makefile.boot | 6 +++--- arch/arm/mach-msm/board-qsd8x50.c | 4 ++-- arch/arm/mach-msm/include/mach/memory.h | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot index 4e76b6cc2cbe..9acaeef05ea9 100644 --- a/arch/arm/mach-msm/Makefile.boot +++ b/arch/arm/mach-msm/Makefile.boot @@ -1,8 +1,8 @@ ifeq ($(CONFIG_ARCH_MSM_SCORPION),y) ifeq ($(CONFIG_MSM_STACKED_MEMORY), y) - zreladdr-y := 0x24008000 -params_phys-y := 0x24000100 -initrd_phys-y := 0x28000000 + zreladdr-y := 0x20008000 +params_phys-y := 0x20000100 +initrd_phys-y := 0x24000000 else # !CONFIG_MSM_STACKED_MEMORY zreladdr-y := 0x00208000 params_phys-y := 0x00200100 diff --git a/arch/arm/mach-msm/board-qsd8x50.c b/arch/arm/mach-msm/board-qsd8x50.c index b74e62a96ca0..51defb5e2808 100644 --- a/arch/arm/mach-msm/board-qsd8x50.c +++ b/arch/arm/mach-msm/board-qsd8x50.c @@ -1455,7 +1455,7 @@ MACHINE_START(QSD8X50_SURF, "QCT QSD8X50 SURF") .phys_io = MSM_DEBUG_UART_PHYS, .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc, #endif - .boot_params = 0x24000100, + .boot_params = 0x20000100, .map_io = qsd8x50_map_io, .init_irq = qsd8x50_init_irq, .init_machine = qsd8x50_init, @@ -1467,7 +1467,7 @@ MACHINE_START(QSD8X50_FFA, "QCT QSD8X50 FFA") .phys_io = MSM_DEBUG_UART_PHYS, .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc, #endif - .boot_params = 0x24000100, + .boot_params = 0x20000100, .map_io = qsd8x50_map_io, .init_irq = qsd8x50_init_irq, .init_machine = qsd8x50_init, diff --git a/arch/arm/mach-msm/include/mach/memory.h b/arch/arm/mach-msm/include/mach/memory.h index fba44ae3b597..dc278487c217 100644 --- a/arch/arm/mach-msm/include/mach/memory.h +++ b/arch/arm/mach-msm/include/mach/memory.h @@ -20,7 +20,7 @@ #ifdef CONFIG_MSM_STACKED_MEMORY #ifdef CONFIG_ARCH_MSM_SCORPION -#define PHYS_OFFSET UL(0x24000000) +#define PHYS_OFFSET UL(0x20000000) #else #define PHYS_OFFSET UL(0x10000000) #endif -- cgit v1.2.3 From 8e7b00f3f097e1275526f90ea7c368bba85ae8de Mon Sep 17 00:00:00 2001 From: "Vishwanathapura, Niranjana" Date: Tue, 4 Aug 2009 15:42:33 -0600 Subject: msm: Include required header files in oem_rapi_client.h Include mising header files in oem_rapi_client.h Signed-off-by: Niranjana Vishwanathapura --- arch/arm/mach-msm/include/mach/oem_rapi_client.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/include/mach/oem_rapi_client.h b/arch/arm/mach-msm/include/mach/oem_rapi_client.h index 8d7344e33de8..4b340eb814c9 100644 --- a/arch/arm/mach-msm/include/mach/oem_rapi_client.h +++ b/arch/arm/mach-msm/include/mach/oem_rapi_client.h @@ -33,7 +33,8 @@ * OEM RAPI CLIENT Driver header file */ -#include +#include +#include enum { OEM_RAPI_CLIENT_EVENT_NONE = 0, -- cgit v1.2.3 From e8eb76c4792b3d7d92065613a39ef2075fe54341 Mon Sep 17 00:00:00 2001 From: Anoop Krishnan Jayasankaran Date: Wed, 5 Aug 2009 10:50:51 -0700 Subject: msm: irq: Fix msm_irq_enter_sleep2 to return correct status. Fixed msm_irq_enter_sleep2 to return error code when there are pending interrupts. CRs-Fixed: 191845 Signed-off-by: Anoop Krishnan Jayasankaran --- arch/arm/mach-msm/irq.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/irq.c b/arch/arm/mach-msm/irq.c index add31d4d7a2b..03687ab2c223 100644 --- a/arch/arm/mach-msm/irq.c +++ b/arch/arm/mach-msm/irq.c @@ -396,12 +396,12 @@ int msm_irq_enter_sleep2(bool modem_wake, int from_idle) pending[0] &= ~(1U << INT_A9_M2A_5); for (i = 0; i < VIC_NUM_REGS; i++) { - if (pending[i]) - if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP_ABORT) { + if (pending[i]) { + if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP_ABORT) DPRINT_ARRAY(pending, "%s abort", __func__); - return -EAGAIN; - } + return -EAGAIN; + } } msm_irq_write_all_regs(VIC_INT_EN0, 0); -- cgit v1.2.3 From a401cdccc13e78fc071e0c83543b02237295bb46 Mon Sep 17 00:00:00 2001 From: Ai Li Date: Wed, 29 Jul 2009 15:02:34 -0600 Subject: msm: pm: reset chip when Modem fails to respond to handshake (n-way) When Modem fails to respond to the power collapse handshake, Modem and Apps are out of sync and Modem is in a bad state. There is no way of recovery other than resetting the chip. This patch also increases the timeout value dramatically to avoid false detection. This patch applies to the n-way protocol implementation. Signed-off-by: Ai Li --- arch/arm/mach-msm/pm2.c | 92 ++++++++++++++++++++++++++++++------------------- 1 file changed, 56 insertions(+), 36 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/pm2.c b/arch/arm/mach-msm/pm2.c index 8ec295426f70..6faa879a1bd4 100644 --- a/arch/arm/mach-msm/pm2.c +++ b/arch/arm/mach-msm/pm2.c @@ -382,6 +382,19 @@ static void msm_pm_config_hw_before_swfi(void) writel(0x1f, APPS_CLK_SLEEP_EN); } +/* + * Reset the entire chip. + * + * NOTE: The function never returns. + */ +static void msm_pm_reset_chip(void) +{ + printk(KERN_EMERG "%s(): resetting chip\n", __func__); + msm_proc_comm(PCOM_RESET_CHIP_IMM, NULL, NULL); + for (;;) + ; +} + /****************************************************************************** * State Polling Definitions @@ -450,7 +463,7 @@ static int msm_pm_poll_state(int nr_grps, struct msm_pm_polled_group *grps) { int i, k; - for (i = 0; i < 100000; i++) + for (i = 0; i < 500000; i++) for (k = 0; k < nr_grps; k++) { bool all_set, all_clear; bool any_set, any_clear; @@ -912,11 +925,9 @@ static int msm_pm_power_collapse ret = msm_pm_poll_state(ARRAY_SIZE(state_grps), state_grps); if (ret < 0) { - MSM_PM_DPRINTK( - MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE, - KERN_INFO, - "%s(): msm_pm_poll_state failed, %d\n", __func__, ret); - goto power_collapse_restore_gpio_bail; + printk(KERN_EMERG "%s(): power collapse entry " + "timed out waiting for Modem's response\n", __func__); + msm_pm_reset_chip(); } if (ret == 1) { @@ -925,8 +936,7 @@ static int msm_pm_power_collapse KERN_INFO, "%s(): msm_pm_poll_state detected Modem reset\n", __func__); - ret = -EAGAIN; - goto power_collapse_restore_gpio_bail; + goto power_collapse_early_exit; } /* DEM Master in RSA */ @@ -1028,16 +1038,20 @@ static int msm_pm_power_collapse msm_pm_config_hw_after_power_up(); MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): post power up"); - do { - memset(state_grps, 0, sizeof(state_grps)); - state_grps[0].group_id = SMSM_POWER_MASTER_DEM; - state_grps[0].bits_any_set = - DEM_MASTER_SMSM_RSA | DEM_MASTER_SMSM_PWRC_EARLY_EXIT; - state_grps[1].group_id = SMSM_MODEM_STATE; - state_grps[1].bits_all_set = SMSM_RESET; + memset(state_grps, 0, sizeof(state_grps)); + state_grps[0].group_id = SMSM_POWER_MASTER_DEM; + state_grps[0].bits_any_set = + DEM_MASTER_SMSM_RSA | DEM_MASTER_SMSM_PWRC_EARLY_EXIT; + state_grps[1].group_id = SMSM_MODEM_STATE; + state_grps[1].bits_all_set = SMSM_RESET; - ret = msm_pm_poll_state(ARRAY_SIZE(state_grps), state_grps); - } while (ret < 0); + ret = msm_pm_poll_state(ARRAY_SIZE(state_grps), state_grps); + + if (ret < 0) { + printk(KERN_EMERG "%s(): power collapse exit " + "timed out waiting for Modem's response\n", __func__); + msm_pm_reset_chip(); + } if (ret == 1) { MSM_PM_DPRINTK( @@ -1045,8 +1059,7 @@ static int msm_pm_power_collapse KERN_INFO, "%s(): msm_pm_poll_state detected Modem reset\n", __func__); - ret = -EAGAIN; - goto power_collapse_restore_gpio_bail; + goto power_collapse_early_exit; } /* Sanity check */ @@ -1066,15 +1079,19 @@ static int msm_pm_power_collapse MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): WFPI"); - do { - memset(state_grps, 0, sizeof(state_grps)); - state_grps[0].group_id = SMSM_POWER_MASTER_DEM; - state_grps[0].bits_all_set = DEM_MASTER_SMSM_RUN; - state_grps[1].group_id = SMSM_MODEM_STATE; - state_grps[1].bits_all_set = SMSM_RESET; + memset(state_grps, 0, sizeof(state_grps)); + state_grps[0].group_id = SMSM_POWER_MASTER_DEM; + state_grps[0].bits_all_set = DEM_MASTER_SMSM_RUN; + state_grps[1].group_id = SMSM_MODEM_STATE; + state_grps[1].bits_all_set = SMSM_RESET; - ret = msm_pm_poll_state(ARRAY_SIZE(state_grps), state_grps); - } while (ret < 0); + ret = msm_pm_poll_state(ARRAY_SIZE(state_grps), state_grps); + + if (ret < 0) { + printk(KERN_EMERG "%s(): power collapse WFPI " + "timed out waiting for Modem's response\n", __func__); + msm_pm_reset_chip(); + } if (ret == 1) { MSM_PM_DPRINTK( @@ -1116,18 +1133,21 @@ power_collapse_early_exit: MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): EARLY_EXIT"); - do { - memset(state_grps, 0, sizeof(state_grps)); - state_grps[0].group_id = SMSM_POWER_MASTER_DEM; - state_grps[0].bits_all_set = DEM_MASTER_SMSM_PWRC_EARLY_EXIT; - state_grps[1].group_id = SMSM_MODEM_STATE; - state_grps[1].bits_all_set = SMSM_RESET; - - ret = msm_pm_poll_state(ARRAY_SIZE(state_grps), state_grps); - } while (ret < 0); + memset(state_grps, 0, sizeof(state_grps)); + state_grps[0].group_id = SMSM_POWER_MASTER_DEM; + state_grps[0].bits_all_set = DEM_MASTER_SMSM_PWRC_EARLY_EXIT; + state_grps[1].group_id = SMSM_MODEM_STATE; + state_grps[1].bits_all_set = SMSM_RESET; + ret = msm_pm_poll_state(ARRAY_SIZE(state_grps), state_grps); MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): EARLY_EXIT EE"); + if (ret < 0) { + printk(KERN_EMERG "%s(): power collapse EARLY_EXIT " + "timed out waiting for Modem's response\n", __func__); + msm_pm_reset_chip(); + } + if (ret == 1) { MSM_PM_DPRINTK( MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE, -- cgit v1.2.3 From 4a2c4bdfe9291c4487966bd46287213d5bb8282e Mon Sep 17 00:00:00 2001 From: "Vishwanathapura, Niranjana" Date: Wed, 5 Aug 2009 16:26:28 -0600 Subject: msm: Add support for NULL RPC callback function Callback Id 0xffffffff (-1) should be used when client specifies a NULL callback function. This is required for other processor not to send callback requests. Signed-off-by: Niranjana Vishwanathapura --- arch/arm/mach-msm/include/mach/msm_rpcrouter.h | 3 +++ arch/arm/mach-msm/oem_rapi_client.c | 2 +- arch/arm/mach-msm/ping_mdm_rpc_client.c | 8 ++++---- arch/arm/mach-msm/smd_rpcrouter_clients.c | 7 +++++-- 4 files changed, 13 insertions(+), 7 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/include/mach/msm_rpcrouter.h b/arch/arm/mach-msm/include/mach/msm_rpcrouter.h index 5b5644eecde2..b50a074af64c 100644 --- a/arch/arm/mach-msm/include/mach/msm_rpcrouter.h +++ b/arch/arm/mach-msm/include/mach/msm_rpcrouter.h @@ -42,6 +42,9 @@ struct rpcrouter_ioctl_server_args { #define RPC_VERSION_MAJOR_MASK 0x0fff0000 #define RPC_VERSION_MINOR_MASK 0x0000ffff +/* callback ID for NULL callback function is -1 */ +#define MSM_RPC_CLIENT_NULL_CB_ID 0xffffffff + struct msm_rpc_endpoint; struct rpcsvr_platform_device diff --git a/arch/arm/mach-msm/oem_rapi_client.c b/arch/arm/mach-msm/oem_rapi_client.c index 77ba7508cb73..7fa513211c21 100644 --- a/arch/arm/mach-msm/oem_rapi_client.c +++ b/arch/arm/mach-msm/oem_rapi_client.c @@ -222,7 +222,7 @@ static int oem_rapi_client_streaming_function_arg(struct msm_rpc_client *client, /* cb_id */ cb_id = msm_rpc_add_cb_func(client, (void *)arg->cb_func); - if (cb_id < 0) + if ((cb_id < 0) && (cb_id != MSM_RPC_CLIENT_NULL_CB_ID)) return cb_id; *((uint32_t *)buf) = cpu_to_be32((uint32_t)cb_id); size += sizeof(uint32_t); diff --git a/arch/arm/mach-msm/ping_mdm_rpc_client.c b/arch/arm/mach-msm/ping_mdm_rpc_client.c index 1401679f03fd..fd7727f547a9 100644 --- a/arch/arm/mach-msm/ping_mdm_rpc_client.c +++ b/arch/arm/mach-msm/ping_mdm_rpc_client.c @@ -266,7 +266,7 @@ static int ping_mdm_data_cb_register_arg(struct msm_rpc_client *client, arg = (struct ping_mdm_register_data_cb_arg *)data; cb_id = msm_rpc_add_cb_func(client, (void *)arg->cb_func); - if (cb_id < 0) + if ((cb_id < 0) && (cb_id != MSM_RPC_CLIENT_NULL_CB_ID)) return cb_id; *((uint32_t *)buf) = cpu_to_be32((uint32_t)cb_id); @@ -300,7 +300,7 @@ static int ping_mdm_data_cb_unregister_arg(struct msm_rpc_client *client, arg = (struct ping_mdm_unregister_data_cb_arg *)data; cb_id = msm_rpc_add_cb_func(client, (void *)arg->cb_func); - if (cb_id < 0) + if ((cb_id < 0) && (cb_id != MSM_RPC_CLIENT_NULL_CB_ID)) return cb_id; *((uint32_t *)buf) = cpu_to_be32((uint32_t)cb_id); @@ -421,7 +421,7 @@ static int ping_mdm_register_arg(struct msm_rpc_client *client, arg = (struct ping_mdm_register_arg *)data; cb_id = msm_rpc_add_cb_func(client, (void *)arg->cb_func); - if (cb_id < 0) + if ((cb_id < 0) && (cb_id != MSM_RPC_CLIENT_NULL_CB_ID)) return cb_id; *((uint32_t *)buf) = cpu_to_be32((uint32_t)cb_id); @@ -443,7 +443,7 @@ static int ping_mdm_unregister_arg(struct msm_rpc_client *client, arg = (struct ping_mdm_unregister_arg *)data; cb_id = msm_rpc_add_cb_func(client, (void *)arg->cb_func); - if (cb_id < 0) + if ((cb_id < 0) && (cb_id != MSM_RPC_CLIENT_NULL_CB_ID)) return cb_id; *((uint32_t *)buf) = cpu_to_be32((uint32_t)cb_id); diff --git a/arch/arm/mach-msm/smd_rpcrouter_clients.c b/arch/arm/mach-msm/smd_rpcrouter_clients.c index 50b867fded54..d7399261aceb 100644 --- a/arch/arm/mach-msm/smd_rpcrouter_clients.c +++ b/arch/arm/mach-msm/smd_rpcrouter_clients.c @@ -65,8 +65,6 @@ #include #include "smd_rpcrouter.h" -#define MSM_RPC_CLIENT_NULL_CB_ID 0xffffffff - struct msm_rpc_client_cb_item { struct list_head list; @@ -510,6 +508,8 @@ EXPORT_SYMBOL(msm_rpc_send_accepted_reply); * * Return Value: * callback ID on success, otherwise returns an error code. + * If cb_func is NULL, the callback Id returned is 0xffffffff. + * This tells the other processor that no callback is reqested. */ int msm_rpc_add_cb_func(struct msm_rpc_client *client, void *cb_func) { @@ -583,6 +583,9 @@ void msm_rpc_remove_cb_func(struct msm_rpc_client *client, void *cb_func) { struct msm_rpc_cb_table_item *cb_item, *tmp_cb_item; + if (cb_func == NULL) + return; + mutex_lock(&client->cb_list_lock); list_for_each_entry_safe(cb_item, tmp_cb_item, &client->cb_list, list) { -- cgit v1.2.3 From 59cffcaa3eee0c6b850f9e0ae60dcbc57f01e8aa Mon Sep 17 00:00:00 2001 From: Neil Leeder Date: Thu, 6 Aug 2009 14:28:37 -0400 Subject: msm: correct gpio register address for 8K Signed-off-by: Neil Leeder --- arch/arm/mach-msm/gpio_hw-8xxx.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/gpio_hw-8xxx.h b/arch/arm/mach-msm/gpio_hw-8xxx.h index 9275220bad09..91b1a43298fd 100644 --- a/arch/arm/mach-msm/gpio_hw-8xxx.h +++ b/arch/arm/mach-msm/gpio_hw-8xxx.h @@ -57,7 +57,7 @@ #define GPIO_IN_4 GPIO1_REG(0x5C) #define GPIO_IN_5 GPIO1_REG(0x60) #define GPIO_IN_6 GPIO1_REG(0x64) -#define GPIO_IN_7 GPIO1_REG(0x6C) +#define GPIO_IN_7 GPIO1_REG(0x68) /* same pin map as above, 1=edge 0=level interrup */ #define GPIO_INT_EDGE_0 GPIO1_REG(0x70) -- cgit v1.2.3 From d9c80874a9bed8e896aaeb633a0e537abbc48b07 Mon Sep 17 00:00:00 2001 From: "Vishwanathapura, Niranjana" Date: Mon, 3 Aug 2009 16:04:48 -0600 Subject: msm: Make logging SMD debug messages a config option Add config item MSM_SMD_DEBUG, enable by default. Also allow runtime switch on/off of debug/info messages. Module parameter msm_smd_debug_mask has following bit definition bit 0 -> enable SMD DEBUG messages when set; default 0; bit 1 -> enable SMSM DEBUG messages when set; default 0; bit 2 -> enable SMD INFO messages when set; default 1; bit 3 -> enable SMSM INFO messages when set; default 1; CRs-Fixed: 188680 Signed-off-by: Niranjana Vishwanathapura --- arch/arm/mach-msm/Kconfig | 8 +++ arch/arm/mach-msm/smd.c | 131 ++++++++++++++++++++++++++-------------------- 2 files changed, 81 insertions(+), 58 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index d4e860f5ba22..9d911a5b19f3 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -381,6 +381,14 @@ choice bool "Package 4" endchoice +config MSM_SMD_DEBUG + depends on MSM_SMD + default y + bool "MSM SMD debug support" + help + Support for debugging the SMD for communication + between the ARM9 and ARM11 + config MSM_N_WAY_SMD depends on (MSM_SMD && (ARCH_MSM_SCORPION || ARCH_MSM7X27)) default y diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c index cf82470cd765..512c9591b4e8 100644 --- a/arch/arm/mach-msm/smd.c +++ b/arch/arm/mach-msm/smd.c @@ -44,7 +44,9 @@ enum { MSM_SMD_DEBUG = 1U << 0, - MSM_SMSM_DEBUG = 1U << 0, + MSM_SMSM_DEBUG = 1U << 1, + MSM_SMD_INFO = 1U << 2, + MSM_SMSM_INFO = 1U << 3, }; enum { @@ -75,10 +77,31 @@ void smd_diag(void); static unsigned last_heap_free = 0xffffffff; -#if 0 -#define D(x...) printk(x) +#if defined(CONFIG_MSM_SMD_DEBUG) +#define SMD_DBG(x...) do { \ + if (msm_smd_debug_mask & MSM_SMD_DEBUG) \ + printk(KERN_DEBUG x); \ + } while (0) + +#define SMSM_DBG(x...) do { \ + if (msm_smd_debug_mask & MSM_SMSM_DEBUG) \ + printk(KERN_DEBUG x); \ + } while (0) + +#define SMD_INFO(x...) do { \ + if (msm_smd_debug_mask & MSM_SMD_INFO) \ + printk(KERN_INFO x); \ + } while (0) + +#define SMSM_INFO(x...) do { \ + if (msm_smd_debug_mask & MSM_SMSM_INFO) \ + printk(KERN_INFO x); \ + } while (0) #else -#define D(x...) do {} while (0) +#define SMD_DBG(x...) do { } while (0) +#define SMSM_DBG(x...) do { } while (0) +#define SMD_INFO(x...) do { } while (0) +#define SMSM_INFO(x...) do { } while (0) #endif #if defined(CONFIG_ARCH_MSM7X30) @@ -133,7 +156,7 @@ void smd_diag(void) x = smem_find(ID_DIAG_ERR_MSG, SZ_DIAG_ERR_MSG); if (x != 0) { x[SZ_DIAG_ERR_MSG - 1] = 0; - printk("smem: DIAG '%s'\n", x); + SMD_INFO("smem: DIAG '%s'\n", x); } x = smem_get_entry(SMEM_ERR_CRASH_LOG, &size); @@ -474,8 +497,8 @@ static void smd_state_change(struct smd_channel *ch, { ch->last_state = next; - printk(KERN_INFO "SMD: ch %d %s -> %s\n", ch->n, - chstate(last), chstate(next)); + SMD_INFO("SMD: ch %d %s -> %s\n", ch->n, + chstate(last), chstate(next)); switch (next) { case SMD_SS_OPENING: @@ -580,42 +603,36 @@ void smd_sleep_exit(void) list_for_each_entry(ch, &smd_ch_list, ch_list) { if (ch_is_open(ch)) { if (ch->recv->fHEAD) { - if (msm_smd_debug_mask & MSM_SMD_DEBUG) - printk(KERN_DEBUG - "smd_sleep_exit ch %d fHEAD " - "%x %x %x\n", - ch->n, - ch->recv->fHEAD, - ch->recv->head, ch->recv->tail); + SMD_INFO("smd_sleep_exit ch %d fHEAD " + "%x %x %x\n", + ch->n, + ch->recv->fHEAD, + ch->recv->head, ch->recv->tail); need_int = 1; break; } if (ch->recv->fTAIL) { - if (msm_smd_debug_mask & MSM_SMD_DEBUG) - printk(KERN_DEBUG - "smd_sleep_exit ch %d fTAIL " - "%x %x %x\n", - ch->n, - ch->recv->fTAIL, - ch->send->head, ch->send->tail); + SMD_INFO("smd_sleep_exit ch %d fTAIL " + "%x %x %x\n", + ch->n, + ch->recv->fTAIL, + ch->send->head, ch->send->tail); need_int = 1; break; } if (ch->recv->fSTATE) { - if (msm_smd_debug_mask & MSM_SMD_DEBUG) - printk("smd_sleep_exit ch %d fSTATE %x" - "\n", ch->n, - ch->recv->fSTATE); + SMD_INFO("smd_sleep_exit ch %d fSTATE %x" + "\n", ch->n, + ch->recv->fSTATE); need_int = 1; break; } tmp = ch->recv->state; if (tmp != ch->last_state) { - if (msm_smd_debug_mask & MSM_SMD_DEBUG) - printk("smd_sleep_exit ch %d " - "state %x != %x\n", - ch->n, tmp, - ch->last_state); + SMD_INFO("smd_sleep_exit ch %d " + "state %x != %x\n", + ch->n, tmp, + ch->last_state); need_int = 1; break; } @@ -624,8 +641,7 @@ void smd_sleep_exit(void) spin_unlock_irqrestore(&smd_lock, flags); do_smd_probe(); if (need_int) { - if (msm_smd_debug_mask & MSM_SMD_DEBUG) - printk("smd_sleep_exit need interrupt\n"); + SMD_INFO("smd_sleep_exit need interrupt\n"); tasklet_schedule(&smd_fake_irq_tasklet); } } @@ -654,7 +670,7 @@ static int smd_stream_write(smd_channel_t *ch, const void *_data, int len) unsigned xfer; int orig_len = len; - D("smd_stream_write() %d -> ch%d\n", len, ch->n); + SMD_DBG("smd_stream_write() %d -> ch%d\n", len, ch->n); if (len < 0) return -EINVAL; @@ -682,7 +698,7 @@ static int smd_packet_write(smd_channel_t *ch, const void *_data, int len) int ret; unsigned hdr[5]; - D("smd_packet_write() %d -> ch%d\n", len, ch->n); + SMD_DBG("smd_packet_write() %d -> ch%d\n", len, ch->n); if (len < 0) return -EINVAL; @@ -695,16 +711,16 @@ static int smd_packet_write(smd_channel_t *ch, const void *_data, int len) ret = smd_stream_write(ch, hdr, sizeof(hdr)); if (ret < 0 || ret != sizeof(hdr)) { - D("%s failed to write pkt header: " - "%d returned\n", __func__, ret); + SMD_DBG("%s failed to write pkt header: " + "%d returned\n", __func__, ret); return -1; } ret = smd_stream_write(ch, _data, len); if (ret < 0 || ret != len) { - D("%s failed to write pkt data: " - "%d returned\n", __func__, ret); + SMD_DBG("%s failed to write pkt data: " + "%d returned\n", __func__, ret); return ret; } @@ -815,8 +831,8 @@ static struct smd_channel *_smd_alloc_channel_v2(uint32_t cid) pr_err("smd_alloc_channel: cid %d fifo do not exist\n", cid); return NULL; } - printk(KERN_INFO "smd_alloc_channel: cid %d fifo found; size = %d\n", - cid, (size / 2)); + SMD_INFO("smd_alloc_channel: cid %d fifo found; size = %d\n", + cid, (size / 2)); ch = kzalloc(sizeof(struct smd_channel), GFP_KERNEL); if (ch) { @@ -870,8 +886,8 @@ static void smd_alloc_channel(struct smd_alloc_elm *alloc_elm) ch->pdev.name = ch->name; ch->pdev.id = ch->type; - pr_info("smd_alloc_channel() '%s' cid=%d\n", - ch->name, ch->n); + SMD_INFO("smd_alloc_channel() '%s' cid=%d\n", + ch->name, ch->n); mutex_lock(&smd_creation_mutex); list_add(&ch->ch_list, &smd_ch_closed_list); @@ -910,11 +926,11 @@ int smd_named_open_on_edge(const char *name, uint32_t edge, unsigned long flags; if (smd_initialized == 0) { - printk(KERN_INFO "smd_open() before smd_init()\n"); + SMD_INFO("smd_open() before smd_init()\n"); return -ENODEV; } - D("smd_open('%s', %p, %p)\n", name, priv, notify); + SMD_DBG("smd_open('%s', %p, %p)\n", name, priv, notify); ch = smd_get_channel(name, edge); if (!ch) @@ -930,11 +946,11 @@ int smd_named_open_on_edge(const char *name, uint32_t edge, *_ch = ch; - D("smd_open: opening '%s'\n", ch->name); + SMD_DBG("smd_open: opening '%s'\n", ch->name); spin_lock_irqsave(&smd_lock, flags); list_add(&ch->ch_list, &smd_ch_list); - D("%s: opening ch %d\n", __func__, ch->n); + SMD_DBG("%s: opening ch %d\n", __func__, ch->n); smd_state_change(ch, ch->last_state, SMD_SS_OPENING); @@ -957,7 +973,7 @@ int smd_close(smd_channel_t *ch) { unsigned long flags; - printk(KERN_INFO "smd_close(%p)\n", ch); + SMD_INFO("smd_close(%p)\n", ch); if (ch == 0) return -1; @@ -1181,15 +1197,14 @@ static irqreturn_t smsm_irq_handler(int irq, void *data) SMSM_NUM_ENTRIES * sizeof(uint32_t)); if (smsm == 0) { - printk(KERN_INFO "\n"); + SMSM_INFO("\n"); } else { unsigned old_apps, apps; unsigned modm = smsm[SMSM_MODEM_STATE]; old_apps = apps = smsm[SMSM_APPS_STATE]; - if (msm_smd_debug_mask & MSM_SMSM_DEBUG) - printk(KERN_INFO "\n", apps, modm); + SMSM_INFO("\n", apps, modm); if (apps & SMSM_RESET) { /* If we get an interrupt and the apps SMSM_RESET bit is already set, the modem is acking the @@ -1218,8 +1233,7 @@ static irqreturn_t smsm_irq_handler(int irq, void *data) } if (smsm[SMSM_APPS_STATE] != apps) { - if (msm_smd_debug_mask & MSM_SMSM_DEBUG) - printk(KERN_INFO "\n", apps); + SMSM_INFO("\n", apps); smsm[SMSM_APPS_STATE] = apps; do_smd_probe(); notify_other_smsm(SMSM_APPS_STATE, old_apps, apps); @@ -1250,9 +1264,7 @@ int smsm_change_state(uint32_t smsm_entry, if (smsm) { old_state = smsm[smsm_entry]; smsm[smsm_entry] = (smsm[smsm_entry] & ~clear_mask) | set_mask; - if (msm_smd_debug_mask & MSM_SMSM_DEBUG) - printk(KERN_INFO "smsm_change_state %x\n", - smsm[smsm_entry]); + SMSM_INFO("smsm_change_state %x\n", smsm[smsm_entry]); notify_other_smsm(SMSM_APPS_STATE, old_state, smsm[smsm_entry]); } @@ -1371,7 +1383,7 @@ void smsm_print_sleep_info(uint32_t sleep_delay, uint32_t sleep_limit, int smd_core_init(void) { int r; - printk(KERN_INFO "smd_core_init()\n"); + SMD_INFO("smd_core_init()\n"); r = request_irq(INT_A9_M2A_0, smd_irq_handler, IRQF_TRIGGER_RISING, "smd_dev", 0); @@ -1419,7 +1431,7 @@ int smd_core_init(void) */ smsm_irq_handler(0, 0); - printk(KERN_INFO "smd_core_init() done\n"); + SMD_INFO("smd_core_init() done\n"); return 0; } @@ -1847,7 +1859,10 @@ static void smsm_debugfs_init(void) {} static int __init msm_smd_probe(struct platform_device *pdev) { - printk(KERN_INFO "smd_init()\n"); + /* enable smd and smsm info messages */ + msm_smd_debug_mask = 0xc; + + SMD_INFO("smd probe\n"); INIT_WORK(&probe_work, smd_channel_probe_worker); -- cgit v1.2.3 From 400562abfa9a13b9c81590c9ef01e09dc9dff836 Mon Sep 17 00:00:00 2001 From: Ai Li Date: Fri, 7 Aug 2009 15:58:05 -0600 Subject: msm: pm: Add config option to choose power management timeout action The action indicates what will happen when the Application Processor times out waiting for Modem's handshake. The choices MSM_PM_TIMEOUT_HALT and MSM_PM_TIMEOUT_RESET_MODEM are useful during development and debugging. MSM_PM_TIMEOUT_RESET_CHIP can be used on production builds. Signed-off-by: Ai Li --- arch/arm/mach-msm/Kconfig | 17 +++++++++++++++++ arch/arm/mach-msm/pm.c | 34 ++++++++++++++++++++++++---------- arch/arm/mach-msm/pm2.c | 19 +++++++++++++------ 3 files changed, 54 insertions(+), 16 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index 9d911a5b19f3..bdc666f8c3be 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -589,4 +589,21 @@ config MSM_SLEEP_TIME_OVERRIDE suspend. The feature is required for automated power management testing. +choice + prompt "Power management timeout action" + default MSM_PM_TIMEOUT_HALT + help + Selects the Application Processor's action when Power Management + times out waiting for Modem's handshake. + + config MSM_PM_TIMEOUT_HALT + bool "Halt the Application Processor" + + config MSM_PM_TIMEOUT_RESET_MODEM + bool "Reset the Modem Processor" + + config MSM_PM_TIMEOUT_RESET_CHIP + bool "Reset the entire chip" +endchoice + endif diff --git a/arch/arm/mach-msm/pm.c b/arch/arm/mach-msm/pm.c index d8a6c78b57cd..47be607e235c 100644 --- a/arch/arm/mach-msm/pm.c +++ b/arch/arm/mach-msm/pm.c @@ -215,6 +215,26 @@ msm_pm_wait_state(uint32_t wait_state_all_set, uint32_t wait_state_all_clear, return -ETIMEDOUT; } +/* + * Respond to timing out waiting for Modem + * + * NOTE: The function never returns. + */ +static void msm_pm_timeout(void) +{ +#if defined(CONFIG_MSM_PM_TIMEOUT_RESET_CHIP) + printk(KERN_EMERG "%s(): resetting chip\n", __func__); + msm_proc_comm(PCOM_RESET_CHIP_IMM, NULL, NULL); +#elif defined(CONFIG_MSM_PM_TIMEOUT_RESET_MODEM) + printk(KERN_EMERG "%s(): resetting modem\n", __func__); + msm_proc_comm_reset_modem_now(); +#elif defined(CONFIG_MSM_PM_TIMEOUT_HALT) + printk(KERN_EMERG "%s(): halting\n", __func__); +#endif + for (;;) + ; +} + static int msm_sleep(int sleep_mode, uint32_t sleep_delay, uint32_t sleep_limit, int from_idle) { @@ -286,11 +306,8 @@ static int msm_sleep(int sleep_mode, uint32_t sleep_delay, ret = msm_pm_wait_state(enter_wait_set, enter_wait_clear, 0, 0); if (ret) { printk(KERN_EMERG "msm_sleep(): power collapse entry " - "timed out waiting for Modem's response " - "-- resetting chip\n"); - msm_proc_comm(PCOM_RESET_CHIP_IMM, NULL, NULL); - for (;;) - ; + "timed out waiting for Modem's response\n"); + msm_pm_timeout(); } } if (msm_irq_enter_sleep2(!!enter_state, from_idle)) @@ -396,11 +413,8 @@ enter_failed: smsm_change_state(SMSM_APPS_STATE, enter_state, exit_state); if (msm_pm_wait_state(exit_wait_set, exit_wait_clear, 0, 0)) { printk(KERN_EMERG "msm_sleep(): power collapse exit " - "timed out waiting for Modem's response " - "-- resetting chip\n"); - msm_proc_comm(PCOM_RESET_CHIP_IMM, NULL, NULL); - for (;;) - ; + "timed out waiting for Modem's response\n"); + msm_pm_timeout(); } if (msm_pm_debug_mask & MSM_PM_DEBUG_STATE) printk(KERN_INFO "msm_sleep(): sleep exit " diff --git a/arch/arm/mach-msm/pm2.c b/arch/arm/mach-msm/pm2.c index 6faa879a1bd4..9db8d17eb75e 100644 --- a/arch/arm/mach-msm/pm2.c +++ b/arch/arm/mach-msm/pm2.c @@ -383,14 +383,21 @@ static void msm_pm_config_hw_before_swfi(void) } /* - * Reset the entire chip. + * Respond to timing out waiting for Modem * * NOTE: The function never returns. */ -static void msm_pm_reset_chip(void) +static void msm_pm_timeout(void) { +#if defined(CONFIG_MSM_PM_TIMEOUT_RESET_CHIP) printk(KERN_EMERG "%s(): resetting chip\n", __func__); msm_proc_comm(PCOM_RESET_CHIP_IMM, NULL, NULL); +#elif defined(CONFIG_MSM_PM_TIMEOUT_RESET_MODEM) + printk(KERN_EMERG "%s(): resetting modem\n", __func__); + msm_proc_comm_reset_modem_now(); +#elif defined(CONFIG_MSM_PM_TIMEOUT_HALT) + printk(KERN_EMERG "%s(): halting\n", __func__); +#endif for (;;) ; } @@ -927,7 +934,7 @@ static int msm_pm_power_collapse if (ret < 0) { printk(KERN_EMERG "%s(): power collapse entry " "timed out waiting for Modem's response\n", __func__); - msm_pm_reset_chip(); + msm_pm_timeout(); } if (ret == 1) { @@ -1050,7 +1057,7 @@ static int msm_pm_power_collapse if (ret < 0) { printk(KERN_EMERG "%s(): power collapse exit " "timed out waiting for Modem's response\n", __func__); - msm_pm_reset_chip(); + msm_pm_timeout(); } if (ret == 1) { @@ -1090,7 +1097,7 @@ static int msm_pm_power_collapse if (ret < 0) { printk(KERN_EMERG "%s(): power collapse WFPI " "timed out waiting for Modem's response\n", __func__); - msm_pm_reset_chip(); + msm_pm_timeout(); } if (ret == 1) { @@ -1145,7 +1152,7 @@ power_collapse_early_exit: if (ret < 0) { printk(KERN_EMERG "%s(): power collapse EARLY_EXIT " "timed out waiting for Modem's response\n", __func__); - msm_pm_reset_chip(); + msm_pm_timeout(); } if (ret == 1) { -- cgit v1.2.3 From a2c3ad155483984e86aa57670dbb15ffd3a0b0fc Mon Sep 17 00:00:00 2001 From: Saravana Kannan Date: Wed, 12 Aug 2009 12:25:53 -0700 Subject: msm: clock: Add support for clk_round_rate(). Clock control over proc-comm doesn't support this API, but other implementations of clock control could support this API. Signed-off-by: Saravana Kannan --- arch/arm/mach-msm/clock-pcom.c | 8 ++++++++ arch/arm/mach-msm/clock.c | 6 ++++++ arch/arm/mach-msm/clock.h | 1 + 3 files changed, 15 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/clock-pcom.c b/arch/arm/mach-msm/clock-pcom.c index b22b3a71db09..a0969072e826 100644 --- a/arch/arm/mach-msm/clock-pcom.c +++ b/arch/arm/mach-msm/clock-pcom.c @@ -93,6 +93,13 @@ unsigned pc_clk_is_enabled(unsigned id) return id; } +long pc_clk_round_rate(unsigned id, unsigned rate) +{ + + /* Not supported. */ + return -EPERM; +} + struct clk_ops clk_ops_pcom = { .enable = pc_clk_enable, .disable = pc_clk_disable, @@ -102,4 +109,5 @@ struct clk_ops clk_ops_pcom = { .set_flags = pc_clk_set_flags, .get_rate = pc_clk_get_rate, .is_enabled = pc_clk_is_enabled, + .round_rate = pc_clk_round_rate, }; diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c index ca2ece0c2d53..1d3e27b538e7 100644 --- a/arch/arm/mach-msm/clock.c +++ b/arch/arm/mach-msm/clock.c @@ -118,6 +118,12 @@ int clk_set_rate(struct clk *clk, unsigned long rate) } EXPORT_SYMBOL(clk_set_rate); +long clk_round_rate(struct clk *clk, unsigned long rate) +{ + return clk->ops->round_rate(clk->id, rate); +} +EXPORT_SYMBOL(clk_round_rate); + int clk_set_min_rate(struct clk *clk, unsigned long rate) { return clk->ops->set_min_rate(clk->id, rate); diff --git a/arch/arm/mach-msm/clock.h b/arch/arm/mach-msm/clock.h index 194d319b62b0..623dbdfd1e74 100644 --- a/arch/arm/mach-msm/clock.h +++ b/arch/arm/mach-msm/clock.h @@ -40,6 +40,7 @@ struct clk_ops { int (*set_flags)(unsigned id, unsigned flags); unsigned (*get_rate)(unsigned id); unsigned (*is_enabled)(unsigned id); + long (*round_rate)(unsigned id, unsigned rate); }; struct clk { -- cgit v1.2.3 From 4c47a3316c8dc5410513e274e5a057cd567e5f4d Mon Sep 17 00:00:00 2001 From: "Vishwanathapura, Niranjana" Date: Wed, 12 Aug 2009 17:39:39 -0600 Subject: msm: Add smd tty device interface for SMD port 'DATA21' Use smd tty driver for SMD port 'DATA21'. Also remove smd port enumeration, as ports are dynamically allocated. Signed-off-by: Niranjana Vishwanathapura --- arch/arm/mach-msm/include/mach/msm_smd.h | 42 -------------- arch/arm/mach-msm/smd_tty.c | 95 ++++++++------------------------ 2 files changed, 24 insertions(+), 113 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/include/mach/msm_smd.h b/arch/arm/mach-msm/include/mach/msm_smd.h index 74ef100af8f5..8ef65c04ea85 100644 --- a/arch/arm/mach-msm/include/mach/msm_smd.h +++ b/arch/arm/mach-msm/include/mach/msm_smd.h @@ -64,48 +64,6 @@ int smd_wait_until_writable(smd_channel_t *ch, int bytes); int smd_tiocmget(smd_channel_t *ch); int smd_tiocmset(smd_channel_t *ch, unsigned int set, unsigned int clear); -typedef enum -{ - SMD_PORT_DS = 0, - SMD_PORT_DIAG, - SMD_PORT_RPC_CALL, - SMD_PORT_RPC_REPLY, - SMD_PORT_BT, - SMD_PORT_CONTROL, - SMD_PORT_MEMCPY_SPARE1, - SMD_PORT_DATA1, - SMD_PORT_DATA2, - SMD_PORT_DATA3, - SMD_PORT_DATA4, - SMD_PORT_DATA5, - SMD_PORT_DATA6, - SMD_PORT_DATA7, - SMD_PORT_DATA8, - SMD_PORT_DATA9, - SMD_PORT_DATA10, - SMD_PORT_DATA11, - SMD_PORT_DATA12, - SMD_PORT_DATA13, - SMD_PORT_DATA14, - SMD_PORT_DATA15, - SMD_PORT_DATA16, - SMD_PORT_DATA17, - SMD_PORT_DATA18, - SMD_PORT_DATA19, - SMD_PORT_DATA20, - SMD_PORT_GPS_NMEA, - SMD_PORT_BRIDGE_1, - SMD_PORT_BRIDGE_2, - SMD_PORT_BRIDGE_3, - SMD_PORT_BRIDGE_4, - SMD_PORT_BRIDGE_5, - SMD_PORT_CS_APPS_MODEM, - SMD_PORT_CS_APPS_DSP, - SMD_PORT_CS_MODEM_DSP, - SMD_PORT_LOOPBACK, - SMD_NUM_PORTS, -} smd_port_id_type; - #if defined(CONFIG_MSM_N_WAY_SMD) enum { SMD_APPS_MODEM = 0, diff --git a/arch/arm/mach-msm/smd_tty.c b/arch/arm/mach-msm/smd_tty.c index 22fca39cd205..ff938c5f7606 100644 --- a/arch/arm/mach-msm/smd_tty.c +++ b/arch/arm/mach-msm/smd_tty.c @@ -29,7 +29,7 @@ #include #include "smd_private.h" -#define MAX_SMD_TTYS 53 +#define MAX_SMD_TTYS 37 static DEFINE_MUTEX(smd_tty_lock); @@ -43,65 +43,6 @@ struct smd_tty_info { static struct smd_tty_info smd_tty[MAX_SMD_TTYS]; static struct workqueue_struct *smd_tty_wq; -char *tty_map_tbl[] = -{ - /* 0 */ "DS", - /* 1 */ "DIAG", - /* 2 */ "RPCCALL", - /* 3 */ "RPCRPY", - /* 4 */ "BT", - /* 5 */ "CONTROL", - /* 6 */ "MCPY_RVD", - /* 7 */ "DATA1", - /* 8 */ "DATA2", - /* 9 */ "DATA3", - /* 10 */ "DATA4", - /* 11 */ "DATA5", - /* 12 */ "DATA6", - /* 13 */ "DATA7", - /* 14 */ "DATA8", - /* 15 */ "DATA9", - /* 16 */ "DATA10", - /* 17 */ "DATA11", - /* 18 */ "DATA12", - /* 19 */ "DATA13", - /* 20 */ "DATA14", - /* 21 */ "DATA15", - /* 22 */ "DATA16", - /* 23 */ "DATA17", - /* 24 */ "DATA18", - /* 25 */ "DATA19", - /* 26 */ "DATA20", - /* 27 */ "GPSNMEA", - /* 28 */ "BRG_1", - /* 29 */ "BRG_2", - /* 30 */ "BRG_3", - /* 31 */ "BRG_4", - /* 32 */ "BRG_5", - /* 33 */ "CS_A2M", - /* 34 */ "CS_A2Q6", - /* 35 */ "CS_M2Q6", - /* 36 */ "LOOPBACK", - - /* new dynamically allocated ctl ports */ - /* 37 */ "DATA0_CNTL", /* name does not exist */ - /* 38 */ "DATA1_CNTL", - /* 39 */ "DATA2_CNTL", - /* 40 */ "DATA3_CNTL", - /* 41 */ "DATA4_CNTL", - /* 42 */ "DATA5_CNTL", /* <- smdcntl0 */ - /* 43 */ "DATA6_CNTL", /* <- smdcntl1 */ - /* 44 */ "DATA7_CNTL", /* <- smdcntl2 */ - /* 45 */ "DATA8_CNTL", - /* 46 */ "DATA9_CNTL", - /* 47 */ "DATA10_CNTL", - /* 48 */ "DATA11_CNTL", - /* 49 */ "DATA12_CNTL", - /* 50 */ "DATA13_CNTL", - /* 51 */ "DATA14_CNTL", - /* 52 */ "DATA15_CNTL", -}; - static void smd_tty_work_func(struct work_struct *work) { unsigned char *ptr; @@ -162,19 +103,31 @@ static int smd_tty_open(struct tty_struct *tty, struct file *f) int res = 0; int n = tty->index; struct smd_tty_info *info; - - if ((n < 0) || (n >= MAX_SMD_TTYS)) + const char *name; + + if (n == 0) + name = "DS"; + else if (n == 7) + name = "DATA1"; + else if (n == 21) + name = "DATA21"; + else if (n == 27) + name = "GPSNMEA"; + else if (n == 36) + name = "LOOPBACK"; + else return -ENODEV; info = smd_tty + n; mutex_lock(&smd_tty_lock); + tty->driver_data = info; if (info->open_count++ == 0) { info->tty = tty; if (!info->ch) { - if (strncmp(tty_map_tbl[n], "LOOPBACK", 9) == 0) { + if (n == 36) { /* set smsm state to SMSM_SMD_LOOPBACK state ** and wait allowing enough time for Modem side ** to open the loopback port (Currently, this is @@ -183,10 +136,10 @@ static int smd_tty_open(struct tty_struct *tty, struct file *f) smsm_change_state(SMSM_APPS_STATE, 0, SMSM_SMD_LOOPBACK); msleep(100); - } else if (strncmp(tty_map_tbl[n], "DS", 3) == 0) { + } else if (n == 0) tty->low_latency = 1; - } - res = smd_open(tty_map_tbl[n], &info->ch, info, + + res = smd_open(name, &info->ch, info, smd_tty_notify); } } @@ -317,14 +270,14 @@ static int __init smd_tty_init(void) tty_register_device(smd_tty_driver, 7, 0); INIT_WORK(&smd_tty[7].tty_work, smd_tty_work_func); - tty_register_device(smd_tty_driver, 17, 0); - INIT_WORK(&smd_tty[27].tty_work, smd_tty_work_func); - tty_register_device(smd_tty_driver, 27, 0); INIT_WORK(&smd_tty[27].tty_work, smd_tty_work_func); - tty_register_device(smd_tty_driver, SMD_PORT_LOOPBACK, 0); - INIT_WORK(&smd_tty[SMD_PORT_LOOPBACK].tty_work, smd_tty_work_func); + tty_register_device(smd_tty_driver, 36, 0); + INIT_WORK(&smd_tty[36].tty_work, smd_tty_work_func); + + tty_register_device(smd_tty_driver, 21, 0); + INIT_WORK(&smd_tty[21].tty_work, smd_tty_work_func); return 0; } -- cgit v1.2.3 From 9bbd79021da965483e25c9f4c160e9aab2e0e81c Mon Sep 17 00:00:00 2001 From: "Vishwanathapura, Niranjana" Date: Wed, 12 Aug 2009 18:23:20 -0600 Subject: msm: Fix bugs in oem_rapi driver Size of each data item transmitted over RPC should be in multiple of 4 bytes. Strings passed are not padded to make their size a multple of 4. Pad the strings with 0s to make its size a multiple of 4. As per the marshalling protocol, the size of variable sized array should only be sent if it is a valid pointer. Correct code to send output_size only if output_valid is true. Buffer pointer is not incremented after reading out_len. Correct buffer increment after reading out_len parameter. Signed-off-by: Niranjana Vishwanathapura --- arch/arm/mach-msm/oem_rapi_client.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/oem_rapi_client.c b/arch/arm/mach-msm/oem_rapi_client.c index 7fa513211c21..e31de45f2920 100644 --- a/arch/arm/mach-msm/oem_rapi_client.c +++ b/arch/arm/mach-msm/oem_rapi_client.c @@ -190,7 +190,13 @@ static int oem_rapi_client_cb(struct msm_rpc_client *client, size += sizeof(uint32_t); memcpy(reply, ret.output, *ret.out_len); + reply += *ret.out_len; size += *ret.out_len; + if (*ret.out_len & 0x3) { + memset(reply, 0, 4 - (*ret.out_len & 0x3)); + reply += 4 - (*ret.out_len & 0x3); + size += 4 - (*ret.out_len & 0x3); + } } else { *(uint32_t *)reply = cpu_to_be32(0); reply += sizeof(uint32_t); @@ -245,6 +251,11 @@ static int oem_rapi_client_streaming_function_arg(struct msm_rpc_client *client, memcpy(buf, arg->input, arg->in_len); size += arg->in_len; buf += arg->in_len; + if (arg->in_len & 0x3) { + memset(buf, 0, 4 - (arg->in_len & 0x3)); + buf += 4 - (arg->in_len & 0x3); + size += 4 - (arg->in_len & 0x3); + } /* out_len */ *((uint32_t *)buf) = cpu_to_be32((uint32_t)(arg->out_len_valid)); @@ -255,9 +266,11 @@ static int oem_rapi_client_streaming_function_arg(struct msm_rpc_client *client, *((uint32_t *)buf) = cpu_to_be32((uint32_t)(arg->output_valid)); size += sizeof(uint32_t); buf += sizeof(uint32_t); - *((uint32_t *)buf) = cpu_to_be32(arg->output_size); - size += sizeof(uint32_t); - buf += sizeof(uint32_t); + if (arg->output_valid) { + *((uint32_t *)buf) = cpu_to_be32(arg->output_size); + size += sizeof(uint32_t); + buf += sizeof(uint32_t); + } return size; } @@ -271,8 +284,10 @@ static int oem_rapi_client_streaming_function_ret(struct msm_rpc_client *client, /* out_len */ data_present = be32_to_cpu(*(uint32_t *)buf); buf += sizeof(uint32_t); - if (data_present && ret->out_len) + if (data_present && ret->out_len) { *ret->out_len = be32_to_cpu(*(uint32_t *)buf); + buf += sizeof(uint32_t); + } /* output */ size = be32_to_cpu(*(uint32_t *)buf); -- cgit v1.2.3 From eb127444bfc76b205f6b0f305567f22574f4fea2 Mon Sep 17 00:00:00 2001 From: "Vishwanathapura, Niranjana" Date: Wed, 12 Aug 2009 18:28:49 -0600 Subject: msm: Add new smem items Add following new smem items. SMEM_SMD_BRIDGE_ALLOC_TABLE ;to be used in SMD bridge layer for SPS SMEM_SMDLITE_TABLE ;to be used for SMDLITE implementation SMEM_SD_IMG_UPGRADE_STATUS ;not used in linux, keeping API in sync Signed-off-by: Niranjana Vishwanathapura --- arch/arm/mach-msm/smd_private.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/smd_private.h b/arch/arm/mach-msm/smd_private.h index 88c96cf67335..ffac0ca964b0 100644 --- a/arch/arm/mach-msm/smd_private.h +++ b/arch/arm/mach-msm/smd_private.h @@ -244,6 +244,9 @@ enum { SMEM_SMEM_LOG_POWER_EVENTS, SMEM_ERR_CRASH_LOG, SMEM_ERR_F3_TRACE_LOG, + SMEM_SMD_BRIDGE_ALLOC_TABLE, + SMEM_SMDLITE_TABLE, + SMEM_SD_IMG_UPGRADE_STATUS, SMEM_NUM_ITEMS, }; -- cgit v1.2.3 From 49b3540c7074e34396017e90dbf5c3c4d0f3de1c Mon Sep 17 00:00:00 2001 From: Saravana Kannan Date: Wed, 12 Aug 2009 22:57:34 -0700 Subject: msm: clock: Add new proc-comm clock ids for 7x30. Signed-off-by: Saravana Kannan --- arch/arm/mach-msm/clock-pcom.h | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/clock-pcom.h b/arch/arm/mach-msm/clock-pcom.h index 9d79a844a590..8d8f5a95b78a 100644 --- a/arch/arm/mach-msm/clock-pcom.h +++ b/arch/arm/mach-msm/clock-pcom.h @@ -90,8 +90,45 @@ #define P_USB_HS3_PCLK 50 /* High speed USB 3 pbus clock */ #define P_GRP_PCLK 51 /* Graphics pbus clock */ #define P_USB_PHY_CLK 52 /* USB PHY clock */ +#define P_USB_HS_CORE_CLK 53 /* High speed USB 1 core clock */ +#define P_USB_HS2_CORE_CLK 54 /* High speed USB 2 core clock */ +#define P_USB_HS3_CORE_CLK 55 /* High speed USB 3 core clock */ +#define P_CAM_MCLK_CLK 56 +#define P_CAMIF_PAD_PCLK 57 +#define P_GRP_2D_CLK 58 +#define P_GRP_2D_PCLK 59 +#define P_I2S_CLK 60 +#define P_JPEG_CLK 61 +#define P_JPEG_PCLK 62 +#define P_LPA_CODEC_CLK 63 +#define P_LPA_CORE_CLK 64 +#define P_LPA_PCLK 65 +#define P_MDC_IO_CLK 66 +#define P_MDC_PCLK 67 +#define P_MFC_CLK 68 +#define P_MFC_DIV2_CLK 69 +#define P_MFC_PCLK 70 +#define P_QUP_I2C_CLK 71 +#define P_ROTATOR_IMEM_CLK 72 +#define P_ROTATOR_PCLK 73 +#define P_VFE_CAMIF_CLK 74 +#define P_VFE_PCLK 75 +#define P_VPE_CLK 76 +#define P_I2C_2_CLK 77 +#define P_MI2S_CODEC_RX_SCLK 78 +#define P_MI2S_CODEC_RX_MCLK 79 +#define P_MI2S_CODEC_TX_SCLK 80 +#define P_MI2S_CODEC_TX_MCLK 81 +#define P_PMDH_PCLK 82 +#define P_EMDH_PCLK 83 +#define P_SPI_PCLK 84 +#define P_TSIF_PCLK 85 +#define P_MDP_PCLK 86 +#define P_SDAC_MCLK 87 +#define P_MI2S_HDMI_CLK 88 +#define P_MI2S_HDMI_MCLK 89 -#define P_NR_CLKS 53 +#define P_NR_CLKS 90 struct clk_ops; extern struct clk_ops clk_ops_pcom; -- cgit v1.2.3 From ad81a3798da18bab42e6b55e5db8a8700b29e986 Mon Sep 17 00:00:00 2001 From: David Brown Date: Tue, 11 Aug 2009 09:36:00 -0700 Subject: msm: dma: Use proper EXPORT_SYMBOL. Use EXPORT_SYMBOL instead of EXPORT_SYMBOL_GPL to match the other instances in the driver. Signed-off-by: David Brown --- arch/arm/mach-msm/dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/dma.c b/arch/arm/mach-msm/dma.c index 5ae76db8fb9b..62b611db9d8d 100644 --- a/arch/arm/mach-msm/dma.c +++ b/arch/arm/mach-msm/dma.c @@ -125,7 +125,7 @@ int msm_dmov_exec_cmd(unsigned id, unsigned int cmdptr) PRINT_FLOW("dmov_exec_cmdptr(%d, %x) done\n", id, cmdptr); return 0; } -EXPORT_SYMBOL_GPL(msm_dmov_exec_cmd); +EXPORT_SYMBOL(msm_dmov_exec_cmd); static irqreturn_t msm_datamover_irq_handler(int irq, void *dev_id) -- cgit v1.2.3 From 040bf632a30aea7ad8792e9f9901c30feb995f29 Mon Sep 17 00:00:00 2001 From: Michael Bohan Date: Fri, 7 Aug 2009 14:01:56 -0700 Subject: msm: gpio: Add support for msm7x30 Note that we are using GPIO shadow region 2 per the modem configuration. Signed-off-by: Michael Bohan --- arch/arm/mach-msm/gpio.c | 25 ++++++- arch/arm/mach-msm/gpio_hw-7x30.h | 112 +++++++++++++++++++++++++++++ arch/arm/mach-msm/gpio_hw.h | 9 ++- arch/arm/mach-msm/include/mach/msm_iomap.h | 4 +- 4 files changed, 145 insertions(+), 5 deletions(-) create mode 100644 arch/arm/mach-msm/gpio_hw-7x30.h (limited to 'arch') diff --git a/arch/arm/mach-msm/gpio.c b/arch/arm/mach-msm/gpio.c index 903379d6f8ed..d9b4fcbebff7 100644 --- a/arch/arm/mach-msm/gpio.c +++ b/arch/arm/mach-msm/gpio.c @@ -104,7 +104,11 @@ struct msm_gpio_chip msm_gpio_chips[] = { }, .chip = { .start = 16, +#if defined(CONFIG_ARCH_MSM7X30) + .end = 43, +#else .end = 42, +#endif .configure = msm_gpio_configure, .get_irq_num = msm_gpio_get_irq_num, .read = msm_gpio_read, @@ -125,7 +129,11 @@ struct msm_gpio_chip msm_gpio_chips[] = { .oe = GPIO_OE_2, }, .chip = { +#if defined(CONFIG_ARCH_MSM7X30) + .start = 44, +#else .start = 43, +#endif .end = 67, .configure = msm_gpio_configure, .get_irq_num = msm_gpio_get_irq_num, @@ -170,7 +178,7 @@ struct msm_gpio_chip msm_gpio_chips[] = { }, .chip = { .start = 95, -#if defined(CONFIG_ARCH_MSM_SCORPION) +#if defined(CONFIG_ARCH_QSD8X50) .end = 103, #else .end = 106, @@ -195,9 +203,12 @@ struct msm_gpio_chip msm_gpio_chips[] = { .oe = GPIO_OE_5, }, .chip = { -#if defined(CONFIG_ARCH_MSM_SCORPION) +#if defined(CONFIG_ARCH_QSD8X50) .start = 104, .end = 121, +#elif defined(CONFIG_ARCH_MSM7X30) + .start = 107, + .end = 133, #else .start = 107, .end = 132, @@ -223,8 +234,13 @@ struct msm_gpio_chip msm_gpio_chips[] = { .oe = GPIO_OE_6, }, .chip = { +#if defined(CONFIG_ARCH_MSM7X30) + .start = 134, + .end = 150, +#else .start = 122, .end = 152, +#endif .configure = msm_gpio_configure, .get_irq_num = msm_gpio_get_irq_num, .read = msm_gpio_read, @@ -245,8 +261,13 @@ struct msm_gpio_chip msm_gpio_chips[] = { .oe = GPIO_OE_7, }, .chip = { +#if defined(CONFIG_ARCH_MSM7X30) + .start = 151, + .end = 181, +#else .start = 153, .end = 164, +#endif .configure = msm_gpio_configure, .get_irq_num = msm_gpio_get_irq_num, .read = msm_gpio_read, diff --git a/arch/arm/mach-msm/gpio_hw-7x30.h b/arch/arm/mach-msm/gpio_hw-7x30.h new file mode 100644 index 000000000000..9142e7e6045c --- /dev/null +++ b/arch/arm/mach-msm/gpio_hw-7x30.h @@ -0,0 +1,112 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef __ARCH_ARM_MACH_MSM_GPIO_HW_7X30_H +#define __ARCH_ARM_MACH_MSM_GPIO_HW_7X30_H + +/* output value */ +#define GPIO_OUT_0 GPIO1_REG(0x00) /* gpio 15-0 */ +#define GPIO_OUT_1 GPIO2_REG(0x00) /* gpio 43-16 */ +#define GPIO_OUT_2 GPIO1_REG(0x04) /* gpio 67-44 */ +#define GPIO_OUT_3 GPIO1_REG(0x08) /* gpio 94-68 */ +#define GPIO_OUT_4 GPIO1_REG(0x0C) /* gpio 106-95 */ +#define GPIO_OUT_5 GPIO1_REG(0x50) /* gpio 133-107 */ +#define GPIO_OUT_6 GPIO1_REG(0xC4) /* gpio 150-134 */ +#define GPIO_OUT_7 GPIO1_REG(0x214) /* gpio 181-151 */ + +/* same pin map as above, output enable */ +#define GPIO_OE_0 GPIO1_REG(0x10) +#define GPIO_OE_1 GPIO2_REG(0x08) +#define GPIO_OE_2 GPIO1_REG(0x14) +#define GPIO_OE_3 GPIO1_REG(0x18) +#define GPIO_OE_4 GPIO1_REG(0x1C) +#define GPIO_OE_5 GPIO1_REG(0x54) +#define GPIO_OE_6 GPIO1_REG(0xC8) +#define GPIO_OE_7 GPIO1_REG(0x218) + +/* same pin map as above, input read */ +#define GPIO_IN_0 GPIO1_REG(0x34) +#define GPIO_IN_1 GPIO2_REG(0x20) +#define GPIO_IN_2 GPIO1_REG(0x38) +#define GPIO_IN_3 GPIO1_REG(0x3C) +#define GPIO_IN_4 GPIO1_REG(0x40) +#define GPIO_IN_5 GPIO1_REG(0x44) +#define GPIO_IN_6 GPIO1_REG(0xCC) +#define GPIO_IN_7 GPIO1_REG(0x21C) + +/* same pin map as above, 1=edge 0=level interrup */ +#define GPIO_INT_EDGE_0 GPIO1_REG(0x60) +#define GPIO_INT_EDGE_1 GPIO2_REG(0x50) +#define GPIO_INT_EDGE_2 GPIO1_REG(0x64) +#define GPIO_INT_EDGE_3 GPIO1_REG(0x68) +#define GPIO_INT_EDGE_4 GPIO1_REG(0x6C) +#define GPIO_INT_EDGE_5 GPIO1_REG(0xC0) +#define GPIO_INT_EDGE_6 GPIO1_REG(0xD0) +#define GPIO_INT_EDGE_7 GPIO1_REG(0x240) + +/* same pin map as above, 1=positive 0=negative */ +#define GPIO_INT_POS_0 GPIO1_REG(0x70) +#define GPIO_INT_POS_1 GPIO2_REG(0x58) +#define GPIO_INT_POS_2 GPIO1_REG(0x74) +#define GPIO_INT_POS_3 GPIO1_REG(0x78) +#define GPIO_INT_POS_4 GPIO1_REG(0x7C) +#define GPIO_INT_POS_5 GPIO1_REG(0xBC) +#define GPIO_INT_POS_6 GPIO1_REG(0xD4) +#define GPIO_INT_POS_7 GPIO1_REG(0x228) + +/* same pin map as above, interrupt enable */ +#define GPIO_INT_EN_0 GPIO1_REG(0x80) +#define GPIO_INT_EN_1 GPIO2_REG(0x60) +#define GPIO_INT_EN_2 GPIO1_REG(0x84) +#define GPIO_INT_EN_3 GPIO1_REG(0x88) +#define GPIO_INT_EN_4 GPIO1_REG(0x8C) +#define GPIO_INT_EN_5 GPIO1_REG(0xB8) +#define GPIO_INT_EN_6 GPIO1_REG(0xD8) +#define GPIO_INT_EN_7 GPIO1_REG(0x22C) + +/* same pin map as above, write 1 to clear interrupt */ +#define GPIO_INT_CLEAR_0 GPIO1_REG(0x90) +#define GPIO_INT_CLEAR_1 GPIO2_REG(0x68) +#define GPIO_INT_CLEAR_2 GPIO1_REG(0x94) +#define GPIO_INT_CLEAR_3 GPIO1_REG(0x98) +#define GPIO_INT_CLEAR_4 GPIO1_REG(0x9C) +#define GPIO_INT_CLEAR_5 GPIO1_REG(0xB4) +#define GPIO_INT_CLEAR_6 GPIO1_REG(0xDC) +#define GPIO_INT_CLEAR_7 GPIO1_REG(0x230) + +/* same pin map as above, 1=interrupt pending */ +#define GPIO_INT_STATUS_0 GPIO1_REG(0xA0) +#define GPIO_INT_STATUS_1 GPIO2_REG(0x70) +#define GPIO_INT_STATUS_2 GPIO1_REG(0xA4) +#define GPIO_INT_STATUS_3 GPIO1_REG(0xA8) +#define GPIO_INT_STATUS_4 GPIO1_REG(0xAC) +#define GPIO_INT_STATUS_5 GPIO1_REG(0xB0) +#define GPIO_INT_STATUS_6 GPIO1_REG(0xE0) +#define GPIO_INT_STATUS_7 GPIO1_REG(0x234) + +#endif diff --git a/arch/arm/mach-msm/gpio_hw.h b/arch/arm/mach-msm/gpio_hw.h index 72e83efcd7f4..cc6b036c1dbc 100644 --- a/arch/arm/mach-msm/gpio_hw.h +++ b/arch/arm/mach-msm/gpio_hw.h @@ -30,11 +30,18 @@ ** macros. */ +#if defined(CONFIG_ARCH_MSM7X30) +#define GPIO1_REG(off) (MSM_GPIO1_BASE + (off)) +#define GPIO2_REG(off) (MSM_GPIO2_BASE + 0x400 + (off)) +#else #define GPIO1_REG(off) (MSM_GPIO1_BASE + 0x800 + (off)) #define GPIO2_REG(off) (MSM_GPIO2_BASE + 0xC00 + (off)) +#endif -#if defined(CONFIG_ARCH_MSM_SCORPION) +#if defined(CONFIG_ARCH_QSD8X50) #include "gpio_hw-8xxx.h" +#elif defined(CONFIG_ARCH_MSM7X30) +#include "gpio_hw-7x30.h" #else #include "gpio_hw-7xxx.h" #endif diff --git a/arch/arm/mach-msm/include/mach/msm_iomap.h b/arch/arm/mach-msm/include/mach/msm_iomap.h index a8a4051118b3..74ec54e61eb9 100644 --- a/arch/arm/mach-msm/include/mach/msm_iomap.h +++ b/arch/arm/mach-msm/include/mach/msm_iomap.h @@ -78,7 +78,7 @@ #if defined(CONFIG_ARCH_QSD8X50) #define MSM_GPIO1_PHYS 0xA9000000 #elif defined(CONFIG_ARCH_MSM7X30) -#define MSM_GPIO1_PHYS 0xABE00000 +#define MSM_GPIO1_PHYS 0xAC001000 #else #define MSM_GPIO1_PHYS 0xA9200000 #endif @@ -87,7 +87,7 @@ #define MSM_GPIO2_BASE IOMEM(0xE0004000) #if defined(CONFIG_ARCH_MSM7X30) -#define MSM_GPIO2_PHYS 0xABF00000 +#define MSM_GPIO2_PHYS 0xAC101000 #elif defined(CONFIG_ARCH_QSD8X50) #define MSM_GPIO2_PHYS 0xA9100000 #else -- cgit v1.2.3 From 54f3b6c8643073564654f1aeb32f247b9a44f0a1 Mon Sep 17 00:00:00 2001 From: Saravana Kannan Date: Wed, 12 Aug 2009 23:02:38 -0700 Subject: msm: clock: Update supported clocks list for 7x30. Add USB and display related clocks. Signed-off-by: Saravana Kannan --- arch/arm/mach-msm/devices.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/devices.c b/arch/arm/mach-msm/devices.c index edf5f520a102..3f21ed9c8480 100644 --- a/arch/arm/mach-msm/devices.c +++ b/arch/arm/mach-msm/devices.c @@ -548,12 +548,14 @@ struct clk msm_clocks_7x30[] = { CLK_PCOM("imem_clk", IMEM_CLK, NULL, OFF), CLK_PCOM("mdc_clk", MDC_CLK, NULL, 0), CLK_PCOM("mdp_clk", MDP_CLK, NULL, OFF), + CLK_PCOM("mdp_pclk", MDP_PCLK, NULL, 0), CLK_PCOM("mdp_lcdc_pclk_clk", MDP_LCDC_PCLK_CLK, NULL, 0), CLK_PCOM("mdp_lcdc_pad_pclk_clk", MDP_LCDC_PAD_PCLK_CLK, NULL, 0), CLK_PCOM("mdp_vsync_clk", MDP_VSYNC_CLK, NULL, 0), CLK_PCOM("pbus_clk", PBUS_CLK, NULL, CLK_MIN), CLK_PCOM("pcm_clk", PCM_CLK, NULL, 0), CLK_PCOM("mddi_clk", PMDH_CLK, NULL, OFF | CLK_MINMAX), + CLK_PCOM("mddi_pclk", PMDH_PCLK, NULL, 0), CLK_PCOM("sdac_clk", SDAC_CLK, NULL, OFF), CLK_PCOM("sdc_clk", SDC1_CLK, &msm_device_sdc1.dev, OFF), CLK_PCOM("sdc_pclk", SDC1_PCLK, &msm_device_sdc1.dev, OFF), @@ -568,14 +570,20 @@ struct clk msm_clocks_7x30[] = { CLK_PCOM("uart_clk", UART3_CLK, &msm_device_uart3.dev, OFF), CLK_PCOM("uartdm_clk", UART1DM_CLK, &msm_device_uart_dm1.dev, OFF), CLK_PCOM("uartdm_clk", UART2DM_CLK, &msm_device_uart_dm2.dev, 0), - CLK_PCOM("usb_hs_clk", USB_HS_CLK, NULL, OFF), - CLK_PCOM("usb_hs_pclk", USB_HS_PCLK, NULL, OFF), + CLK_PCOM("usb_hs_clk", USB_HS_CLK, NULL, OFF), + CLK_PCOM("usb_hs_pclk", USB_HS_PCLK, NULL, OFF), + CLK_PCOM("usb_hs_core_clk", USB_HS_CORE_CLK, NULL, OFF), + CLK_PCOM("usb_hs2_clk", USB_HS2_CLK, NULL, OFF), + CLK_PCOM("usb_hs2_pclk", USB_HS2_PCLK, NULL, OFF), + CLK_PCOM("usb_hs2_core_clk", USB_HS2_CORE_CLK, NULL, OFF), + CLK_PCOM("usb_hs3_clk", USB_HS3_CLK, NULL, OFF), + CLK_PCOM("usb_hs3_pclk", USB_HS3_PCLK, NULL, OFF), + CLK_PCOM("usb_hs3_core_clk", USB_HS3_CORE_CLK, NULL, OFF), CLK_PCOM("usb_otg_clk", USB_OTG_CLK, NULL, 0), CLK_PCOM("vdc_clk", VDC_CLK, NULL, OFF | CLK_MIN), CLK_PCOM("vfe_clk", VFE_CLK, NULL, OFF), CLK_PCOM("vfe_mdc_clk", VFE_MDC_CLK, NULL, OFF), CLK_PCOM("grp_pclk", GRP_PCLK, NULL, 0), - CLK_PCOM("usb_phy_clk", USB_PHY_CLK, NULL, 0), }; unsigned msm_num_clocks_7x30 = ARRAY_SIZE(msm_clocks_7x30); -- cgit v1.2.3 From a5f16d3bafcd04408941e29ce197962223408422 Mon Sep 17 00:00:00 2001 From: Neil Leeder Date: Fri, 14 Aug 2009 17:27:00 -0400 Subject: msm: correct bluetooth host wake GPIO for comet Signed-off-by: Neil Leeder --- arch/arm/mach-msm/board-comet.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/board-comet.c b/arch/arm/mach-msm/board-comet.c index 370fb6bd9cba..82766fb635f1 100644 --- a/arch/arm/mach-msm/board-comet.c +++ b/arch/arm/mach-msm/board-comet.c @@ -476,8 +476,8 @@ static struct msm_serial_hs_platform_data msm_uart_dm1_pdata = { static struct resource bluesleep_resources[] = { { .name = "gpio_host_wake", - .start = 21, - .end = 21, + .start = 40, + .end = 40, .flags = IORESOURCE_IO, }, { @@ -488,8 +488,8 @@ static struct resource bluesleep_resources[] = { }, { .name = "host_wake", - .start = MSM_GPIO_TO_INT(21), - .end = MSM_GPIO_TO_INT(21), + .start = MSM_GPIO_TO_INT(40), + .end = MSM_GPIO_TO_INT(40), .flags = IORESOURCE_IRQ, }, }; @@ -523,7 +523,7 @@ enum { static unsigned bt_config_power_on[] = { GPIO_CFG(29, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* WAKE */ - GPIO_CFG(21, 0, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), /* HOST_WAKE */ + GPIO_CFG(40, 0, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), /* HOST_WAKE */ GPIO_CFG(22, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* PWR_EN */ GPIO_CFG(43, 2, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* RFR */ GPIO_CFG(44, 2, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), /* CTS */ @@ -536,7 +536,7 @@ static unsigned bt_config_power_on[] = { }; static unsigned bt_config_power_off[] = { GPIO_CFG(29, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* WAKE */ - GPIO_CFG(21, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* HOST_WAKE */ + GPIO_CFG(40, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* HOST_WAKE */ GPIO_CFG(22, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* PWR_EN */ GPIO_CFG(43, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* RFR */ GPIO_CFG(44, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* CTS */ -- cgit v1.2.3 From d4f80372bd9f03aa9c15932b23b38169a795b28a Mon Sep 17 00:00:00 2001 From: Neil Leeder Date: Fri, 14 Aug 2009 14:18:17 -0400 Subject: msm: correct handling of vreg gp6 for comet Voltage regulator gp6 is used for both the MDDI WVGA display and SDCC. Previously SDCC turned it on and off without regard to usage by MDDI. This change shares control between MDDI and SDCC. Signed-off-by: Neil Leeder --- arch/arm/mach-msm/board-comet.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/board-comet.c b/arch/arm/mach-msm/board-comet.c index 82766fb635f1..32e30bced856 100644 --- a/arch/arm/mach-msm/board-comet.c +++ b/arch/arm/mach-msm/board-comet.c @@ -114,6 +114,10 @@ #define COMET_CPLD_PER_ENABLE_WXGA 0x0040 #define COMET_CPLD_EXT_PER_ENABLE_WXGA 0x0080 +static unsigned long vreg_sts, gpio_sts; +static struct vreg *vreg_mmc; +static int gp6_enabled; + static int cpld_version; static bool wvga_present; static bool wxga_present; @@ -398,6 +402,20 @@ static struct mddi_platform_data mddi_pdata = { static void __init msm_fb_add_devices(void) { + int rc; + + if (wvga_present) { + vreg_mmc = vreg_get(NULL, "gp6"); + rc = vreg_set_level(vreg_mmc, 2850); + if (!rc) + rc = vreg_enable(vreg_mmc); + if (rc) + printk(KERN_ERR "%s: gp6 vreg error: %d\n", + __func__, rc); + else + gp6_enabled = 1; + } + msm_fb_register_device("mdp", 0); msm_fb_register_device("pmdh", &mddi_pdata); msm_fb_register_device("emdh", &mddi_pdata); @@ -876,9 +894,6 @@ static unsigned sdcc_cfg_data[][6] = { }, }; -static unsigned long vreg_sts, gpio_sts; -static struct vreg *vreg_mmc; - static void msm_sdcc_setup_gpio(int dev_id, unsigned int enable) { int i, rc; @@ -914,7 +929,7 @@ static uint32_t msm_sdcc_setup_power(struct device *dv, unsigned int vdd) clear_bit(pdev->id, &vreg_sts); - if (!vreg_sts) { + if (!vreg_sts && !gp6_enabled) { rc = vreg_disable(vreg_mmc); if (rc) printk(KERN_ERR "%s: return val: %d \n", @@ -923,7 +938,7 @@ static uint32_t msm_sdcc_setup_power(struct device *dv, unsigned int vdd) return 0; } - if (!vreg_sts) { + if (!vreg_sts && !gp6_enabled) { rc = vreg_set_level(vreg_mmc, 2850); if (!rc) rc = vreg_enable(vreg_mmc); -- cgit v1.2.3 From 121af7ec4d291a79d24f60719e103dd37b6f172a Mon Sep 17 00:00:00 2001 From: Kenneth Heitke Date: Mon, 17 Aug 2009 12:26:58 -0600 Subject: msm: spi: Add SPI clock support for 7x30 Signed-off-by: Kenneth Heitke --- arch/arm/mach-msm/devices.c | 1 + 1 file changed, 1 insertion(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/devices.c b/arch/arm/mach-msm/devices.c index 3f21ed9c8480..5b89f3180479 100644 --- a/arch/arm/mach-msm/devices.c +++ b/arch/arm/mach-msm/devices.c @@ -565,6 +565,7 @@ struct clk msm_clocks_7x30[] = { CLK_PCOM("sdc_pclk", SDC3_PCLK, &msm_device_sdc3.dev, OFF), CLK_PCOM("sdc_clk", SDC4_CLK, &msm_device_sdc4.dev, OFF), CLK_PCOM("sdc_pclk", SDC4_PCLK, &msm_device_sdc4.dev, OFF), + CLK_PCOM("spi_clk", SPI_CLK, NULL, 0), CLK_PCOM("uart_clk", UART1_CLK, &msm_device_uart1.dev, OFF), CLK_PCOM("uart_clk", UART2_CLK, &msm_device_uart2.dev, 0), CLK_PCOM("uart_clk", UART3_CLK, &msm_device_uart3.dev, OFF), -- cgit v1.2.3 From 04c508066f6e9a6a074f9d4498c21a7710a43d61 Mon Sep 17 00:00:00 2001 From: "Ruigrok, Richard" Date: Mon, 17 Aug 2009 15:20:45 -0600 Subject: msm: add proc_comm commands for clkctl_rpc_rail on/off New proc_comm commands: PCOM_CLKCTL_RPC_RAIL_ON PCOM_CLKCTL_RPC_RAIL_OFF Signed-off-by: Richard Ruigrok --- arch/arm/mach-msm/proc_comm.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/proc_comm.h b/arch/arm/mach-msm/proc_comm.h index 3ba013ed3aed..4d236dcbea2e 100644 --- a/arch/arm/mach-msm/proc_comm.h +++ b/arch/arm/mach-msm/proc_comm.h @@ -129,6 +129,8 @@ enum { PCOM_CLK_REGIME_SEC_SET_PCLK_AXI_POLICY, PCOM_CLKCTL_RPC_RESET_ASSERT, PCOM_CLKCTL_RPC_RESET_DEASSERT, + PCOM_CLKCTL_RPC_RAIL_ON, + PCOM_CLKCTL_RPC_RAIL_OFF, PCOM_NUM_CMDS, }; -- cgit v1.2.3 From 9242b02997dcf8b6f6c6e08850924ee9d577647d Mon Sep 17 00:00:00 2001 From: Abhijeet Dharmapurikar Date: Fri, 31 Jul 2009 16:40:35 -0700 Subject: msm: acpuclock-8x50: Couple CPU freq and AXI freq. The memory throughput is directly proportional to the AXI frequency. The AXI freq is coupled with the CPU freq to prevent the memory from being the bottleneck when the CPU is running at one of its higher frequencies. This will cause an increase in power consumption when the CPU is running at higher frequencies, but will give a better performance/power ratio. Signed-off-by: Abhijeet Dharmapurikar --- arch/arm/mach-msm/acpuclock-8x50.c | 73 +++++++++++++++++++++++--------------- 1 file changed, 45 insertions(+), 28 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/acpuclock-8x50.c b/arch/arm/mach-msm/acpuclock-8x50.c index 36c90ea7d27a..b91c0fc7c12f 100644 --- a/arch/arm/mach-msm/acpuclock-8x50.c +++ b/arch/arm/mach-msm/acpuclock-8x50.c @@ -67,6 +67,7 @@ #include #include "acpuclock.h" +#include "clock.h" #define SHOT_SWITCH 4 #define HOP_SWITCH 5 @@ -89,6 +90,7 @@ struct clkctl_acpu_speed { unsigned int a11clk_src_div; unsigned int ahbclk_khz; unsigned int ahbclk_div; + unsigned int axiclk_khz; unsigned int sc_core_src_sel_mask; unsigned int sc_l_value; int vdd; @@ -96,33 +98,33 @@ struct clkctl_acpu_speed { }; struct clkctl_acpu_speed acpu_freq_tbl[] = { - { 0, 19200, ACPU_PLL_TCXO, 0, 0, 0, 0, 0, 0, 1000}, - { 0, 48000, ACPU_PLL_1, 1, 0xF, 0, 0, 0, 0, 1000}, - { 0, 64000, ACPU_PLL_1, 1, 0xB, 0, 0, 0, 0, 1000}, - { 0, 96000, ACPU_PLL_1, 1, 7, 0, 0, 0, 0, 1000}, - { 0, 128000, ACPU_PLL_1, 1, 5, 0, 0, 2, 0, 1000}, - { 0, 192000, ACPU_PLL_1, 1, 3, 0, 0, 0, 0, 1000}, + { 0, 19200, ACPU_PLL_TCXO, 0, 0, 0, 0, 14000, 0, 0, 1000}, + { 0, 48000, ACPU_PLL_1, 1, 0xF, 0, 0, 14000, 0, 0, 1000}, + { 0, 64000, ACPU_PLL_1, 1, 0xB, 0, 0, 14000, 0, 0, 1000}, + { 0, 96000, ACPU_PLL_1, 1, 7, 0, 0, 14000, 0, 0, 1000}, + { 0, 128000, ACPU_PLL_1, 1, 5, 0, 0, 14000, 2, 0, 1000}, + { 0, 192000, ACPU_PLL_1, 1, 3, 0, 0, 14000, 0, 0, 1000}, /* 235.93 on CDMA only. */ - { 1, 245000, ACPU_PLL_0, 4, 0, 0, 0, 0, 0, 1000}, - { 0, 256000, ACPU_PLL_1, 1, 2, 0, 0, 0, 0, 1000}, - { 1, 384000, ACPU_PLL_3, 0, 0, 0, 0, 1, 0xA, 1000}, - { 0, 422400, ACPU_PLL_3, 0, 0, 0, 0, 1, 0xB, 1000}, - { 0, 460800, ACPU_PLL_3, 0, 0, 0, 0, 1, 0xC, 1000}, - { 0, 499200, ACPU_PLL_3, 0, 0, 0, 0, 1, 0xD, 1025}, - { 0, 537600, ACPU_PLL_3, 0, 0, 0, 0, 1, 0xE, 1050}, - { 1, 576000, ACPU_PLL_3, 0, 0, 0, 0, 1, 0xF, 1050}, - { 0, 614400, ACPU_PLL_3, 0, 0, 0, 0, 1, 0x10, 1075}, - { 0, 652800, ACPU_PLL_3, 0, 0, 0, 0, 1, 0x11, 1100}, - { 0, 691200, ACPU_PLL_3, 0, 0, 0, 0, 1, 0x12, 1125}, - { 0, 729600, ACPU_PLL_3, 0, 0, 0, 0, 1, 0x13, 1150}, - { 1, 768000, ACPU_PLL_3, 0, 0, 0, 0, 1, 0x14, 1150}, - { 0, 806400, ACPU_PLL_3, 0, 0, 0, 0, 1, 0x15, 1175}, - { 0, 844800, ACPU_PLL_3, 0, 0, 0, 0, 1, 0x16, 1200}, - { 0, 883200, ACPU_PLL_3, 0, 0, 0, 0, 1, 0x17, 1225}, - { 0, 921600, ACPU_PLL_3, 0, 0, 0, 0, 1, 0x18, 1250}, - { 0, 960000, ACPU_PLL_3, 0, 0, 0, 0, 1, 0x19, 1250}, - { 1, 998400, ACPU_PLL_3, 0, 0, 0, 0, 1, 0x1A, 1250}, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 1, 245000, ACPU_PLL_0, 4, 0, 0, 0, 29000, 0, 0, 1000}, + { 0, 256000, ACPU_PLL_1, 1, 2, 0, 0, 29000, 0, 0, 1000}, + { 1, 384000, ACPU_PLL_3, 0, 0, 0, 0, 58000, 1, 0xA, 1000}, + { 0, 422400, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0xB, 1000}, + { 0, 460800, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0xC, 1000}, + { 0, 499200, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0xD, 1025}, + { 0, 537600, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0xE, 1050}, + { 1, 576000, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0xF, 1050}, + { 0, 614400, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0x10, 1075}, + { 0, 652800, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0x11, 1100}, + { 0, 691200, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0x12, 1125}, + { 0, 729600, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0x13, 1150}, + { 1, 768000, ACPU_PLL_3, 0, 0, 0, 0, 128000, 1, 0x14, 1150}, + { 0, 806400, ACPU_PLL_3, 0, 0, 0, 0, 128000, 1, 0x15, 1175}, + { 0, 844800, ACPU_PLL_3, 0, 0, 0, 0, 128000, 1, 0x16, 1200}, + { 0, 883200, ACPU_PLL_3, 0, 0, 0, 0, 128000, 1, 0x17, 1225}, + { 0, 921600, ACPU_PLL_3, 0, 0, 0, 0, 128000, 1, 0x18, 1250}, + { 0, 960000, ACPU_PLL_3, 0, 0, 0, 0, 128000, 1, 0x19, 1250}, + { 1, 998400, ACPU_PLL_3, 0, 0, 0, 0, 128000, 1, 0x1A, 1250}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, }; #ifdef CONFIG_CPU_FREQ_MSM @@ -443,8 +445,19 @@ int acpuclk_set_rate(unsigned long rate, enum setrate_reason reason) /* Re-adjust lpj for the new clock speed. */ loops_per_jiffy = tgt_s->lpj; - /* Nothing else to do for power collapse or SWFI. */ - if (reason != SETRATE_CPUFREQ) + /* Nothing else to do for SWFI. */ + if (reason == SETRATE_SWFI) + return 0; + + if (strt_s->axiclk_khz != tgt_s->axiclk_khz) { + rc = ebi1_clk_set_min_rate(CLKVOTE_ACPUCLK, + tgt_s->axiclk_khz * 1000); + if (rc < 0) + pr_err("Setting AXI min rate failed!\n"); + } + + /* Nothing else to do for power collapse */ + if (reason == SETRATE_PC) return 0; /* Drop VDD level if we can. */ @@ -465,6 +478,7 @@ static void __init acpuclk_init(void) { struct clkctl_acpu_speed *speed; uint32_t div, sel, regval; + int rc; /* Determine the source of the Scorpion clock. */ regval = readl(SPSS_CLK_SEL_ADDR); @@ -516,6 +530,9 @@ static void __init acpuclk_init(void) } drv_state.current_speed = speed; + rc = ebi1_clk_set_min_rate(CLKVOTE_ACPUCLK, speed->axiclk_khz * 1000); + if (rc < 0) + pr_err("Setting AXI min rate failed!\n"); printk(KERN_INFO "ACPU running at %d KHz\n", speed->a11clk_khz); } -- cgit v1.2.3 From 2f9da9dfc830b3cd41e34c287041f114d70fdc5a Mon Sep 17 00:00:00 2001 From: Saravana Kannan Date: Wed, 15 Jul 2009 18:05:31 -0700 Subject: msm: clock: Implement direct clock control for 7x30. The other existing targets use proc_comm calls to the modem processor to control all the clocks. In 7x30 based SoCs, the application processor has read/write permissions to most clock registers. This allows direct control of most clocks in 7x30 based SoCs. Since the shadow registers aren't accessible at this time (requires modem change), the init code has been commented out to avoid trampling over registers that are used by the modem. Signed-off-by: Saravana Kannan --- arch/arm/mach-msm/Makefile | 2 +- arch/arm/mach-msm/clock-7x30.c | 936 +++++++++++++++++++++++++++++++++++++++++ arch/arm/mach-msm/clock-7x30.h | 136 ++++++ arch/arm/mach-msm/clock.h | 1 + 4 files changed, 1074 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-msm/clock-7x30.c create mode 100644 arch/arm/mach-msm/clock-7x30.h (limited to 'arch') diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 2a65859efb6f..523db55ad00f 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -58,7 +58,7 @@ obj-$(CONFIG_TROUT_H2W) += board-trout-h2w.o obj-$(CONFIG_TROUT_BATTCHG) += htc_battery.o obj-$(CONFIG_TROUT_PWRSINK) += htc_pwrsink.o obj-$(CONFIG_ARCH_MSM7X27) += board-msm7x27.o -obj-$(CONFIG_ARCH_MSM7X30) += board-msm7x30.o +obj-$(CONFIG_ARCH_MSM7X30) += board-msm7x30.o clock-7x30.o obj-$(CONFIG_QSD_AUDIO) += qdsp6/ diff --git a/arch/arm/mach-msm/clock-7x30.c b/arch/arm/mach-msm/clock-7x30.c new file mode 100644 index 000000000000..70a824ba4489 --- /dev/null +++ b/arch/arm/mach-msm/clock-7x30.c @@ -0,0 +1,936 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clock.h" +#include "clock-7x30.h" + +struct clk_freq_tbl { + uint32_t freq_hz; + uint32_t src; + uint32_t md_val; + uint32_t ns_val; + uint32_t mode; +}; + +struct clk_local { + uint32_t count; + uint32_t type; + uint32_t md_reg; + uint32_t ns_reg; + uint32_t freq_mask; + uint32_t br_en_mask; + uint32_t root_en_mask; + int parent; + uint32_t *children; + struct clk_freq_tbl *freq_tbl; + struct clk_freq_tbl *current_freq; +}; + + +enum { + SRC_PLL0 = 4, /* Modem PLL */ + SRC_PLL1 = 1, /* Global PLL */ + SRC_PLL3 = 3, /* Multimedia/Peripheral PLL or Backup PLL1 */ + SRC_PLL4 = 2, /* Display PLL */ + SRC_LPXO = 6, /* Low power XO. */ + SRC_MAX /* Used for sources that can't be turned on/off. */ +}; + +struct pll_data { + int count; + uint32_t bit_mask; +}; + +static struct pll_data pll_tbl[SRC_MAX] = { + /* FIXME: Put in proper values for bit_mask. */ + [SRC_PLL0] = { 0, 0 }, + [SRC_PLL1] = { 0, 0 }, + [SRC_PLL3] = { 0, 0 }, + [SRC_PLL4] = { 0, 0 }, +}; + +#define B(x) BIT(x) +#define BM(msb, lsb) (((((uint32_t)-1) << (31-msb)) >> (31-msb+lsb)) << lsb) +#define BVAL(msb, lsb, val) (((val) << lsb) & BM(msb, lsb)) + +#define MD8(m, n) (BVAL(15, 8, m) | BVAL(7, 0, ~(n))) +#define N8(msb, lsb, m, n) (BVAL(msb, lsb, ~(n-m))) +#define MD16(m, n) (BVAL(31, 16, m) | BVAL(15, 0, ~(n))) +#define N16(m, n) (BVAL(31, 16, ~(n-m))) +#define SPDIV(s, d) (BVAL(4, 3, d-1) | BVAL(2, 0, s)) +#define SDIV(s, d) (BVAL(6, 3, d-1) | BVAL(2, 0, s)) +#define F_MASK_BASIC (BM(6, 3)|BM(2, 0)) +#define F_MASK_MND16 (BM(31, 16)|BM(4, 3)|BM(2, 0)) +#define F_MASK_MND8(m, l) (BM(m, l)|BM(4, 3)|BM(2, 0)) + +#define F_RAW(f, s, m_v, n_v, mde) { \ + .freq_hz = f, \ + .src = s, \ + .md_val = m_v, \ + .ns_val = n_v, \ + .mode = mde, \ + } + +#define FREQ_END 0 +#define F_BASIC(f, s, div) F_RAW(f, s, 0, SDIV(s, div), 0) +#define F_MND16(f, s, div, m, n) \ + F_RAW(f, s, MD16(m, n), N16(m, n)|SPDIV(s, div), !!(n)) +#define F_MND8(f, nmsb, nlsb, s, div, m, n) \ + F_RAW(f, s, MD8(m, n), N8(nmsb, nlsb, m, n)|SPDIV(s, div), !!(n)) +#define F_END F_RAW(FREQ_END, SRC_MAX, 0, 0, 0) + +static struct clk_freq_tbl clk_tbl_tcxo[] = { + F_RAW(19200000, SRC_MAX, 0, 0, 0), + F_END, +}; + +static struct clk_freq_tbl clk_tbl_uartdm[] = { + F_MND16( 3686400, SRC_PLL3, 3, 3, 200), + F_MND16( 7372800, SRC_PLL3, 3, 3, 100), + F_MND16(14745600, SRC_PLL3, 3, 3, 50), + F_MND16(46400000, SRC_PLL3, 3, 145, 768), + F_MND16(51200000, SRC_PLL3, 3, 5, 24), + F_MND16(58982400, SRC_PLL3, 3, 6, 25), + F_MND16(64000000, SRC_PLL1, 4, 1, 3), + F_END, +}; + +static struct clk_freq_tbl clk_tbl_mdh[] = { + F_BASIC( 73728000, SRC_PLL3, 10), + F_BASIC( 92160000, SRC_PLL3, 8), + F_BASIC(122880000, SRC_PLL3, 6), + F_BASIC(184320000, SRC_PLL3, 4), + F_BASIC(245760000, SRC_PLL3, 3), + F_BASIC(368640000, SRC_PLL3, 2), + F_BASIC(384000000, SRC_PLL1, 2), + F_END, +}; + +static struct clk_freq_tbl clk_tbl_grp[] = { + F_BASIC( 24576000, SRC_LPXO, 1), + F_BASIC( 46000000, SRC_PLL3, 16), + F_BASIC( 49000000, SRC_PLL3, 15), + F_BASIC( 52000000, SRC_PLL3, 14), + F_BASIC( 56000000, SRC_PLL3, 13), + F_BASIC( 61440000, SRC_PLL3, 12), + F_BASIC( 67000000, SRC_PLL3, 11), + F_BASIC( 73000000, SRC_PLL3, 10), + F_BASIC( 81000000, SRC_PLL3, 9), + F_BASIC( 92000000, SRC_PLL3, 8), + F_BASIC(105000000, SRC_PLL3, 7), + F_BASIC(120000000, SRC_PLL3, 6), + F_BASIC(150000000, SRC_PLL3, 5), + F_BASIC(183000000, SRC_PLL3, 4), + F_BASIC(192000000, SRC_PLL1, 4), + F_BASIC(245760000, SRC_PLL3, 3), + /* Sync to AXI. Hence this "rate" is not fixed. */ + F_RAW(1, SRC_MAX, 0, B(14), 0), + F_END, +}; + +static struct clk_freq_tbl clk_tbl_sdc1_3[] = { + F_MND8( 144000, 19, 12, SRC_LPXO, 1, 1, 171), + F_MND8( 400000, 19, 12, SRC_LPXO, 1, 2, 123), + F_MND8(16000000, 19, 12, SRC_PLL3, 3, 14, 215), + F_MND8(17000000, 19, 12, SRC_PLL3, 4, 19, 206), + F_MND8(20000000, 19, 12, SRC_PLL3, 4, 23, 212), + F_MND8(25000000, 19, 12, SRC_LPXO, 1, 0, 0), + F_MND8(50000000, 19, 12, SRC_PLL3, 3, 1, 5), + F_END, +}; + +static struct clk_freq_tbl clk_tbl_sdc2_4[] = { + F_MND8( 144000, 20, 13, SRC_LPXO, 1, 1, 171), + F_MND8( 400000, 20, 13, SRC_LPXO, 1, 2, 123), + F_MND8(16000000, 20, 13, SRC_PLL3, 3, 14, 215), + F_MND8(17000000, 20, 13, SRC_PLL3, 4, 19, 206), + F_MND8(20000000, 20, 13, SRC_PLL3, 4, 23, 212), + F_MND8(25000000, 20, 13, SRC_LPXO, 1, 0, 0), + F_MND8(50000000, 20, 13, SRC_PLL3, 3, 1, 5), + F_END, +}; + +static struct clk_freq_tbl clk_tbl_mdp_core[] = { + F_BASIC( 46000000, SRC_PLL3, 16), + F_BASIC( 49000000, SRC_PLL3, 15), + F_BASIC( 52000000, SRC_PLL3, 14), + F_END, +}; + +static struct clk_freq_tbl clk_tbl_mdp_lcdc[] = { + F_MND16(25000000, SRC_LPXO, 1, 0, 0), + F_MND16(30000000, SRC_PLL3, 4, 1, 6), + F_MND16(40000000, SRC_PLL3, 2, 1, 9), + F_END, +}; + +static struct clk_freq_tbl clk_tbl_mdp_vsync[] = { + F_RAW(24576000, SRC_MAX, 0, 0, 0), /* Initialized to LPXO. */ + F_END, +}; + +static struct clk_freq_tbl clk_tbl_mi2s_codec[] = { + F_MND16( 2048000, SRC_LPXO, 4, 1, 3), + F_MND16(12288000, SRC_LPXO, 2, 0, 0), + F_END, +}; + +static struct clk_freq_tbl clk_tbl_mi2s[] = { + F_MND16(12288000, SRC_LPXO, 2, 0, 0), + F_END, +}; + +static struct clk_freq_tbl clk_tbl_midi[] = { + F_MND8(98304000, 19, 12, SRC_PLL3, 3, 2, 5), + F_END, +}; +static struct clk_freq_tbl clk_tbl_sdac[] = { + F_MND16( 256000, SRC_LPXO, 4, 1, 24), + F_MND16( 352800, SRC_LPXO, 1, 147, 10240), + F_MND16( 384000, SRC_LPXO, 4, 1, 16), + F_MND16( 512000, SRC_LPXO, 4, 1, 12), + F_MND16( 705600, SRC_LPXO, 1, 147, 5120), + F_MND16( 768000, SRC_LPXO, 4, 1, 8), + F_MND16(1024000, SRC_LPXO, 4, 1, 6), + F_MND16(1411200, SRC_LPXO, 1, 147, 2560), + F_MND16(1536000, SRC_LPXO, 4, 1, 4), + F_END, +}; + +static struct clk_freq_tbl clk_tbl_tv[] = { + F_MND8(27000000, 23, 16, SRC_PLL4, 2, 2, 33), + F_MND8(74250000, 23, 16, SRC_PLL4, 2, 1, 6), + F_END, +}; + +static struct clk_freq_tbl clk_tbl_usb[] = { + F_MND8(60000000, 23, 16, SRC_PLL1, 2, 5, 32), + F_END, +}; + +static struct clk_freq_tbl clk_tbl_vfe_jpeg[] = { + F_MND16( 36000000, SRC_PLL3, 4, 1, 5), + F_MND16( 46000000, SRC_PLL3, 4, 1, 4), + F_MND16( 61440000, SRC_PLL3, 4, 1, 3), + F_MND16( 74000000, SRC_PLL3, 2, 1, 5), + F_MND16( 82000000, SRC_PLL3, 3, 1, 3), + F_MND16( 92000000, SRC_PLL3, 4, 1, 2), + F_MND16( 98000000, SRC_PLL3, 3, 2, 5), + F_MND16(105000000, SRC_PLL3, 2, 2, 7), + F_MND16(122880000, SRC_PLL3, 2, 1, 3), + F_MND16(148000000, SRC_PLL3, 2, 2, 5), + F_MND16(154000000, SRC_PLL1, 2, 2, 5), + F_END, +}; + +static struct clk_freq_tbl clk_tbl_cam[] = { + F_MND16( 6000000, SRC_PLL1, 4, 1, 32), + F_MND16( 8000000, SRC_PLL1, 4, 1, 24), + F_MND16(12000000, SRC_PLL1, 4, 1, 16), + F_MND16(16000000, SRC_PLL1, 4, 1, 12), + F_MND16(19000000, SRC_PLL1, 4, 1, 10), + F_MND16(24000000, SRC_PLL1, 4, 1, 8), + F_MND16(32000000, SRC_PLL1, 4, 1, 6), + F_MND16(48000000, SRC_PLL1, 4, 1, 4), + F_MND16(64000000, SRC_PLL1, 4, 1, 3), + F_END, +}; + +static struct clk_freq_tbl clk_tbl_vpe[] = { + F_MND8( 24576000, 22, 15, SRC_LPXO, 1, 0, 0), + F_MND8( 30720000, 22, 15, SRC_PLL3, 4, 1, 6), + F_MND8( 61440000, 22, 15, SRC_PLL3, 4, 1, 3), + F_MND8( 81920000, 22, 15, SRC_PLL3, 3, 1, 3), + F_MND8(122880000, 22, 15, SRC_PLL3, 3, 1, 2), + F_MND8(147000000, 22, 15, SRC_PLL3, 1, 1, 5), + F_MND8(153600000, 22, 15, SRC_PLL1, 1, 1, 5), + F_MND8(170667000, 22, 15, SRC_PLL1, 1, 2, 9), + F_END, +}; + +static struct clk_freq_tbl clk_tbl_mfc[] = { + F_MND8( 24576000, 24, 17, SRC_LPXO, 1, 0, 0), + F_MND8( 30720000, 24, 17, SRC_PLL3, 4, 1, 6), + F_MND8( 61440000, 24, 17, SRC_PLL3, 4, 1, 3), + F_MND8( 81920000, 24, 17, SRC_PLL3, 3, 1, 3), + F_MND8(122880000, 24, 17, SRC_PLL3, 3, 1, 2), + F_MND8(147000000, 24, 17, SRC_PLL3, 1, 1, 5), + F_MND8(153600000, 24, 17, SRC_PLL1, 1, 1, 5), + F_MND8(170667000, 24, 17, SRC_PLL1, 1, 2, 9), + F_END, +}; + +static struct clk_freq_tbl clk_tbl_spi[] = { + F_MND8(10000000, 19, 12, SRC_PLL3, 4, 7, 129), + F_MND8(26000000, 19, 12, SRC_PLL3, 4, 34, 241), + F_END, +}; + +static struct clk_freq_tbl clk_tbl_lpa_codec[] = { + F_RAW(1, SRC_MAX, 0, 0, 0), /* src = MI2S_CODEC_RX */ + F_RAW(2, SRC_MAX, 0, 1, 0), /* src = ECODEC_CIF */ + F_RAW(3, SRC_MAX, 0, 2, 0), /* src = MI2S */ + F_RAW(4, SRC_MAX, 0, 3, 0), /* src = SDAC */ + F_END, +}; + +static struct clk_freq_tbl dummy_freq = F_END; + +#define MND 1 /* Integer predivider and fractional MN:D divider. */ +#define BASIC 2 /* Integer divider. */ +#define NORATE 3 /* Just on/off. */ + +#define C(x) L_7X30_##x##_CLK + +#define CLK_LOCAL(id, t, md, ns, f_msk, br, root, tbl, par, chld_lst) \ + [C(id)] = { \ + .type = t, \ + .md_reg = md, \ + .ns_reg = ns, \ + .freq_mask = f_msk, \ + .br_en_mask = br, \ + .root_en_mask = root, \ + .parent = C(par), \ + .children = chld_lst, \ + .freq_tbl = tbl, \ + .current_freq = &dummy_freq, \ + } + +#define CLK_BASIC(id, ns, br, root, tbl, par) \ + CLK_LOCAL(id, BASIC, 0, ns, F_MASK_BASIC, br, root, tbl, \ + par, NULL) +#define CLK_MND8_P(id, ns, m, l, br, root, tbl, par, chld_lst) \ + CLK_LOCAL(id, MND, (ns-4), ns, F_MASK_MND8(m, l), br, root, \ + tbl, par, chld_lst) +#define CLK_MND8(id, ns, m, l, br, root, tbl, chld_lst) \ + CLK_MND8_P(id, ns, m, l, br, root, tbl, NONE, chld_lst) +#define CLK_MND16(id, ns, br, root, tbl, par, chld_lst) \ + CLK_LOCAL(id, MND, (ns-4), ns, F_MASK_MND16, br, root, tbl, \ + par, chld_lst) +#define CLK_1RATE(id, ns, br, root, tbl) \ + CLK_LOCAL(id, BASIC, 0, ns, 0, br, root, tbl, NONE, NULL) +#define CLK_SLAVE(id, ns, br, par) \ + CLK_LOCAL(id, NORATE, 0, ns, 0, br, 0, NULL, par, NULL) +#define CLK_NORATE(id, ns, br, root) \ + CLK_LOCAL(id, NORATE, 0, ns, 0, br, root, NULL, NONE, NULL) +#define CLK_GLBL(id, glbl, root) \ + CLK_LOCAL(id, NORATE, 0, glbl, 0, 0, root, NULL, NONE, NULL) +#define CLK_BRIDGE(id, glbl, root, par) \ + CLK_LOCAL(id, NORATE, 0, glbl, 0, 0, root, NULL, par, NULL) + +#define REG(off) (MSM_CLK_CTL_BASE + off) +#define MNCNTR_EN_MASK B(8) +#define MNCNTR_RST_MASK B(7) +#define MNCNTR_MODE_MASK BM(6, 5) +#define MNCNTR_MODE BVAL(6, 5, 0x2) /* Dual-edge mode. */ + +/* Register offsets used more than once. */ +#define USBH_MD 0x02BC +#define USBH_NS 0x02C0 +#define USBH2_NS 0x046C +#define USBH3_NS 0x0470 +#define CAM_VFE_NS 0x0044 +#define GLBL_CLK_ENA_SC 0x03BC +#define GLBL_CLK_ENA_2_SC 0x03C0 +#define SDAC_NS 0x009C +#define TV_NS 0x00CC +#define MI2S_RX_NS 0x0070 +#define MI2S_TX_NS 0x0078 +#define MI2S_NS 0x02E0 +#define LPA_NS 0x02E8 +#define MDC_NS 0x007C +#define MDP_VSYNC_REG 0x0460 +#define PLL_ENA_REG 0x0260 + +static uint32_t chld_grp_3d_src[] = {C(IMEM), C(GRP_3D), C(NONE)}; +static uint32_t chld_mdp_lcdc_p[] = {C(MDP_LCDC_PAD_P), C(NONE)}; +static uint32_t chld_mi2s_codec_rx[] = {C(MI2S_CODEC_RX_S), C(NONE)}; +static uint32_t chld_mi2s_codec_tx[] = {C(MI2S_CODEC_TX_S), C(NONE)}; +static uint32_t chld_mi2s[] = {C(MI2S_S), C(NONE)}; +static uint32_t chld_sdac_m[] = {C(SDAC_S), C(NONE)}; +static uint32_t chld_tv[] = {C(TV_DAC), C(TV_ENC), C(TSIF_REF), C(NONE)}; +static uint32_t chld_usb_src[] = { + C(USB_HS), C(USB_HS_CORE), + C(USB_HS2), C(USB_HS2_CORE), + C(USB_HS3), C(USB_HS3_CORE), + C(NONE), +}; +uint32_t chld_vfe[] = {C(VFE_MDC), C(VFE_CAMIF), C(NONE)}; + +static struct clk_local clk_local_tbl[] = { + CLK_NORATE(MDC, MDC_NS, B(9), B(11)), + CLK_NORATE(LPA_CORE, LPA_NS, B(5), 0), + + CLK_1RATE(I2C, 0x0068, B(9), B(11), clk_tbl_tcxo), + CLK_1RATE(I2C_2, 0x02D8, B(0), B(2), clk_tbl_tcxo), + CLK_1RATE(QUP_I2C, 0x04F0, B(0), B(2), clk_tbl_tcxo), + CLK_1RATE(UART1, 0x00E0, B(5), B(4), clk_tbl_tcxo), + CLK_1RATE(UART3, 0x0468, B(5), B(4), clk_tbl_tcxo), + + CLK_BASIC(EMDH, 0x0050, 0, B(11), clk_tbl_mdh, NONE), + CLK_BASIC(PMDH, 0x008C, 0, B(11), clk_tbl_mdh, NONE), + CLK_BASIC(MDP, 0x014C, B(9), B(11), clk_tbl_mdp_core, + AXI_MDP), + + CLK_MND8_P(VPE, 0x015C, 22, 15, B(9), B(11), clk_tbl_vpe, + AXI_VPE, NULL), + /* Combining MFC and MFC_DIV2 clocks. */ + CLK_MND8_P(MFC, 0x0154, 24, 17, B(9)|B(15), B(11), clk_tbl_mfc, + AXI_MFC, NULL), + + CLK_MND8(SDC1, 0x00A4, 19, 12, B(9), B(11), clk_tbl_sdc1_3, NULL), + CLK_MND8(SDC2, 0x00AC, 20, 13, B(9), B(11), clk_tbl_sdc2_4, NULL), + CLK_MND8(SDC3, 0x00B4, 19, 12, B(9), B(11), clk_tbl_sdc1_3, NULL), + CLK_MND8(SDC4, 0x00BC, 20, 13, B(9), B(11), clk_tbl_sdc2_4, NULL), + CLK_MND8(SPI, 0x02C8, 19, 12, B(9), B(11), clk_tbl_spi, NULL), + CLK_MND8(MIDI, 0x02D0, 19, 12, B(9), B(11), clk_tbl_midi, NULL), + CLK_MND8(USB_HS_SRC, USBH_NS, 23, 16, 0, B(11), clk_tbl_usb, + chld_usb_src), + CLK_SLAVE(USB_HS, USBH_NS, B(9), USB_HS_SRC), + CLK_SLAVE(USB_HS_CORE, USBH_NS, B(13), USB_HS_SRC), + CLK_SLAVE(USB_HS2, USBH2_NS, B(9), USB_HS_SRC), + CLK_SLAVE(USB_HS2_CORE, USBH2_NS, B(4), USB_HS_SRC), + CLK_SLAVE(USB_HS3, USBH3_NS, B(9), USB_HS_SRC), + CLK_SLAVE(USB_HS3_CORE, USBH3_NS, B(4), USB_HS_SRC), + CLK_MND8(TV, TV_NS, 23, 16, 0, B(11), clk_tbl_tv, chld_tv), + CLK_SLAVE(TV_DAC, TV_NS, B(12), TV), + CLK_SLAVE(TV_ENC, TV_NS, B(9), TV), + /* Hacking root & branch into one param. */ + CLK_SLAVE(TSIF_REF, 0x00C4, B(9)|B(11), TV), + + CLK_MND16(UART1DM, 0x00D4, B(9), B(11), clk_tbl_uartdm, NONE, NULL), + CLK_MND16(UART2DM, 0x00DC, B(9), B(11), clk_tbl_uartdm, NONE, NULL), + CLK_MND16(JPEG, 0x0164, B(9), B(11), clk_tbl_vfe_jpeg, + AXI_LI_JPEG, NULL), + CLK_MND16(CAM, 0x0374, 0, B(9), clk_tbl_cam, NONE, NULL), + CLK_MND16(VFE, CAM_VFE_NS, B(9), B(13), clk_tbl_vfe_jpeg, + AXI_LI_VFE, chld_vfe), + CLK_SLAVE(VFE_MDC, CAM_VFE_NS, B(11), VFE), + CLK_SLAVE(VFE_CAMIF, CAM_VFE_NS, B(15), VFE), + + CLK_MND16(SDAC_M, SDAC_NS, B(12), B(11), clk_tbl_sdac, + NONE, chld_sdac_m), + CLK_SLAVE(SDAC_S, SDAC_NS, B(9), SDAC_M), + + CLK_MND16(MDP_LCDC_P, 0x0390, B(9), B(11), clk_tbl_mdp_lcdc, + NONE, chld_mdp_lcdc_p), + CLK_SLAVE(MDP_LCDC_PAD_P, 0x0390, B(12), MDP_LCDC_P), + CLK_1RATE(MDP_VSYNC, MDP_VSYNC_REG, B(0), 0, clk_tbl_mdp_vsync), + + CLK_MND16(MI2S_CODEC_RX_M, MI2S_RX_NS, B(12), B(11), + clk_tbl_mi2s_codec, NONE, chld_mi2s_codec_rx), + CLK_SLAVE(MI2S_CODEC_RX_S, MI2S_RX_NS, B(9), MI2S_CODEC_RX_M), + + CLK_MND16(MI2S_CODEC_TX_M, MI2S_TX_NS, B(12), B(11), + clk_tbl_mi2s_codec, NONE, chld_mi2s_codec_tx), + CLK_SLAVE(MI2S_CODEC_TX_S, MI2S_TX_NS, B(9), MI2S_CODEC_TX_M), + + CLK_MND16(MI2S_M, MI2S_NS, B(12), B(11), + clk_tbl_mi2s, NONE, chld_mi2s), + CLK_SLAVE(MI2S_S, MI2S_NS, B(9), MI2S_M), + + CLK_LOCAL(GRP_2D, BASIC, 0, 0x0034, F_MASK_BASIC | (7 << 12), + B(7), B(11), clk_tbl_grp, AXI_GRP_2D, NULL), + CLK_LOCAL(GRP_3D_SRC, BASIC, 0, 0x0084, F_MASK_BASIC | (7 << 12), + 0, B(11), clk_tbl_grp, AXI_LI_GRP, chld_grp_3d_src), + CLK_SLAVE(GRP_3D, 0x0084, B(7), GRP_3D_SRC), + CLK_SLAVE(IMEM, 0x0084, B(9), GRP_3D_SRC), + CLK_LOCAL(LPA_CODEC, BASIC, 0, LPA_NS, BM(1, 0), B(9), 0, + clk_tbl_lpa_codec, NONE, NULL), + + /* Peripheral bus clocks. */ + CLK_GLBL(ADM, GLBL_CLK_ENA_SC, B(5)), + CLK_GLBL(CAMIF_PAD_P, GLBL_CLK_ENA_SC, B(9)), + CLK_GLBL(EMDH_P, GLBL_CLK_ENA_2_SC, B(3)), + CLK_GLBL(GRP_2D_P, GLBL_CLK_ENA_SC, B(24)), + CLK_GLBL(GRP_3D_P, GLBL_CLK_ENA_2_SC, B(17)), + CLK_GLBL(JPEG_P, GLBL_CLK_ENA_2_SC, B(24)), + CLK_GLBL(MDP_P, GLBL_CLK_ENA_2_SC, B(6)), + CLK_GLBL(MFC_P, GLBL_CLK_ENA_2_SC, B(26)), + CLK_GLBL(PMDH_P, GLBL_CLK_ENA_2_SC, B(4)), + CLK_GLBL(SDC1_H, GLBL_CLK_ENA_SC, B(7)), + CLK_GLBL(SDC2_H, GLBL_CLK_ENA_SC, B(8)), + CLK_GLBL(SDC3_H, GLBL_CLK_ENA_SC, B(27)), + CLK_GLBL(SDC4_H, GLBL_CLK_ENA_SC, B(28)), + CLK_GLBL(SPI_P, GLBL_CLK_ENA_2_SC, B(10)), + CLK_GLBL(TSIF_P, GLBL_CLK_ENA_SC, B(18)), + CLK_GLBL(UART1DM_P, GLBL_CLK_ENA_SC, B(17)), + CLK_GLBL(UART2DM_P, GLBL_CLK_ENA_SC, B(26)), + CLK_GLBL(USB_HS2_P, GLBL_CLK_ENA_2_SC, B(8)), + CLK_GLBL(USB_HS3_P, GLBL_CLK_ENA_2_SC, B(9)), + CLK_GLBL(USB_HS_P, GLBL_CLK_ENA_SC, B(25)), + CLK_GLBL(VFE_P, GLBL_CLK_ENA_2_SC, B(27)), + CLK_GLBL(LPA_P, GLBL_CLK_ENA_2_SC, B(7)), + + /* AXI bridge clocks. */ + CLK_BRIDGE(AXI_LI_APPS, GLBL_CLK_ENA_SC, B(2), NONE), + CLK_BRIDGE(AXI_LI_JPEG, GLBL_CLK_ENA_2_SC, B(19), AXI_LI_APPS), + CLK_BRIDGE(AXI_LI_VFE, GLBL_CLK_ENA_SC, B(23), AXI_LI_APPS), + CLK_BRIDGE(AXI_MDP, GLBL_CLK_ENA_2_SC, B(29), AXI_LI_APPS), + + CLK_BRIDGE(AXI_IMEM, GLBL_CLK_ENA_2_SC, B(18), NONE), + + CLK_BRIDGE(AXI_LI_VG, GLBL_CLK_ENA_SC, B(3), NONE), + CLK_BRIDGE(AXI_GRP_2D, GLBL_CLK_ENA_SC, B(21), AXI_LI_VG), + CLK_BRIDGE(AXI_LI_GRP, GLBL_CLK_ENA_SC, B(22), AXI_LI_VG), + CLK_BRIDGE(AXI_MFC, GLBL_CLK_ENA_2_SC, B(20), AXI_LI_VG), + CLK_BRIDGE(AXI_VPE, GLBL_CLK_ENA_2_SC, B(21), AXI_LI_VG), +}; + +static DEFINE_SPINLOCK(clock_reg_lock); + +void pll_enable(uint32_t pll) +{ + struct pll_data *p; + uint32_t reg_val; + + /* SRC_MAX is used as a placeholder for some freqencies that don't + * have any direct PLL dependency. */ + if (pll == SRC_MAX || pll == SRC_LPXO) + return; + + p = &pll_tbl[pll]; + if (!p->count) { + reg_val = readl(REG(PLL_ENA_REG)); + reg_val |= p->bit_mask; + writel(reg_val, REG(PLL_ENA_REG)); + } + p->count++; +} + +void pll_disable(uint32_t pll) +{ + struct pll_data *p; + uint32_t reg_val; + + /* SRC_MAX is used as a placeholder for some freqencies that don't + * have any direct PLL dependency. */ + if (pll == SRC_MAX || pll == SRC_LPXO) + return; + + p = &pll_tbl[pll]; + if (!p->count) { + pr_warning("Reference count mismatch in PLL disable!\n"); + return; + } + if (p->count) + p->count--; + if (p->count == 0) { + reg_val = readl(REG(PLL_ENA_REG)); + reg_val &= ~(p->bit_mask); + writel(reg_val, REG(PLL_ENA_REG)); + } +} + +/* + * SoC specific register-based control of clocks. + */ +static int _soc_clk_enable(unsigned id) +{ + struct clk_local *t = &clk_local_tbl[id]; + void *ns_reg = REG(t->ns_reg); + uint32_t reg_val = 0; + + reg_val = readl(ns_reg); + if (t->type == MND) { + /* mode can be either 0 or 1. So the R-value of the + * expression will evaluate to MNCNTR_EN_MASK or 0. This + * avoids the need for a "if(mode == 1)". A "&" will not work + * here. */ + reg_val |= (MNCNTR_EN_MASK * t->current_freq->mode); + writel(reg_val, ns_reg); + } + if (t->root_en_mask) { + reg_val |= t->root_en_mask; + writel(reg_val, ns_reg); + } + if (t->br_en_mask) { + reg_val |= t->br_en_mask; + writel(reg_val, ns_reg); + } + return 0; +} + +static void _soc_clk_disable(unsigned id) +{ + struct clk_local *t = &clk_local_tbl[id]; + void *ns_reg = REG(t->ns_reg); + uint32_t reg_val = 0; + + reg_val = readl(ns_reg); + + if (t->br_en_mask) { + reg_val &= ~(t->br_en_mask); + writel(reg_val, ns_reg); + } + if (t->root_en_mask) { + reg_val &= ~(t->root_en_mask); + writel(reg_val, ns_reg); + } + if (t->type == MND) { + reg_val &= ~MNCNTR_EN_MASK; + writel(reg_val, ns_reg); + } +} + +static int soc_clk_enable_nolock(unsigned id) +{ + struct clk_local *t = &clk_local_tbl[id]; + int ret = 0; + + if (!t->count) { + if (t->parent != C(NONE)) + soc_clk_enable_nolock(t->parent); + pll_enable(t->current_freq->src); + ret = _soc_clk_enable(id); + } + t->count++; + + return ret; +} + +static void soc_clk_disable_nolock(unsigned id) +{ + struct clk_local *t = &clk_local_tbl[id]; + + if (!t->count) { + pr_warning("Reference count mismatch in clock disable!\n"); + return; + } + if (t->count) + t->count--; + if (t->count == 0) { + _soc_clk_disable(id); + pll_disable(t->current_freq->src); + if (t->parent != C(NONE)) + soc_clk_disable_nolock(t->parent); + } + + return; +} + +static int soc_clk_enable(unsigned id) +{ + int ret = 0; + unsigned long flags; + + spin_lock_irqsave(&clock_reg_lock, flags); + ret = soc_clk_enable_nolock(id); + spin_unlock_irqrestore(&clock_reg_lock, flags); + + return ret; +} + +static void soc_clk_disable(unsigned id) +{ + unsigned long flags; + + spin_lock_irqsave(&clock_reg_lock, flags); + soc_clk_disable_nolock(id); + spin_unlock_irqrestore(&clock_reg_lock, flags); + + return; +} + +static int soc_clk_set_rate(unsigned id, unsigned rate) +{ + struct clk_local *t = &clk_local_tbl[id]; + struct clk_freq_tbl *cf = t->current_freq; + struct clk_freq_tbl *nf; + uint32_t *chld = t->children; + void *ns_reg = REG(t->ns_reg); + void *md_reg = REG(t->md_reg); + uint32_t reg_val = 0; + int i, ret = 0; + unsigned long flags; + + if (t->type != MND && t->type != BASIC) + return -EPERM; + + spin_lock_irqsave(&clock_reg_lock, flags); + + if (rate == cf->freq_hz) + goto release_lock; + + for (nf = t->freq_tbl; nf->freq_hz != FREQ_END; nf++) + if (nf->freq_hz == rate) + break; + + if (nf->freq_hz == FREQ_END) { + ret = -EINVAL; + goto release_lock; + } + + if (t->freq_mask == 0) { + t->current_freq = nf; + goto release_lock; + } + + /* Disable all branches before changing rate to prevent jitter. */ + for (i = 0; chld && chld[i] != C(NONE); i++) { + struct clk_local *ch = &clk_local_tbl[chld[i]]; + /* Don't bother turning off if it is already off. + * Checking ch->count is cheaper (cache) than reading and + * writing to a register (uncached/unbuffered). */ + if (ch->count) { + reg_val = readl(REG(ch->ns_reg)); + reg_val &= ~(ch->br_en_mask); + writel(reg_val, REG(ch->ns_reg)); + } + } + if (t->count) + _soc_clk_disable(id); + + /* Turn on PLL of the new freq. */ + pll_enable(nf->src); + + /* Some clocks share the same register, so must be careful when + * assuming a register doesn't need to be re-read. */ + reg_val = readl(ns_reg); + if (t->type == MND) { + reg_val |= MNCNTR_RST_MASK; + writel(reg_val, ns_reg); + /* TODO: Currently writing 0's into reserved bits for 8-bit + * MND. Can be avoided by adding md_mask. */ + if (nf->mode) + writel(nf->md_val, md_reg); + reg_val &= ~MNCNTR_MODE_MASK; + reg_val |= (MNCNTR_MODE * nf->mode); + } + reg_val &= ~(t->freq_mask); + reg_val |= nf->ns_val; + writel(reg_val, ns_reg); + + if (t->type == MND) { + reg_val &= ~MNCNTR_RST_MASK; + writel(reg_val, ns_reg); + } + + /* Turn off PLL of the old freq. */ + pll_disable(cf->src); + + /* Current freq must be updated before _soc_clk_enable() is called to + * make sure the MNCNTR_E bit is set correctly. */ + t->current_freq = nf; + + if (t->count) + _soc_clk_enable(id); + /* Enable only branches that were ON before. */ + for (i = 0; chld && chld[i] != C(NONE); i++) { + struct clk_local *ch = &clk_local_tbl[chld[i]]; + if (ch->count) { + reg_val = readl(REG(ch->ns_reg)); + reg_val |= ch->br_en_mask; + writel(reg_val, REG(ch->ns_reg)); + } + } + +release_lock: + spin_unlock_irqrestore(&clock_reg_lock, flags); + return ret; +} + +static int soc_clk_set_min_rate(unsigned id, unsigned rate) +{ + return -EPERM; +} + +static int soc_clk_set_max_rate(unsigned id, unsigned rate) +{ + return -EPERM; +} + +static int soc_clk_set_flags(unsigned id, unsigned flags) +{ + return -EPERM; +} + +static unsigned soc_clk_get_rate(unsigned id) +{ + struct clk_local *t = &clk_local_tbl[id]; + unsigned long flags; + unsigned ret = 0; + + spin_lock_irqsave(&clock_reg_lock, flags); + if (t->type == MND && t->type == BASIC) + ret = t->current_freq->freq_hz; + else { + /* Walk up the tree to see if any parent has a rate. */ + while (t->type == NORATE && t->parent != C(NONE)) + t = &clk_local_tbl[t->parent]; + if (t->type == MND || t->type == BASIC) + ret = t->current_freq->freq_hz; + } + spin_unlock_irqrestore(&clock_reg_lock, flags); + + /* Return 0 if the rate has never been set. Might not be correct, + * but it's good enough. */ + if (ret == FREQ_END) + ret = 0; + + return ret; +} + +static unsigned soc_clk_is_enabled(unsigned id) +{ + return !!(clk_local_tbl[id].count); +} + +static long soc_clk_round_rate(unsigned id, unsigned rate) +{ + struct clk_local *t = &clk_local_tbl[id]; + struct clk_freq_tbl *f; + + if (t->type != MND && t->type != BASIC) + return -EINVAL; + + for (f = t->freq_tbl; f->freq_hz != FREQ_END; f++) + if (f->freq_hz >= rate) + return f->freq_hz; + + return -EPERM; +} + +struct clk_ops clk_ops_7x30 = { + .enable = soc_clk_enable, + .disable = soc_clk_disable, + .set_rate = soc_clk_set_rate, + .set_min_rate = soc_clk_set_min_rate, + .set_max_rate = soc_clk_set_max_rate, + .set_flags = soc_clk_set_flags, + .get_rate = soc_clk_get_rate, + .is_enabled = soc_clk_is_enabled, + .round_rate = soc_clk_round_rate, +}; + +#if 0 +static struct reg_init { + void *reg; + uint32_t mask; + uint32_t val; +} ri_list[] __initdata = { + /* TODO: Remove next line from commercial code. */ + {REG(PLL_ENA_REG), 0x7F, 0x7F}, /* Turn on all PLLs. */ + + {REG(0x0050), 0x3 << 17, 0x3}, /* EMDH RX div = div-4. */ + {REG(0x008C), 0x3 << 17, 0x3}, /* PMDH RX div = div-4. */ + /* MI2S_CODEC_RX_S src = MI2S_CODEC_RX_M. */ + {REG(MI2S_RX_NS), B(14), 0x0}, + /* MI2S_CODEC_TX_S src = MI2S_CODEC_TX_M. */ + {REG(MI2S_TX_NS), B(14), 0x0}, + {REG(MI2S_NS), B(14), 0x0}, /* MI2S_S src = MI2S_M. */ + {REG(LPA_NS), B(4), B(4)}, /* LPA CORE src = LPA_CODEC. */ + {REG(0x02EC), 0xF, 0xD}, /* MI2S_CODEC_RX_S div = div-8. */ + {REG(0x02F0), 0xF, 0xD}, /* MI2S_CODEC_TX_S div = div-8. */ + {REG(0x02E4), 0xF, 0x4}, /* MI2S_S div = div-4. */ + {REG(MDC_NS), 0x3, 0x3}, /* MDC src = external MDH src. */ + {REG(SDAC_NS), 0x3 << 14, 0x0}, /* SDAC div = div-1. */ + /* Disable sources TCXO/5 & TCXO/6. UART1 src = TCXO*/ + {REG(0x00E0), 0x3 << 25 | 0x7, 0x0}, + {REG(0x0468), 0x7, 0x0}, /* UART3 src = TCXO. */ + {REG(MDP_VSYNC_REG), 0xC, 0x4}, /* MDP VSYNC src = LPXO. */ + + /* USBH core clocks src = USB_HS_SRC. */ + {REG(USBH_NS), B(15), B(15)}, + {REG(USBH2_NS), B(6), B(6)}, + {REG(USBH3_NS), B(6), B(6)}, +}; + +#define set_1rate(clk) \ + soc_clk_set_rate(C(clk), clk_local_tbl[C(clk)].freq_tbl->freq_hz) +static __init int soc_clk_init(void) +{ + int i; + uint32_t val; + + /* Disable all the child clocks of USB_HS_SRC. This needs to be done + * before the register init loop since it changes the source of the + * USB HS core clocks. */ + for (i = 0; chld_usb_src[i] != C(NONE); i++) + _soc_clk_disable(chld_usb_src[i]); + + soc_clk_set_rate(C(USB_HS_SRC), clk_tbl_usb[0].freq_hz); + + for (i = 0; i < ARRAY_SIZE(ri_list); i++) { + val = readl(ri_list[i].reg); + val &= ~ri_list[i].mask; + val |= ri_list[i].val; + writel(val, ri_list[i].reg); + } + + /* This is just to update the driver data structures. The actual + * register set up is taken care of in the register init loop. */ + set_1rate(I2C); + set_1rate(I2C_2); + set_1rate(QUP_I2C); + set_1rate(UART1); + set_1rate(UART3); + + return 0; +} + +arch_initcall(soc_clk_init); +#endif diff --git a/arch/arm/mach-msm/clock-7x30.h b/arch/arm/mach-msm/clock-7x30.h new file mode 100644 index 000000000000..56741b4ff64a --- /dev/null +++ b/arch/arm/mach-msm/clock-7x30.h @@ -0,0 +1,136 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef __ARCH_ARM_MACH_MSM_CLOCK_7X30_H +#define __ARCH_ARM_MACH_MSM_CLOCK_7X30_H + +enum { + L_7X30_NONE_CLK = -1, + L_7X30_ADM_CLK, + L_7X30_I2C_CLK, + L_7X30_I2C_2_CLK, + L_7X30_QUP_I2C_CLK, + L_7X30_UART1DM_CLK, + L_7X30_UART1DM_P_CLK, + L_7X30_UART2DM_CLK, + L_7X30_UART2DM_P_CLK, + L_7X30_EMDH_CLK, + L_7X30_EMDH_P_CLK, + L_7X30_PMDH_CLK, + L_7X30_PMDH_P_CLK, + L_7X30_GRP_2D_CLK, + L_7X30_GRP_2D_P_CLK, + L_7X30_GRP_3D_SRC_CLK, + L_7X30_GRP_3D_CLK, + L_7X30_GRP_3D_P_CLK, + L_7X30_IMEM_CLK, + L_7X30_SDC1_CLK, + L_7X30_SDC1_H_CLK, + L_7X30_SDC2_CLK, + L_7X30_SDC2_H_CLK, + L_7X30_SDC3_CLK, + L_7X30_SDC3_H_CLK, + L_7X30_SDC4_CLK, + L_7X30_SDC4_H_CLK, + L_7X30_MDP_CLK, + L_7X30_MDP_P_CLK, + L_7X30_MDP_LCDC_P_CLK, + L_7X30_MDP_LCDC_PAD_P_CLK, + L_7X30_MDP_VSYNC_CLK, + L_7X30_MI2S_CODEC_RX_M_CLK, + L_7X30_MI2S_CODEC_RX_S_CLK, + L_7X30_MI2S_CODEC_TX_M_CLK, + L_7X30_MI2S_CODEC_TX_S_CLK, + L_7X30_MI2S_M_CLK, + L_7X30_MI2S_S_CLK, + L_7X30_LPA_CODEC_CLK, + L_7X30_LPA_CORE_CLK, + L_7X30_LPA_P_CLK, + L_7X30_MIDI_CLK, + L_7X30_MDC_CLK, + L_7X30_SDAC_M_CLK, + L_7X30_SDAC_S_CLK, + L_7X30_UART1_CLK, + L_7X30_UART3_CLK, + L_7X30_TV_CLK, + L_7X30_TV_DAC_CLK, + L_7X30_TV_ENC_CLK, + L_7X30_TSIF_REF_CLK, + L_7X30_TSIF_P_CLK, + L_7X30_USB_HS_SRC_CLK, + L_7X30_USB_HS_CLK, + L_7X30_USB_HS_CORE_CLK, + L_7X30_USB_HS_P_CLK, + L_7X30_USB_HS2_CLK, + L_7X30_USB_HS2_CORE_CLK, + L_7X30_USB_HS2_P_CLK, + L_7X30_USB_HS3_CLK, + L_7X30_USB_HS3_CORE_CLK, + L_7X30_USB_HS3_P_CLK, + L_7X30_VFE_CLK, + L_7X30_VFE_P_CLK, + L_7X30_VFE_MDC_CLK, + L_7X30_VFE_CAMIF_CLK, + L_7X30_CAMIF_PAD_P_CLK, + L_7X30_CAM_CLK, + L_7X30_JPEG_CLK, + L_7X30_JPEG_P_CLK, + L_7X30_VPE_CLK, + L_7X30_MFC_CLK, + L_7X30_MFC_P_CLK, + L_7X30_SPI_CLK, + L_7X30_SPI_P_CLK, + + L_7X30_AXI_LI_VG_CLK, + L_7X30_AXI_LI_GRP_CLK, + L_7X30_AXI_LI_JPEG_CLK, + L_7X30_AXI_GRP_2D_CLK, + L_7X30_AXI_MFC_CLK, + L_7X30_AXI_VPE_CLK, + L_7X30_AXI_LI_VFE_CLK, + L_7X30_AXI_LI_APPS_CLK, + L_7X30_AXI_MDP_CLK, + L_7X30_AXI_IMEM_CLK, + + L_7X30_NR_CLKS +}; + +struct clk_ops; +extern struct clk_ops clk_ops_7x30; + +#define CLK_7X30(clk_name, clk_id, clk_dev, clk_flags) { \ + .name = clk_name, \ + .id = L_7X30_##clk_id, \ + .ops = &clk_ops_7x30, \ + .flags = clk_flags, \ + .dev = clk_dev, \ + .dbg_name = #clk_id, \ + } + +#endif + diff --git a/arch/arm/mach-msm/clock.h b/arch/arm/mach-msm/clock.h index 623dbdfd1e74..c1292841bbc4 100644 --- a/arch/arm/mach-msm/clock.h +++ b/arch/arm/mach-msm/clock.h @@ -20,6 +20,7 @@ #include #include "clock-pcom.h" +#include "clock-7x30.h" #define CLKFLAG_INVERT 0x00000001 #define CLKFLAG_NOINVERT 0x00000002 -- cgit v1.2.3 From 7076fff52e8f44fec2a56e699ff297739ba596a0 Mon Sep 17 00:00:00 2001 From: Michael Bohan Date: Mon, 17 Aug 2009 18:55:51 -0700 Subject: msm: socinfo: Add support for msm7x30 Without this change, flash booted msm7x30 SURFs will dereference bad memory. ID 59 is for MSM7630. ID 60 is for MSM7230. Signed-off-by: Michael Bohan --- arch/arm/mach-msm/socinfo.c | 12 +++++++----- arch/arm/mach-msm/socinfo.h | 9 +++++++++ 2 files changed, 16 insertions(+), 5 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c index 978f7af6d60c..2dbd6f6fb5f1 100644 --- a/arch/arm/mach-msm/socinfo.c +++ b/arch/arm/mach-msm/socinfo.c @@ -86,9 +86,6 @@ static union { } *socinfo; static enum msm_cpu cpu_of_id[] = { - /* Uninitialized IDs are not known to run Linux. - * MSM_CPU_UNKNOWN is set to 0 to ensure these IDs are - * considered as unknown CPUs. */ /* 7x01 IDs */ [1] = MSM_CPU_7X01, @@ -124,8 +121,13 @@ static enum msm_cpu cpu_of_id[] = { [37] = MSM_CPU_8X50, [38] = MSM_CPU_8X50, - /* Last known ID. */ - [53] = MSM_CPU_UNKNOWN, + /* 7x30 IDs */ + [59] = MSM_CPU_7X30, + [60] = MSM_CPU_7X30, + + /* Uninitialized IDs are not known to run Linux. + MSM_CPU_UNKNOWN is set to 0 to ensure these IDs are + considered as unknown CPU. Any ID > 60 is invalid. */ }; static enum msm_cpu cur_cpu; diff --git a/arch/arm/mach-msm/socinfo.h b/arch/arm/mach-msm/socinfo.h index 523b4ac01373..66b36e8243a4 100644 --- a/arch/arm/mach-msm/socinfo.h +++ b/arch/arm/mach-msm/socinfo.h @@ -44,6 +44,7 @@ enum msm_cpu { MSM_CPU_7X25, MSM_CPU_7X27, MSM_CPU_8X50, + MSM_CPU_7X30, }; enum msm_cpu socinfo_get_msm_cpu(void); @@ -84,4 +85,12 @@ static inline int cpu_is_qsd8x50(void) return cpu == MSM_CPU_8X50; } +static inline int cpu_is_msm7x30(void) +{ + enum msm_cpu cpu = socinfo_get_msm_cpu(); + + BUG_ON(cpu == MSM_CPU_UNKNOWN); + return cpu == MSM_CPU_7X30; +} + #endif -- cgit v1.2.3 From 8dfbcfc955cdd206b59eff21609e3f64b437b381 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 20 Aug 2009 15:15:32 +0300 Subject: msm: smc91x: off-by-one in memory resource In memory resource, .end should be last used byte, i.e. .start + size - 1 Signed-off-by: Vladimir Kondratiev --- arch/arm/mach-msm/board-halibut.c | 4 ++-- arch/arm/mach-msm/board-msm7x27.c | 4 ++-- arch/arm/mach-msm/board-msm7x30.c | 2 +- arch/arm/mach-msm/board-qsd8x50.c | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/board-halibut.c b/arch/arm/mach-msm/board-halibut.c index 93f658088f66..c91d22fb1940 100644 --- a/arch/arm/mach-msm/board-halibut.c +++ b/arch/arm/mach-msm/board-halibut.c @@ -70,7 +70,7 @@ static struct resource smc91x_resources[] = { [0] = { .start = 0x9C004300, - .end = 0x9C004400, + .end = 0x9C0043ff, .flags = IORESOURCE_MEM, }, [1] = { @@ -666,7 +666,7 @@ static void __init halibut_init(void) if (machine_is_msm7201a_ffa()) { smc91x_resources[0].start = 0x98000300; - smc91x_resources[0].end = 0x98000400; + smc91x_resources[0].end = 0x980003ff; smc91x_resources[1].start = MSM_GPIO_TO_INT(85); smc91x_resources[1].end = MSM_GPIO_TO_INT(85); } diff --git a/arch/arm/mach-msm/board-msm7x27.c b/arch/arm/mach-msm/board-msm7x27.c index c24f36f617fc..ea7c81fd360e 100644 --- a/arch/arm/mach-msm/board-msm7x27.c +++ b/arch/arm/mach-msm/board-msm7x27.c @@ -63,7 +63,7 @@ static struct resource smc91x_resources[] = { [0] = { .start = 0x9C004300, - .end = 0x9C004400, + .end = 0x9C0043ff, .flags = IORESOURCE_MEM, }, [1] = { @@ -1065,7 +1065,7 @@ static void __init msm7x27_init(void) #endif if (machine_is_msm7x27_ffa()) { smc91x_resources[0].start = 0x98000300; - smc91x_resources[0].end = 0x98000400; + smc91x_resources[0].end = 0x980003ff; smc91x_resources[1].start = MSM_GPIO_TO_INT(85); smc91x_resources[1].end = MSM_GPIO_TO_INT(85); if (gpio_tlmm_config(GPIO_CFG(85, 0, diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c index 88fe3238f46d..c76426620122 100644 --- a/arch/arm/mach-msm/board-msm7x30.c +++ b/arch/arm/mach-msm/board-msm7x30.c @@ -78,7 +78,7 @@ static struct resource smc91x_resources[] = { [0] = { .start = 0x8A000300, - .end = 0x8A000400, + .end = 0x8A0003ff, .flags = IORESOURCE_MEM, }, [1] = { diff --git a/arch/arm/mach-msm/board-qsd8x50.c b/arch/arm/mach-msm/board-qsd8x50.c index 51defb5e2808..e677d0cdb33d 100644 --- a/arch/arm/mach-msm/board-qsd8x50.c +++ b/arch/arm/mach-msm/board-qsd8x50.c @@ -1277,12 +1277,12 @@ static void __init qsd8x50_cfg_smc91x(void) if (machine_is_qsd8x50_surf()) { smc91x_resources[0].start = 0x70000300; - smc91x_resources[0].end = 0x70000400; + smc91x_resources[0].end = 0x700003ff; smc91x_resources[1].start = MSM_GPIO_TO_INT(156); smc91x_resources[1].end = MSM_GPIO_TO_INT(156); } else if (machine_is_qsd8x50_ffa()) { smc91x_resources[0].start = 0x84000300; - smc91x_resources[0].end = 0x84000400; + smc91x_resources[0].end = 0x840003ff; smc91x_resources[1].start = MSM_GPIO_TO_INT(87); smc91x_resources[1].end = MSM_GPIO_TO_INT(87); -- cgit v1.2.3 From e49197c93d7ea3cfff1ca728bca00a5b71127fa0 Mon Sep 17 00:00:00 2001 From: Saravana Kannan Date: Fri, 21 Aug 2009 19:08:58 -0700 Subject: msm: clock: Updated supported clock list for 7x30. Add MFC, LPA, SPI and GRP 2D clocks. Signed-off-by: Saravana Kannan --- arch/arm/mach-msm/devices.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/devices.c b/arch/arm/mach-msm/devices.c index 5b89f3180479..3a9a5e0f037b 100644 --- a/arch/arm/mach-msm/devices.c +++ b/arch/arm/mach-msm/devices.c @@ -566,6 +566,7 @@ struct clk msm_clocks_7x30[] = { CLK_PCOM("sdc_clk", SDC4_CLK, &msm_device_sdc4.dev, OFF), CLK_PCOM("sdc_pclk", SDC4_PCLK, &msm_device_sdc4.dev, OFF), CLK_PCOM("spi_clk", SPI_CLK, NULL, 0), + CLK_PCOM("spi_pclk", SPI_PCLK, NULL, 0), CLK_PCOM("uart_clk", UART1_CLK, &msm_device_uart1.dev, OFF), CLK_PCOM("uart_clk", UART2_CLK, &msm_device_uart2.dev, 0), CLK_PCOM("uart_clk", UART3_CLK, &msm_device_uart3.dev, OFF), @@ -585,6 +586,14 @@ struct clk msm_clocks_7x30[] = { CLK_PCOM("vfe_clk", VFE_CLK, NULL, OFF), CLK_PCOM("vfe_mdc_clk", VFE_MDC_CLK, NULL, OFF), CLK_PCOM("grp_pclk", GRP_PCLK, NULL, 0), + CLK_PCOM("lpa_codec_clk", LPA_CODEC_CLK, NULL, 0), + CLK_PCOM("lpa_core_clk", LPA_CORE_CLK, NULL, 0), + CLK_PCOM("lpa_pclk", LPA_PCLK, NULL, 0), + CLK_PCOM("mfc_clk", MFC_CLK, NULL, 0), + CLK_PCOM("mfc_div2_clk", MFC_DIV2_CLK, NULL, 0), + CLK_PCOM("mfc_pclk", MFC_PCLK, NULL, 0), + CLK_PCOM("grp_2d_clk", GRP_2D_CLK, NULL, 0), + CLK_PCOM("grp_2d_pclk", GRP_2D_PCLK, NULL, 0), }; unsigned msm_num_clocks_7x30 = ARRAY_SIZE(msm_clocks_7x30); -- cgit v1.2.3 From fd738803ca9cb8357e87e46be1464b24b737f5f1 Mon Sep 17 00:00:00 2001 From: Saravana Kannan Date: Tue, 25 Aug 2009 16:18:22 -0700 Subject: msm: acpuclock-8x50: Avoid configuring PLL divider mux when not using it. Configuring the PLL divider mux unnecessarily could result in running off of wrong PLLs for a very short duration. Doing so will cause a crash if that PLL is not on. One example case is when switching from running off of modem PLL to run off of the AXI clock source. Signed-off-by: Saravana Kannan --- arch/arm/mach-msm/acpuclock-8x50.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/acpuclock-8x50.c b/arch/arm/mach-msm/acpuclock-8x50.c index b91c0fc7c12f..d8c0f4c3a337 100644 --- a/arch/arm/mach-msm/acpuclock-8x50.c +++ b/arch/arm/mach-msm/acpuclock-8x50.c @@ -325,7 +325,8 @@ static void config_pll(struct clkctl_acpu_speed *s) if (s->pll == ACPU_PLL_3) scpll_set_freq(s->sc_l_value, HOP_SWITCH); - else { + /* Configure the PLL divider mux if we plan to use it. */ + else if (s->sc_core_src_sel_mask == 0) { /* get the current clock source selection */ regval = readl(SPSS_CLK_SEL_ADDR) & 0x1; -- cgit v1.2.3 From 4881e89b9db2032b53b408c39548bb1a3b7ecbf4 Mon Sep 17 00:00:00 2001 From: Matt Wagantall Date: Mon, 24 Aug 2009 16:50:24 -0700 Subject: msm: clock-7x30: Handle AXI_LI_ADSP_A clock dependencies. The AXI_LI_ADSP_A clock feeds the AXI arbiter that arbitrates between the USB and MDH h/w blocks. When any one of those h/w block are active, the arbiter clock needs to be turned on to allow the use of the AXI bus. Also, enable the UMDX_P_CLK clock during initialization. Signed-off-by: Matt Wagantall --- arch/arm/mach-msm/clock-7x30.c | 16 +++++++++------- arch/arm/mach-msm/clock-7x30.h | 1 + 2 files changed, 10 insertions(+), 7 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/clock-7x30.c b/arch/arm/mach-msm/clock-7x30.c index 70a824ba4489..d814eef70053 100644 --- a/arch/arm/mach-msm/clock-7x30.c +++ b/arch/arm/mach-msm/clock-7x30.c @@ -430,10 +430,9 @@ static struct clk_local clk_local_tbl[] = { CLK_1RATE(UART1, 0x00E0, B(5), B(4), clk_tbl_tcxo), CLK_1RATE(UART3, 0x0468, B(5), B(4), clk_tbl_tcxo), - CLK_BASIC(EMDH, 0x0050, 0, B(11), clk_tbl_mdh, NONE), - CLK_BASIC(PMDH, 0x008C, 0, B(11), clk_tbl_mdh, NONE), - CLK_BASIC(MDP, 0x014C, B(9), B(11), clk_tbl_mdp_core, - AXI_MDP), + CLK_BASIC(EMDH, 0x0050, 0, B(11), clk_tbl_mdh, AXI_LI_ADSP_A), + CLK_BASIC(PMDH, 0x008C, 0, B(11), clk_tbl_mdh, AXI_LI_ADSP_A), + CLK_BASIC(MDP, 0x014C, B(9), B(11), clk_tbl_mdp_core, AXI_MDP), CLK_MND8_P(VPE, 0x015C, 22, 15, B(9), B(11), clk_tbl_vpe, AXI_VPE, NULL), @@ -447,8 +446,8 @@ static struct clk_local clk_local_tbl[] = { CLK_MND8(SDC4, 0x00BC, 20, 13, B(9), B(11), clk_tbl_sdc2_4, NULL), CLK_MND8(SPI, 0x02C8, 19, 12, B(9), B(11), clk_tbl_spi, NULL), CLK_MND8(MIDI, 0x02D0, 19, 12, B(9), B(11), clk_tbl_midi, NULL), - CLK_MND8(USB_HS_SRC, USBH_NS, 23, 16, 0, B(11), clk_tbl_usb, - chld_usb_src), + CLK_MND8_P(USB_HS_SRC, USBH_NS, 23, 16, 0, B(11), clk_tbl_usb, + AXI_LI_ADSP_A, chld_usb_src), CLK_SLAVE(USB_HS, USBH_NS, B(9), USB_HS_SRC), CLK_SLAVE(USB_HS_CORE, USBH_NS, B(13), USB_HS_SRC), CLK_SLAVE(USB_HS2, USBH2_NS, B(9), USB_HS_SRC), @@ -508,6 +507,7 @@ static struct clk_local clk_local_tbl[] = { CLK_GLBL(GRP_2D_P, GLBL_CLK_ENA_SC, B(24)), CLK_GLBL(GRP_3D_P, GLBL_CLK_ENA_2_SC, B(17)), CLK_GLBL(JPEG_P, GLBL_CLK_ENA_2_SC, B(24)), + CLK_GLBL(LPA_P, GLBL_CLK_ENA_2_SC, B(7)), CLK_GLBL(MDP_P, GLBL_CLK_ENA_2_SC, B(6)), CLK_GLBL(MFC_P, GLBL_CLK_ENA_2_SC, B(26)), CLK_GLBL(PMDH_P, GLBL_CLK_ENA_2_SC, B(4)), @@ -523,10 +523,10 @@ static struct clk_local clk_local_tbl[] = { CLK_GLBL(USB_HS3_P, GLBL_CLK_ENA_2_SC, B(9)), CLK_GLBL(USB_HS_P, GLBL_CLK_ENA_SC, B(25)), CLK_GLBL(VFE_P, GLBL_CLK_ENA_2_SC, B(27)), - CLK_GLBL(LPA_P, GLBL_CLK_ENA_2_SC, B(7)), /* AXI bridge clocks. */ CLK_BRIDGE(AXI_LI_APPS, GLBL_CLK_ENA_SC, B(2), NONE), + CLK_BRIDGE(AXI_LI_ADSP_A, GLBL_CLK_ENA_2_SC, B(14), AXI_LI_APPS), CLK_BRIDGE(AXI_LI_JPEG, GLBL_CLK_ENA_2_SC, B(19), AXI_LI_APPS), CLK_BRIDGE(AXI_LI_VFE, GLBL_CLK_ENA_SC, B(23), AXI_LI_APPS), CLK_BRIDGE(AXI_MDP, GLBL_CLK_ENA_2_SC, B(29), AXI_LI_APPS), @@ -875,6 +875,8 @@ static struct reg_init { /* TODO: Remove next line from commercial code. */ {REG(PLL_ENA_REG), 0x7F, 0x7F}, /* Turn on all PLLs. */ + /* Enable UMDX_P clock. Known to causes issues, so never turn off. */ + {REG(GLBL_CLK_ENA_2_SC), B(2), B(2)}, {REG(0x0050), 0x3 << 17, 0x3}, /* EMDH RX div = div-4. */ {REG(0x008C), 0x3 << 17, 0x3}, /* PMDH RX div = div-4. */ /* MI2S_CODEC_RX_S src = MI2S_CODEC_RX_M. */ diff --git a/arch/arm/mach-msm/clock-7x30.h b/arch/arm/mach-msm/clock-7x30.h index 56741b4ff64a..8aa92f2e0d1a 100644 --- a/arch/arm/mach-msm/clock-7x30.h +++ b/arch/arm/mach-msm/clock-7x30.h @@ -116,6 +116,7 @@ enum { L_7X30_AXI_LI_APPS_CLK, L_7X30_AXI_MDP_CLK, L_7X30_AXI_IMEM_CLK, + L_7X30_AXI_LI_ADSP_A_CLK, L_7X30_NR_CLKS }; -- cgit v1.2.3 From 48777b445da4cb2ab19aa889df4c3d27511154d3 Mon Sep 17 00:00:00 2001 From: "Vishwanathapura, Niranjana" Date: Thu, 27 Aug 2009 13:50:23 -0600 Subject: msm: allow smd_ctl_read to attempt reading more than maximum packet size remove checking 'count' value in smd_ctl_read. user trying to read more than maximum packet size is valid. Signed-off-by: Niranjana Vishwanathapura --- arch/arm/mach-msm/smd_ctl2.c | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/smd_ctl2.c b/arch/arm/mach-msm/smd_ctl2.c index 0b9668068256..8348f94dae68 100644 --- a/arch/arm/mach-msm/smd_ctl2.c +++ b/arch/arm/mach-msm/smd_ctl2.c @@ -214,17 +214,6 @@ ssize_t smd_ctl_read(struct file *file, D(KERN_ERR "%s: read %i bytes\n", __func__, count); - if (count > MAX_BUF_SIZE) { - printk(KERN_ERR "ERROR:%s:%i:%s: " - "count = %i > MAX_BUF_SIZE = %i\n", - __FILE__, - __LINE__, - __func__, - count, - MAX_BUF_SIZE); - return -EINVAL; - } - smd_ctl_devp = file->private_data; if (!smd_ctl_devp->ctl_ch) -- cgit v1.2.3 From 996e2d2333ab5182e5bb71ba16b72996e6b1fe5e Mon Sep 17 00:00:00 2001 From: "Vishwanathapura, Niranjana" Date: Thu, 27 Aug 2009 13:59:01 -0600 Subject: msm: set low_latency flag for DATA1 smd port tty interface smd7 which is tty interface for smd DATA1 port can be used in place of smd0 interface. Increase the throughput effeciency of smd7 interface by setting low_latency flag similar to smd0 interface. Signed-off-by: Niranjana Vishwanathapura --- arch/arm/mach-msm/smd_tty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/smd_tty.c b/arch/arm/mach-msm/smd_tty.c index ff938c5f7606..e39b0487c319 100644 --- a/arch/arm/mach-msm/smd_tty.c +++ b/arch/arm/mach-msm/smd_tty.c @@ -136,7 +136,7 @@ static int smd_tty_open(struct tty_struct *tty, struct file *f) smsm_change_state(SMSM_APPS_STATE, 0, SMSM_SMD_LOOPBACK); msleep(100); - } else if (n == 0) + } else if ((n == 0) || (n == 7)) tty->low_latency = 1; res = smd_open(name, &info->ch, info, -- cgit v1.2.3 From f1c234f68af5abb184eb5ad32a178438a343202c Mon Sep 17 00:00:00 2001 From: "Zeng, Helen" Date: Thu, 27 Aug 2009 13:09:57 -0700 Subject: Use msm_rpc_connect_compatible API in pmic function Replace msm_rpc_connect with msm_rpc_connect_compatible in pmic_rpc_req_reply function. Change-Id: I396953d289ba50d5e2eb46c91a7bc7fa0a5e837e Signed-off-by: Zeng, Helen --- arch/arm/mach-msm/pmic.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/pmic.c b/arch/arm/mach-msm/pmic.c index a9eeb02b7003..3c481a6bc180 100644 --- a/arch/arm/mach-msm/pmic.c +++ b/arch/arm/mach-msm/pmic.c @@ -327,22 +327,18 @@ static int pmic_rpc_req_reply(struct pmic_buf *tbuf, struct pmic_buf *rbuf, int ans, len; - if (pm->endpoint == NULL) { - pm->endpoint = msm_rpc_connect(PMIC_RPC_PROG, - PMIC_RPC_VER_1_1, 0); - if (pm->endpoint == NULL) { - pm->endpoint = msm_rpc_connect(PMIC_RPC_PROG, - PMIC_RPC_VER_2_1, 0); + if ((pm->endpoint == NULL) || IS_ERR(pm->endpoint)) { + pm->endpoint = msm_rpc_connect_compatible(PMIC_RPC_PROG, + PMIC_RPC_VER_2_1, 0); + if (IS_ERR(pm->endpoint)) { + pm->endpoint = msm_rpc_connect_compatible(PMIC_RPC_PROG, + PMIC_RPC_VER_1_1, 0); } - if (pm->endpoint == NULL) - return -ENODEV; - if (IS_ERR(pm->endpoint)) { ans = PTR_ERR(pm->endpoint); printk(KERN_ERR "%s: init rpc failed! ans = %d\n", __func__, ans); - pm->endpoint = NULL; return ans; } } -- cgit v1.2.3 From 503cb3448ebbbcc35990a92c69b50f500c344936 Mon Sep 17 00:00:00 2001 From: Ai Li Date: Mon, 31 Aug 2009 10:03:27 -0600 Subject: msm: pm: correct CLK_SLEEP_EN bit value for 7x27 If bit 4 of CLK_SLEEP_EN is set before entering SWFI, the GP_Timer occasionally misses expiration and not fires the timer interrupt. Change code to make sure bit 4 is not set before SWFI. Signed-off-by: Ai Li --- arch/arm/mach-msm/pm2.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/pm2.c b/arch/arm/mach-msm/pm2.c index 9db8d17eb75e..c5c6bfef8e89 100644 --- a/arch/arm/mach-msm/pm2.c +++ b/arch/arm/mach-msm/pm2.c @@ -372,6 +372,7 @@ static void msm_pm_config_hw_before_power_down(void) static void msm_pm_config_hw_after_power_up(void) { writel(0, APPS_PWRDOWN); + writel(0, APPS_CLK_SLEEP_EN); } /* @@ -379,7 +380,11 @@ static void msm_pm_config_hw_after_power_up(void) */ static void msm_pm_config_hw_before_swfi(void) { +#ifdef CONFIG_ARCH_MSM_SCORPION writel(0x1f, APPS_CLK_SLEEP_EN); +#else + writel(0x0f, APPS_CLK_SLEEP_EN); +#endif } /* -- cgit v1.2.3 From daf490e0754f43801f61420326677f8ac5c4097a Mon Sep 17 00:00:00 2001 From: Ai Li Date: Mon, 31 Aug 2009 10:09:23 -0600 Subject: msm: pm: fix residency math to match expiration time unit Timer expiration is in units of nanoseconds. residency is in units of microseconds. Fix the math so the units match. Signed-off-by: Ai Li --- arch/arm/mach-msm/pm2.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/pm2.c b/arch/arm/mach-msm/pm2.c index c5c6bfef8e89..67f6546d9d69 100644 --- a/arch/arm/mach-msm/pm2.c +++ b/arch/arm/mach-msm/pm2.c @@ -1316,7 +1316,7 @@ void arch_idle(void) struct msm_pm_platform_data *mode = &msm_pm_modes[i]; if (!mode->supported || !mode->idle_enabled || mode->latency >= latency_qos || - mode->residency >= timer_expiration) + mode->residency * 1000ULL >= timer_expiration) allow[i] = false; } @@ -1332,8 +1332,8 @@ void arch_idle(void) #endif MSM_PM_DPRINTK(MSM_PM_DEBUG_IDLE, KERN_INFO, - "%s(): next timer %lld, sleep limit %u\n", - __func__, timer_expiration, sleep_limit); + "%s(): latency qos %d, next timer %lld, sleep limit %u\n", + __func__, latency_qos, timer_expiration, sleep_limit); for (i = 0; i < ARRAY_SIZE(allow); i++) MSM_PM_DPRINTK(MSM_PM_DEBUG_IDLE, KERN_INFO, -- cgit v1.2.3 From 8343276bb0e654467929bd6a61652b6b1a585bb2 Mon Sep 17 00:00:00 2001 From: Ai Li Date: Mon, 31 Aug 2009 10:12:38 -0600 Subject: msm: pm: update shared memory bits Update the shared memory bits to be in sync with newer modem values. Signed-off-by: Ai Li --- arch/arm/mach-msm/pm2.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/pm2.c b/arch/arm/mach-msm/pm2.c index 67f6546d9d69..ff096495397a 100644 --- a/arch/arm/mach-msm/pm2.c +++ b/arch/arm/mach-msm/pm2.c @@ -810,7 +810,7 @@ write_proc_failed: * Shared Memory Bits *****************************************************************************/ -#define DEM_MASTER_BITS_PER_CPU 5 +#define DEM_MASTER_BITS_PER_CPU 6 /* Power Master State Bits - Per CPU */ #define DEM_MASTER_SMSM_RUN \ @@ -823,6 +823,8 @@ write_proc_failed: (0x08UL << (DEM_MASTER_BITS_PER_CPU * SMSM_APPS_STATE)) #define DEM_MASTER_SMSM_READY \ (0x10UL << (DEM_MASTER_BITS_PER_CPU * SMSM_APPS_STATE)) +#define DEM_MASTER_SMSM_SLEEP \ + (0x20UL << (DEM_MASTER_BITS_PER_CPU * SMSM_APPS_STATE)) /* Power Slave State Bits */ #define DEM_SLAVE_SMSM_RUN (0x0001) @@ -1449,6 +1451,9 @@ static int msm_pm_enter(suspend_state_t state) sleep_limit = SLEEP_LIMIT_NO_TCXO_SHUTDOWN; #endif + MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND, KERN_INFO, + "%s(): sleep limit %u\n", __func__, sleep_limit); + for (i = 0; i < ARRAY_SIZE(allow); i++) allow[i] = true; @@ -1533,6 +1538,9 @@ static int msm_pm_enter(suspend_state_t state) msm_pm_swfi(false); } + MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND, KERN_INFO, + "%s(): return %d\n", __func__, ret); + return ret; } -- cgit v1.2.3 From 399a0551b622fa2f4efce6b6d6c747b787bec772 Mon Sep 17 00:00:00 2001 From: "Vishwanathapura, Niranjana" Date: Thu, 27 Aug 2009 16:24:57 -0600 Subject: msm: provide interface to set/clear smsm_intr_mask APPS processor can specifify which smsm interrupts it wants to receive by setting/clearing smsm_intr_mask table entry for a particular smsm_entry and APPS host. Provide interface from smd driver to get and set/clear these fields. Provide following interfaces. int smsm_change_intr_mask(uint32_t smsm_entry, uint32_t clear_mask, uint32_t set_mask); where 'set_mask' and 'clear_mask' are set and clear masks and the status whether set/clear is successful. int smsm_get_intr_mask(uint32_t smsm_entry, uint32_t *intr_mask); where required 'smsm_entry' value for APPS host is returned in '*intr_mask' and status of read is returned. Also correct initializing the smsm_intr_mask table. Initialize SMSM_APPS host field for all smsm entries instead of initializing only apps owned entries. Signed-off-by: Niranjana Vishwanathapura --- arch/arm/mach-msm/smd.c | 65 +++++++++++++++++++++++++++++++++++------ arch/arm/mach-msm/smd_private.h | 3 ++ 2 files changed, 59 insertions(+), 9 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c index 512c9591b4e8..0d22f9192c79 100644 --- a/arch/arm/mach-msm/smd.c +++ b/arch/arm/mach-msm/smd.c @@ -1123,7 +1123,7 @@ void *smem_find(unsigned id, unsigned size_in) static int smem_init(void) { struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE; - uint32_t *smsm; + uint32_t *smsm, i; smsm = smem_alloc(ID_SHARED_STATE, SMSM_NUM_ENTRIES * sizeof(uint32_t)); @@ -1137,14 +1137,9 @@ static int smem_init(void) smsm = smem_alloc(SMEM_SMSM_CPU_INTR_MASK, SMSM_NUM_ENTRIES * SMSM_NUM_HOSTS * sizeof(uint32_t)); - if (smsm) { - smsm[SMSM_APPS_STATE * SMSM_NUM_HOSTS + SMSM_MODEM] = - 0xffffffff; - smsm[SMSM_APPS_DEM_I * SMSM_NUM_HOSTS + SMSM_MODEM] = - 0xffffffff; - smsm[SMSM_APPS_STATE * SMSM_NUM_HOSTS + SMSM_Q6_I] = 0xffffffff; - smsm[SMSM_APPS_DEM_I * SMSM_NUM_HOSTS + SMSM_Q6_I] = 0xffffffff; - } + if (smsm) + for (i = 0; i < SMSM_NUM_ENTRIES; i++) + smsm[i * SMSM_NUM_HOSTS + SMSM_APPS] = 0xffffffff; return 0; } @@ -1277,6 +1272,58 @@ int smsm_change_state(uint32_t smsm_entry, return 0; } +int smsm_change_intr_mask(uint32_t smsm_entry, + uint32_t clear_mask, uint32_t set_mask) +{ + uint32_t *smsm; + + if (smsm_entry >= SMSM_NUM_ENTRIES) { + printk(KERN_ERR "smsm_change_state: Invalid entry %d\n", + smsm_entry); + return -EINVAL; + } + + smsm = smem_alloc(SMEM_SMSM_CPU_INTR_MASK, + SMSM_NUM_ENTRIES * SMSM_NUM_HOSTS * sizeof(uint32_t)); + + if (smsm) { + smsm[smsm_entry * SMSM_NUM_HOSTS + SMSM_APPS] = + (smsm[smsm_entry * SMSM_NUM_HOSTS + SMSM_APPS] & + ~clear_mask) | set_mask; + SMSM_INFO("smsm_entry %d, new intr_mask %x\n", smsm_entry, + smsm[smsm_entry * SMSM_NUM_HOSTS + SMSM_APPS]); + } else { + printk(KERN_ERR "smsm_change_intr_mask \n"); + return -EIO; + } + + return 0; +} + +int smsm_get_intr_mask(uint32_t smsm_entry, uint32_t *intr_mask) +{ + uint32_t *smsm; + + if ((smsm_entry >= SMSM_NUM_ENTRIES) || (!intr_mask)) { + printk(KERN_ERR "smsm_change_state: Invalid input " + "entry %d, mask 0x%x\n", + smsm_entry, (unsigned int)intr_mask); + return -EINVAL; + } + + smsm = smem_alloc(SMEM_SMSM_CPU_INTR_MASK, + SMSM_NUM_ENTRIES * SMSM_NUM_HOSTS * sizeof(uint32_t)); + + if (smsm) { + *intr_mask = smsm[smsm_entry * SMSM_NUM_HOSTS + SMSM_APPS]; + } else { + printk(KERN_ERR "smsm_change_intr_mask \n"); + return -EIO; + } + + return 0; +} + uint32_t smsm_get_state(uint32_t smsm_entry) { unsigned long flags; diff --git a/arch/arm/mach-msm/smd_private.h b/arch/arm/mach-msm/smd_private.h index ffac0ca964b0..3dec5d8ef794 100644 --- a/arch/arm/mach-msm/smd_private.h +++ b/arch/arm/mach-msm/smd_private.h @@ -153,6 +153,9 @@ void *smem_alloc(unsigned id, unsigned size); void *smem_get_entry(unsigned id, unsigned *size); int smsm_change_state(uint32_t smsm_entry, uint32_t clear_mask, uint32_t set_mask); +int smsm_change_intr_mask(uint32_t smsm_entry, + uint32_t clear_mask, uint32_t set_mask); +int smsm_get_intr_mask(uint32_t smsm_entry, uint32_t *intr_mask); uint32_t smsm_get_state(uint32_t smsm_entry); void smsm_print_sleep_info(uint32_t sleep_delay, uint32_t sleep_limit, uint32_t irq_mask, uint32_t wakeup_reason, uint32_t pending_irqs); -- cgit v1.2.3 From 89a8faae81c3c638b4465f5886ad74eae70e2255 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 15 Jul 2009 14:25:38 -0700 Subject: rpcrouter: cleanup printk messages Output before change: rpcrouter:Server create rejected, version = 0program (3000fe00) Output after change: rpcrouter: Server create rejected, version = 0, program = 3000fe00 Also modernize a bit with pr_err(). Acked-by: Stephen Boyd Signed-off-by: Michael Bohan --- arch/arm/mach-msm/smd_rpcrouter.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/smd_rpcrouter.c b/arch/arm/mach-msm/smd_rpcrouter.c index 2636f3b7b6dd..6aa43a7758d0 100644 --- a/arch/arm/mach-msm/smd_rpcrouter.c +++ b/arch/arm/mach-msm/smd_rpcrouter.c @@ -631,9 +631,9 @@ static int process_control_msg(union rr_control_msg *msg, int len) case RPCROUTER_CTRL_CMD_NEW_SERVER: if (msg->srv.vers == 0) { - printk(KERN_ERR - "rpcrouter:Server create rejected, version = 0" - "program (%08x)\n", msg->srv.prog); + pr_err( + "rpcrouter: Server create rejected, version = 0, " + "program = %08x\n", msg->srv.prog); break; } -- cgit v1.2.3 From d5bfd205e9c249a16830cf962735be6b03b873b4 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 14 Jul 2009 13:31:21 -0700 Subject: smem_log: add missing newline in printk, use __func__ output from dmesg <3>[ 0.361046] smem_log_init: no power log or log_idx allocated, smem_log disabled<6>smd_alloc_channel() 'DATA5_CNTL' cid=38 While we're here, use __func__ instead of hand writing the function name and modernize a bit with pr_err(). Acked-by: Stephen Boyd Signed-off-by: Michael Bohan --- arch/arm/mach-msm/smem_log.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/smem_log.c b/arch/arm/mach-msm/smem_log.c index def476ac5795..c2809109fc62 100644 --- a/arch/arm/mach-msm/smem_log.c +++ b/arch/arm/mach-msm/smem_log.c @@ -1126,8 +1126,8 @@ static int _smem_log_init(void) inst[GEN].idx = (uint32_t *)smem_alloc(SMEM_SMEM_LOG_IDX, sizeof(uint32_t)); if (!inst[GEN].events || !inst[GEN].idx) { - printk(KERN_ERR "smem_log_init: no log or log_idx allocated, " - "smem_log disabled"); + pr_err("%s: no log or log_idx allocated, " + "smem_log disabled\n", __func__); } inst[GEN].num = SMEM_LOG_NUM_ENTRIES; inst[GEN].remote_spinlock = &remote_spinlock; @@ -1140,8 +1140,8 @@ static int _smem_log_init(void) inst[STA].idx = (uint32_t *)smem_alloc(SMEM_SMEM_STATIC_LOG_IDX, sizeof(uint32_t)); if (!inst[STA].events || !inst[STA].idx) { - printk(KERN_ERR "smem_log_init: no static log or log_idx " - "allocated, smem_log disabled"); + pr_err("%s: no static log or log_idx " + "allocated, smem_log disabled\n", __func__); } inst[STA].num = SMEM_LOG_NUM_STATIC_ENTRIES; inst[STA].remote_spinlock = &remote_spinlock_static; @@ -1154,8 +1154,8 @@ static int _smem_log_init(void) inst[POW].idx = (uint32_t *)smem_alloc(SMEM_SMEM_LOG_POWER_IDX, sizeof(uint32_t)); if (!inst[POW].events || !inst[POW].idx) { - printk(KERN_ERR "smem_log_init: no power log or log_idx " - "allocated, smem_log disabled"); + pr_err("%s: no power log or log_idx " + "allocated, smem_log disabled\n", __func__); } inst[POW].num = SMEM_LOG_NUM_POWER_ENTRIES; inst[POW].remote_spinlock = &remote_spinlock; -- cgit v1.2.3 From 1ae3938c3cf80fa381ef709e81401f888e78e1d0 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 24 Jul 2009 15:29:04 -0700 Subject: msm: io: refactor msm_map_*_io() and compile out unused code add/remove: 1/6 grow/shrink: 0/1 up/down: 108/-928 (-820) Acked-by: Stephen Boyd Signed-off-by: Michael Bohan --- arch/arm/mach-msm/io.c | 100 ++++++++++++++++++++----------------------------- 1 file changed, 41 insertions(+), 59 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c index 7511d6f30e92..830eb43f5bc1 100644 --- a/arch/arm/mach-msm/io.c +++ b/arch/arm/mach-msm/io.c @@ -41,6 +41,19 @@ */ int msm_shared_ram_phys = 0x00100000; +static void msm_map_io(struct map_desc *io_desc, int size) +{ + int i; + + BUG_ON(!size); + for (i = 0; i < size; i++) + if (io_desc[i].virtual == (unsigned long)MSM_SHARED_RAM_BASE) + io_desc[i].pfn = __phys_to_pfn(msm_shared_ram_phys); + + iotable_init(io_desc, size); +} + +#if defined(CONFIG_ARCH_MSM7X01A) || defined(CONFIG_ARCH_MSM7X27) static struct map_desc msm_io_desc[] __initdata = { MSM_DEVICE(VIC), MSM_DEVICE(CSR), @@ -67,6 +80,18 @@ static struct map_desc msm_io_desc[] __initdata = { }, }; +void __init msm_map_common_io(void) +{ + /* Make sure the peripheral register window is closed, since + * we will use PTE flags (TEX[1]=1,B=0,C=1) to determine which + * pages are peripheral interface or not. + */ + asm("mcr p15, 0, %0, c15, c2, 4" : : "r" (0)); + msm_map_io(msm_io_desc, ARRAY_SIZE(msm_io_desc)); +} +#endif + +#ifdef CONFIG_ARCH_QSD8X50 static struct map_desc qsd8x50_io_desc[] __initdata = { MSM_DEVICE(VIC), MSM_DEVICE(CSR), @@ -89,6 +114,13 @@ static struct map_desc qsd8x50_io_desc[] __initdata = { }, }; +void __init msm_map_qsd8x50_io(void) +{ + msm_map_io(qsd8x50_io_desc, ARRAY_SIZE(qsd8x50_io_desc)); +} +#endif /* CONFIG_ARCH_QSD8X50 */ + +#ifdef CONFIG_ARCH_MSM7X30 static struct map_desc msm7x30_io_desc[] __initdata = { MSM_DEVICE(VIC), MSM_DEVICE(CSR), @@ -112,6 +144,13 @@ static struct map_desc msm7x30_io_desc[] __initdata = { }, }; +void __init msm_map_msm7x30_io(void) +{ + msm_map_io(msm7x30_io_desc, ARRAY_SIZE(msm7x30_io_desc)); +} +#endif /* CONFIG_ARCH_MSM7X30 */ + +#ifdef CONFIG_MACH_QSD8X50_COMET static struct map_desc comet_io_desc[] __initdata = { MSM_DEVICE(VIC), MSM_DEVICE(CSR), @@ -134,67 +173,11 @@ static struct map_desc comet_io_desc[] __initdata = { }, }; -void __init msm_map_common_io(void) -{ - int i; - - /* Make sure the peripheral register window is closed, since - * we will use PTE flags (TEX[1]=1,B=0,C=1) to determine which - * pages are peripheral interface or not. - */ - asm("mcr p15, 0, %0, c15, c2, 4" : : "r" (0)); - - BUG_ON(!ARRAY_SIZE(msm_io_desc)); - for (i = 0; i < ARRAY_SIZE(msm_io_desc); i++) - if (msm_io_desc[i].virtual == - (unsigned long)MSM_SHARED_RAM_BASE) - msm_io_desc[i].pfn = - __phys_to_pfn(msm_shared_ram_phys); - - iotable_init(msm_io_desc, ARRAY_SIZE(msm_io_desc)); -} - -void __init msm_map_qsd8x50_io(void) -{ - int i; - - BUG_ON(!ARRAY_SIZE(qsd8x50_io_desc)); - for (i = 0; i < ARRAY_SIZE(qsd8x50_io_desc); i++) - if (qsd8x50_io_desc[i].virtual == - (unsigned long)MSM_SHARED_RAM_BASE) - qsd8x50_io_desc[i].pfn = - __phys_to_pfn(msm_shared_ram_phys); - - iotable_init(qsd8x50_io_desc, ARRAY_SIZE(qsd8x50_io_desc)); -} - -void __init msm_map_msm7x30_io(void) -{ - int i; - - BUG_ON(!ARRAY_SIZE(msm7x30_io_desc)); - for (i = 0; i < ARRAY_SIZE(msm7x30_io_desc); i++) - if (msm7x30_io_desc[i].virtual == - (unsigned long)MSM_SHARED_RAM_BASE) - msm7x30_io_desc[i].pfn = - __phys_to_pfn(msm_shared_ram_phys); - - iotable_init(msm7x30_io_desc, ARRAY_SIZE(msm7x30_io_desc)); -} - void __init msm_map_comet_io(void) { - int i; - - BUG_ON(!ARRAY_SIZE(comet_io_desc)); - for (i = 0; i < ARRAY_SIZE(comet_io_desc); i++) - if (comet_io_desc[i].virtual == - (unsigned long)MSM_SHARED_RAM_BASE) - comet_io_desc[i].pfn = - __phys_to_pfn(msm_shared_ram_phys); - - iotable_init(comet_io_desc, ARRAY_SIZE(comet_io_desc)); + msm_map_io(comet_io_desc, ARRAY_SIZE(comet_io_desc)); } +#endif /* CONFIG_MACH_QSD8X50_COMET */ void __iomem * __msm_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype) @@ -210,5 +193,4 @@ __msm_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype) return __arm_ioremap(phys_addr, size, mtype); } - EXPORT_SYMBOL(__msm_ioremap); -- cgit v1.2.3 From 334e4d4872174d9484dbd99b4beeec15559d5d56 Mon Sep 17 00:00:00 2001 From: "Pfeffer, Zach" Date: Sat, 15 Aug 2009 22:27:19 -0700 Subject: msm: dma: disable dma clk when idle Add a timer to defer dma clk disable until idle to negate the immediate disable performance penalty. In addition add a suspend_late call to cancel the timer when suspending and execute dma clk disable if all channels are idle. CRs-fixed: 190215 Signed-off-by: Zach Pfeffer --- arch/arm/mach-msm/board-comet.c | 1 + arch/arm/mach-msm/board-halibut.c | 1 + arch/arm/mach-msm/board-msm7x27.c | 1 + arch/arm/mach-msm/board-msm7x30.c | 1 + arch/arm/mach-msm/board-qsd8x50.c | 1 + arch/arm/mach-msm/board-sapphire.c | 1 + arch/arm/mach-msm/board-trout.c | 1 + arch/arm/mach-msm/devices.c | 5 +++ arch/arm/mach-msm/devices.h | 1 + arch/arm/mach-msm/dma.c | 72 +++++++++++++++++++++++++++++++++++++- 10 files changed, 84 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/board-comet.c b/arch/arm/mach-msm/board-comet.c index 32e30bced856..c83e699b1c43 100644 --- a/arch/arm/mach-msm/board-comet.c +++ b/arch/arm/mach-msm/board-comet.c @@ -625,6 +625,7 @@ static void __init bt_power_init(void) static struct platform_device *devices[] __initdata = { &msm_fb_device, &msm_device_smd, + &msm_device_dmov, &smc911x_device, &android_pmem_device, &android_pmem_gpu0_device, diff --git a/arch/arm/mach-msm/board-halibut.c b/arch/arm/mach-msm/board-halibut.c index c91d22fb1940..5a6b2ca7159f 100644 --- a/arch/arm/mach-msm/board-halibut.c +++ b/arch/arm/mach-msm/board-halibut.c @@ -219,6 +219,7 @@ static struct platform_device *devices[] __initdata = { #endif &msm_device_uart_dm1, &msm_device_smd, + &msm_device_dmov, &msm_device_nand, &msm_device_i2c, &smc91x_device, diff --git a/arch/arm/mach-msm/board-msm7x27.c b/arch/arm/mach-msm/board-msm7x27.c index ea7c81fd360e..800513abaf8e 100644 --- a/arch/arm/mach-msm/board-msm7x27.c +++ b/arch/arm/mach-msm/board-msm7x27.c @@ -751,6 +751,7 @@ static struct platform_device *devices[] __initdata = { &msm_device_uart3, #endif &msm_device_smd, + &msm_device_dmov, &msm_device_nand, &msm_device_hsusb_otg, &msm_device_hsusb_host, diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c index c76426620122..4b024988a505 100644 --- a/arch/arm/mach-msm/board-msm7x30.c +++ b/arch/arm/mach-msm/board-msm7x30.c @@ -97,6 +97,7 @@ static struct platform_device smc91x_device = { static struct platform_device *devices[] __initdata = { &msm_device_smd, + &msm_device_dmov, &smc91x_device, &msm_device_nand, }; diff --git a/arch/arm/mach-msm/board-qsd8x50.c b/arch/arm/mach-msm/board-qsd8x50.c index e677d0cdb33d..85395db1fc2f 100644 --- a/arch/arm/mach-msm/board-qsd8x50.c +++ b/arch/arm/mach-msm/board-qsd8x50.c @@ -714,6 +714,7 @@ static struct platform_device *devices[] __initdata = { &mddi_toshiba_device, &smc91x_device, &msm_device_smd, + &msm_device_dmov, &android_pmem_device, &android_pmem_adsp_device, &android_pmem_gpu0_device, diff --git a/arch/arm/mach-msm/board-sapphire.c b/arch/arm/mach-msm/board-sapphire.c index a971a24d7e28..8de7a45ea649 100644 --- a/arch/arm/mach-msm/board-sapphire.c +++ b/arch/arm/mach-msm/board-sapphire.c @@ -785,6 +785,7 @@ static struct platform_device sapphire_snd = { static struct platform_device *devices[] __initdata = { &msm_device_smd, + &msm_device_dmov, &msm_device_nand, &msm_device_i2c, &msm_device_uart1, diff --git a/arch/arm/mach-msm/board-trout.c b/arch/arm/mach-msm/board-trout.c index ac3d43e4eaa4..637253ec3f78 100644 --- a/arch/arm/mach-msm/board-trout.c +++ b/arch/arm/mach-msm/board-trout.c @@ -634,6 +634,7 @@ static struct platform_device trout_snd = { static struct platform_device *devices[] __initdata = { &msm_device_smd, + &msm_device_dmov, &msm_device_nand, &msm_device_i2c, &msm_device_uart1, diff --git a/arch/arm/mach-msm/devices.c b/arch/arm/mach-msm/devices.c index 3a9a5e0f037b..ad39a350a320 100644 --- a/arch/arm/mach-msm/devices.c +++ b/arch/arm/mach-msm/devices.c @@ -199,6 +199,11 @@ struct platform_device msm_device_smd = { .id = -1, }; +struct platform_device msm_device_dmov = { + .name = "msm_dmov", + .id = -1, +}; + #if defined(CONFIG_ARCH_MSM_SCORPION) #define MSM_SDC1_BASE 0xA0300000 #define MSM_SDC2_BASE 0xA0400000 diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h index e8d3b8d6e96b..9dd8d9b698c8 100644 --- a/arch/arm/mach-msm/devices.h +++ b/arch/arm/mach-msm/devices.h @@ -35,6 +35,7 @@ extern struct platform_device msm_device_hsusb_host; extern struct platform_device msm_device_i2c; extern struct platform_device msm_device_smd; +extern struct platform_device msm_device_dmov; extern struct platform_device msm_device_nand; diff --git a/arch/arm/mach-msm/dma.c b/arch/arm/mach-msm/dma.c index 62b611db9d8d..c4c8502ec04d 100644 --- a/arch/arm/mach-msm/dma.c +++ b/arch/arm/mach-msm/dma.c @@ -14,11 +14,15 @@ * */ +#include +#include #include #include #include +#include #include +#define MODULE_NAME "msm_dmov" #define MSM_DMOV_CHANNEL_COUNT 16 enum { @@ -27,11 +31,19 @@ enum { MSM_DMOV_PRINT_FLOW = 4 }; +enum { + CLK_DIS, + CLK_TO_BE_DIS, + CLK_EN +}; + static DEFINE_SPINLOCK(msm_dmov_lock); +static struct clk *msm_dmov_clk; static unsigned int channel_active; static struct list_head ready_commands[MSM_DMOV_CHANNEL_COUNT]; static struct list_head active_commands[MSM_DMOV_CHANNEL_COUNT]; unsigned int msm_dmov_print_mask = MSM_DMOV_PRINT_ERRORS; +unsigned int clk_ctl = CLK_DIS; #define MSM_DMOV_DPRINTF(mask, format, args...) \ do { \ @@ -50,12 +62,32 @@ void msm_dmov_stop_cmd(unsigned id, struct msm_dmov_cmd *cmd, int graceful) writel((graceful << 31), DMOV_FLUSH0(id)); } +static void timer_func(unsigned long func_paramter) +{ + unsigned long irq_flags; + + spin_lock_irqsave(&msm_dmov_lock, irq_flags); + if (clk_ctl == CLK_TO_BE_DIS) { + BUG_ON(channel_active); + clk_disable(msm_dmov_clk); + clk_ctl = CLK_DIS; + } + spin_unlock_irqrestore(&msm_dmov_lock, irq_flags); +} +DEFINE_TIMER(timer, timer_func, 0, 0); + void msm_dmov_enqueue_cmd(unsigned id, struct msm_dmov_cmd *cmd) { unsigned long irq_flags; unsigned int status; spin_lock_irqsave(&msm_dmov_lock, irq_flags); + if (clk_ctl == CLK_DIS) + clk_enable(msm_dmov_clk); + else if (clk_ctl == CLK_TO_BE_DIS) + del_timer(&timer); + clk_ctl = CLK_EN; + status = readl(DMOV_STATUS(id)); if (list_empty(&ready_commands[id]) && (status & DMOV_STATUS_CMD_PTR_RDY)) { @@ -72,6 +104,10 @@ void msm_dmov_enqueue_cmd(unsigned id, struct msm_dmov_cmd *cmd) channel_active |= 1U << id; writel(cmd->cmdptr, DMOV_CMD_PTR(id)); } else { + if (!channel_active) { + clk_ctl = CLK_TO_BE_DIS; + mod_timer(&timer, jiffies + HZ); + } if (list_empty(&active_commands[id])) PRINT_ERROR("msm_dmov_enqueue_cmd(%d), error datamover stalled, status %x\n", id, status); @@ -222,26 +258,60 @@ static irqreturn_t msm_datamover_irq_handler(int irq, void *dev_id) PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", id, ch_status); } - if (!channel_active) + if (!channel_active) { disable_irq(INT_ADM_AARM); + clk_ctl = CLK_TO_BE_DIS; + mod_timer(&timer, jiffies + HZ); + } spin_unlock_irqrestore(&msm_dmov_lock, irq_flags); return IRQ_HANDLED; } +static int msm_dmov_suspend_late(struct platform_device *pdev, + pm_message_t state) +{ + unsigned long irq_flags; + + spin_lock_irqsave(&msm_dmov_lock, irq_flags); + if (clk_ctl == CLK_TO_BE_DIS) { + BUG_ON(channel_active); + del_timer(&timer); + clk_disable(msm_dmov_clk); + clk_ctl = CLK_DIS; + } + spin_unlock_irqrestore(&msm_dmov_lock, irq_flags); + return 0; +} + +static struct platform_driver msm_dmov_driver = { + .suspend_late = msm_dmov_suspend_late, + .driver = { + .name = MODULE_NAME, + .owner = THIS_MODULE, + }, +}; + static int __init msm_init_datamover(void) { int i; int ret; + for (i = 0; i < MSM_DMOV_CHANNEL_COUNT; i++) { INIT_LIST_HEAD(&ready_commands[i]); INIT_LIST_HEAD(&active_commands[i]); writel(DMOV_CONFIG_IRQ_EN | DMOV_CONFIG_FORCE_TOP_PTR_RSLT | DMOV_CONFIG_FORCE_FLUSH_RSLT, DMOV_CONFIG(i)); } + msm_dmov_clk = clk_get(NULL, "adm_clk"); + if (IS_ERR(msm_dmov_clk)) + return PTR_ERR(msm_dmov_clk); ret = request_irq(INT_ADM_AARM, msm_datamover_irq_handler, 0, "msmdatamover", NULL); if (ret) return ret; disable_irq(INT_ADM_AARM); + ret = platform_driver_register(&msm_dmov_driver); + if (ret) + return ret; return 0; } -- cgit v1.2.3 From a65ffc8c5038168f7fd3c6cc60cfaac2795faa03 Mon Sep 17 00:00:00 2001 From: "Vishwanathapura, Niranjana" Date: Tue, 1 Sep 2009 10:55:31 -0600 Subject: msm: Fix bug in ping modem client in callback reply Ping modem client while replying to register callback requests, is wrongly setting accept_status to RPC_ACCEPTSTAT_SYSTEM_ERR instead of RPC_ACCEPTSTAT_SUCCESS when user callback function returns success. Fix it to correctly set accpet status to RPC_ACCEPTSTAT_SUCCESS. Signed-off-by: Niranjana Vishwanathapura --- arch/arm/mach-msm/ping_mdm_rpc_client.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/ping_mdm_rpc_client.c b/arch/arm/mach-msm/ping_mdm_rpc_client.c index fd7727f547a9..b70527e4875d 100644 --- a/arch/arm/mach-msm/ping_mdm_rpc_client.c +++ b/arch/arm/mach-msm/ping_mdm_rpc_client.c @@ -184,9 +184,9 @@ static int ping_mdm_data_cb(struct msm_rpc_client *client, struct ping_mdm_register_data_cb_cb_ret *)) cb_func)(&arg, &ret); if (rc) - accept_status = RPC_ACCEPTSTAT_SUCCESS; - else accept_status = RPC_ACCEPTSTAT_SYSTEM_ERR; + else + accept_status = RPC_ACCEPTSTAT_SUCCESS; } else accept_status = RPC_ACCEPTSTAT_SYSTEM_ERR; -- cgit v1.2.3 From dfd04b3c6bb4ef7b91cda2dc23776d3a56af6ab6 Mon Sep 17 00:00:00 2001 From: Matt Wagantall Date: Thu, 13 Aug 2009 11:36:51 -0700 Subject: msm: remote-spinlock: Use SWP-based locking with ARM11 apps cores Use a remote spinlock mechanism based on the SWP instruction instead of one based on the local spinlock's LDREX/STREX implementation. This is required for MSM7XXX SoC's equipped with an ARM11 application processor. The memory controllers in these SoC's do not support tagging shared memory addresses for exclusive access and therefore LDREX and STREX cannot be used for locking between the modem and apps processors. For SoC's supporting exclusive tagging of shared memory, as well as for spinlocks local to the application processor, the LDREX/STREX implementation is preferable and therefore still used. Use of the WFE instruction avoids excessive polling of memory by putting the application processor in a wait state. The application processor, however, expects the remote processor to execute an SEV instruction to cause the application processor to come out of the wait state. The remote processors do not support the SEV instruction (older ARM architectures, etc.) and so using the WFE instruction can lead to the application processor waiting forever. Hence, the WFE instruction is removed in favor of continuously polling the remote spinlock's location in memory. CRs-fixed: 211016, 211034 Signed-off-by: Matt Wagantall --- arch/arm/mach-msm/include/mach/remote_spinlock.h | 75 +++++++++++++++++++++++- arch/arm/mach-msm/remote_spinlock.c | 26 -------- 2 files changed, 72 insertions(+), 29 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/include/mach/remote_spinlock.h b/arch/arm/mach-msm/include/mach/remote_spinlock.h index 17be4eeb5450..8d8a5ddb8a4e 100644 --- a/arch/arm/mach-msm/include/mach/remote_spinlock.h +++ b/arch/arm/mach-msm/include/mach/remote_spinlock.h @@ -26,6 +26,11 @@ * */ +/* + * Part of this this code is based on the standard ARM spinlock + * implementation (asm/spinlock.h) found in the 2.6.29 kernel. + */ + #ifndef __ASM__ARCH_QC_REMOTE_SPINLOCK_H #define __ASM__ARCH_QC_REMOTE_SPINLOCK_H @@ -39,8 +44,72 @@ typedef raw_remote_spinlock_t *_remote_spinlock_t; #define remote_spin_lock_id_t uint32_t +static inline void __raw_remote_ex_spin_lock(raw_remote_spinlock_t *lock) +{ + unsigned long tmp; + + __asm__ __volatile__( +"1: ldrex %0, [%1]\n" +" teq %0, #0\n" +" strexeq %0, %2, [%1]\n" +" teqeq %0, #0\n" +" bne 1b" + : "=&r" (tmp) + : "r" (&lock->lock), "r" (1) + : "cc"); + + smp_mb(); +} + +static inline void __raw_remote_ex_spin_unlock(raw_remote_spinlock_t *lock) +{ + smp_mb(); + + __asm__ __volatile__( +" str %1, [%0]\n" + : + : "r" (&lock->lock), "r" (0) + : "cc"); +} + +static inline void __raw_remote_swp_spin_lock(raw_remote_spinlock_t *lock) +{ + unsigned long tmp; + + __asm__ __volatile__( +"1: swp %0, %2, [%1]\n" +" teq %0, #0\n" +" bne 1b" + : "=&r" (tmp) + : "r" (&lock->lock), "r" (1) + : "cc"); + + smp_mb(); +} + +static inline void __raw_remote_swp_spin_unlock(raw_remote_spinlock_t *lock) +{ + smp_mb(); + + __asm__ __volatile__( +" str %1, [%0]" + : + : "r" (&lock->lock), "r" (0) + : "cc"); +} + + int _remote_spin_lock_init(remote_spin_lock_id_t id, _remote_spinlock_t *lock); -void _remote_spin_lock(_remote_spinlock_t *lock); -void _remote_spin_unlock(_remote_spinlock_t *lock); -#endif +/* Only use SWP-based spinlocks for ARM11 apps processors where the LDREX/STREX + * instructions are unable to lock shared memory for exclusive access. */ +#if defined(CONFIG_ARCH_MSM_ARM11) +#define _remote_spin_lock(lock) __raw_remote_swp_spin_lock(*lock) +#define _remote_spin_unlock(lock) __raw_remote_swp_spin_unlock(*lock) +#else +#define _remote_spin_lock(lock) __raw_remote_ex_spin_lock(*lock) +#define _remote_spin_unlock(lock) __raw_remote_ex_spin_unlock(*lock) +#endif /* CONFIG_ARCH_MSM_ARM11 */ + +#endif /* __ASM__ARCH_QC_REMOTE_SPINLOCK_H */ + diff --git a/arch/arm/mach-msm/remote_spinlock.c b/arch/arm/mach-msm/remote_spinlock.c index 7c3271bedd56..6e488865930e 100644 --- a/arch/arm/mach-msm/remote_spinlock.c +++ b/arch/arm/mach-msm/remote_spinlock.c @@ -60,16 +60,6 @@ #include -/* This is ugly but it has to be done. If linux/spinlock_types is included, - * then for a UP kernel, the spinlock will get stubbed out. Since this is a - * remote spin lock, stubbing out is not the right thing to do. - */ -#define __LINUX_SPINLOCK_TYPES_H -#include -#undef __LINUX_SPINLOCK_TYPES_H - -#include - #include #include "smd_private.h" @@ -80,13 +70,6 @@ int _remote_spin_lock_init(remote_spin_lock_id_t id, _remote_spinlock_t *lock) { _remote_spinlock_t spinlock_start; - /* The raw_spinlock_t structure should be the same as - * raw_remote_spinlock_t to be able to reuse the __raw_spin_lock() - * and __raw_spin_unlock() functions. If this condition is not met, - * then please write new code to replace calls to __raw_spin_lock() - * and __raw_spin_unlock(). */ - BUILD_BUG_ON(sizeof(raw_remote_spinlock_t) != sizeof(raw_spinlock_t)); - if (id >= SMEM_SPINLOCK_COUNT) return -EINVAL; @@ -100,12 +83,3 @@ int _remote_spin_lock_init(remote_spin_lock_id_t id, _remote_spinlock_t *lock) return 0; } -void _remote_spin_lock(_remote_spinlock_t *lock) -{ - __raw_spin_lock((raw_spinlock_t *) (*lock)); -} - -void _remote_spin_unlock(_remote_spinlock_t *lock) -{ - __raw_spin_unlock((raw_spinlock_t *) (*lock)); -} -- cgit v1.2.3 From 501a85e883b5d009075b7d9b0e3038f9d0ab9c32 Mon Sep 17 00:00:00 2001 From: Matt Wagantall Date: Fri, 28 Aug 2009 16:00:41 -0700 Subject: msm: clock: Correct MI2S clock divider for 7x30 The value written to the MI2S clock divider register is corrected so that it accomplishes the divide-by-4 specified in the frequency plan. Signed-off-by: Matt Wagantall --- arch/arm/mach-msm/clock-7x30.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/clock-7x30.c b/arch/arm/mach-msm/clock-7x30.c index d814eef70053..e420b4a913ee 100644 --- a/arch/arm/mach-msm/clock-7x30.c +++ b/arch/arm/mach-msm/clock-7x30.c @@ -887,7 +887,7 @@ static struct reg_init { {REG(LPA_NS), B(4), B(4)}, /* LPA CORE src = LPA_CODEC. */ {REG(0x02EC), 0xF, 0xD}, /* MI2S_CODEC_RX_S div = div-8. */ {REG(0x02F0), 0xF, 0xD}, /* MI2S_CODEC_TX_S div = div-8. */ - {REG(0x02E4), 0xF, 0x4}, /* MI2S_S div = div-4. */ + {REG(0x02E4), 0xF, 0x3}, /* MI2S_S div = div-4. */ {REG(MDC_NS), 0x3, 0x3}, /* MDC src = external MDH src. */ {REG(SDAC_NS), 0x3 << 14, 0x0}, /* SDAC div = div-1. */ /* Disable sources TCXO/5 & TCXO/6. UART1 src = TCXO*/ -- cgit v1.2.3 From 4fd16690d2459a95fada6061d9c4b7c42bc4649e Mon Sep 17 00:00:00 2001 From: Matt Wagantall Date: Tue, 1 Sep 2009 17:30:30 -0700 Subject: msm: clock: Add SoC/board independent APIs to set/get max AXI frequency. Some drivers need to set the AXI frequency to the maximum frequency supported by the board. Add a MSM_AXI_MAX_FREQ_KHZ magic value that allows them to achieve that in a SoC/board independent manner. Signed-off-by: Matt Wagantall --- arch/arm/mach-msm/acpuclock-8x50.c | 6 ++++++ arch/arm/mach-msm/acpuclock.c | 12 ++++++++++-- arch/arm/mach-msm/board-halibut.c | 3 +++ arch/arm/mach-msm/board-msm7x27.c | 1 + arch/arm/mach-msm/clock.c | 3 ++- arch/arm/mach-msm/clock.h | 1 + arch/arm/mach-msm/include/mach/clk.h | 6 ++++++ 7 files changed, 29 insertions(+), 3 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/acpuclock-8x50.c b/arch/arm/mach-msm/acpuclock-8x50.c index d8c0f4c3a337..a923c288b36c 100644 --- a/arch/arm/mach-msm/acpuclock-8x50.c +++ b/arch/arm/mach-msm/acpuclock-8x50.c @@ -173,6 +173,12 @@ struct clock_state { static struct clock_state drv_state = { 0 }; +unsigned long clk_get_max_axi_khz(void) +{ + return 128000; +} +EXPORT_SYMBOL(clk_get_max_axi_khz); + static void scpll_set_freq(uint32_t lval, unsigned freq_switch) { uint32_t regval; diff --git a/arch/arm/mach-msm/acpuclock.c b/arch/arm/mach-msm/acpuclock.c index 05b5ab1a87ff..f46f8df25b7c 100644 --- a/arch/arm/mach-msm/acpuclock.c +++ b/arch/arm/mach-msm/acpuclock.c @@ -51,7 +51,7 @@ struct clock_state uint32_t vdd_switch_time_us; unsigned long power_collapse_khz; unsigned long wait_for_irq_khz; - unsigned int max_axi_khz; + unsigned long max_axi_khz; }; #define PLL_BASE 7 @@ -282,6 +282,12 @@ static void __init cpufreq_table_init(void) } #endif +unsigned long clk_get_max_axi_khz(void) +{ + return drv_state.max_axi_khz; +} +EXPORT_SYMBOL(clk_get_max_axi_khz); + static int pc_pll_request(unsigned id, unsigned on) { int res = 0; @@ -705,13 +711,15 @@ static void __init acpu_freq_tbl_fixup(void) t->axiclk_khz = 200000; } + t--; + drv_state.max_axi_khz = t->axiclk_khz; + /* The default 7x27 ACPU clock plan supports running the AXI bus at * 200 MHz. So we don't classify it as Turbo mode. */ if (cpu_is_msm7x27()) return; - t--; if (!axi_160mhz) pr_info("Turbo mode not supported.\n"); else if (t->axiclk_khz == 160000) diff --git a/arch/arm/mach-msm/board-halibut.c b/arch/arm/mach-msm/board-halibut.c index 5a6b2ca7159f..537516723f16 100644 --- a/arch/arm/mach-msm/board-halibut.c +++ b/arch/arm/mach-msm/board-halibut.c @@ -50,6 +50,7 @@ #include "devices.h" #include "socinfo.h" +#include "clock.h" #include "msm-keypad-devices.h" #include "pm.h" @@ -678,6 +679,8 @@ static void __init halibut_init(void) && SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 2) halibut_clock_data.max_axi_khz = 160000; + msm_acpu_clock_init(&halibut_clock_data); + #if defined(CONFIG_MSM_SERIAL_DEBUGGER) msm_serial_debug_init(MSM_UART3_PHYS, INT_UART3, &msm_device_uart3.dev, 1); diff --git a/arch/arm/mach-msm/board-msm7x27.c b/arch/arm/mach-msm/board-msm7x27.c index 800513abaf8e..32cdf4cabc72 100644 --- a/arch/arm/mach-msm/board-msm7x27.c +++ b/arch/arm/mach-msm/board-msm7x27.c @@ -52,6 +52,7 @@ #include "devices.h" #include "socinfo.h" +#include "clock.h" #include "msm-keypad-devices.h" #include "pm.h" diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c index 1d3e27b538e7..7e1d2a95d527 100644 --- a/arch/arm/mach-msm/clock.c +++ b/arch/arm/mach-msm/clock.c @@ -174,7 +174,8 @@ int ebi1_clk_set_min_rate(enum clkvote_client client, unsigned long rate) spin_lock_irqsave(&ebi1_vote_lock, flags); - ebi1_min_rate[client] = rate; + ebi1_min_rate[client] = (rate == MSM_AXI_MAX_FREQ_KHZ) ? + clk_get_max_axi_khz() : rate; new_val = ebi1_min_rate[0]; for (i = 1; i < CLKVOTE_MAX; i++) diff --git a/arch/arm/mach-msm/clock.h b/arch/arm/mach-msm/clock.h index c1292841bbc4..99e1bac7bfc8 100644 --- a/arch/arm/mach-msm/clock.h +++ b/arch/arm/mach-msm/clock.h @@ -88,6 +88,7 @@ enum clkvote_client { int msm_clock_require_tcxo(unsigned long *reason, int nbits); int msm_clock_get_name(uint32_t id, char *name, uint32_t size); int ebi1_clk_set_min_rate(enum clkvote_client client, unsigned long rate); +unsigned long clk_get_max_axi_khz(void); #endif diff --git a/arch/arm/mach-msm/include/mach/clk.h b/arch/arm/mach-msm/include/mach/clk.h index 32e014ae764b..39cec947b365 100644 --- a/arch/arm/mach-msm/include/mach/clk.h +++ b/arch/arm/mach-msm/include/mach/clk.h @@ -28,6 +28,12 @@ #ifndef __MACH_CLK_H #define __MACH_CLK_H +/* Magic rate value for use with PM QOS to request the board's maximum + * supported AXI rate. This value is chosen to not collide with + * PM_QOS_DEFAULT_VALUE which may also be used to vote on the AXI rate. + */ +#define MSM_AXI_MAX_FREQ_KHZ -2 + struct clk; /* Rate is minimum clock rate in Hz */ -- cgit v1.2.3 From cd5aa1875dd330b0c10be5ac8ee1050786d9ba8f Mon Sep 17 00:00:00 2001 From: Willie Ruan Date: Thu, 3 Sep 2009 11:44:29 -0700 Subject: msm: vreg: fix a typo for lvsw1 Signed-off-by: Willie Ruan --- arch/arm/mach-msm/vreg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/vreg.c b/arch/arm/mach-msm/vreg.c index 53e9119ded4a..cb7a71b55f43 100644 --- a/arch/arm/mach-msm/vreg.c +++ b/arch/arm/mach-msm/vreg.c @@ -90,7 +90,7 @@ static struct vreg vregs[] = { VREG("wlan2", 45, 0, 0), VREG("xo_out", 46, 0, 0), VREG("lvsw0", 47, 0, 0), - VREG("lvsw0", 48, 0, 0), + VREG("lvsw1", 48, 0, 0), }; struct vreg *vreg_get(struct device *dev, const char *id) -- cgit v1.2.3 From 76e5eccd54db0d5a8a00f03b64fcb85ded5c405a Mon Sep 17 00:00:00 2001 From: "Vishwanathapura, Niranjana" Date: Thu, 3 Sep 2009 14:49:14 -0600 Subject: msm: Change some SMD info messages to dbg messages to reduce logging Change some SMD info messages which are of low importance to dbg messages. By default only info messages are turned on. Hence will reduced smd message logging. Signed-off-by: Niranjana Vishwanathapura --- arch/arm/mach-msm/smd.c | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c index 0d22f9192c79..0fb8c60a04ee 100644 --- a/arch/arm/mach-msm/smd.c +++ b/arch/arm/mach-msm/smd.c @@ -603,36 +603,36 @@ void smd_sleep_exit(void) list_for_each_entry(ch, &smd_ch_list, ch_list) { if (ch_is_open(ch)) { if (ch->recv->fHEAD) { - SMD_INFO("smd_sleep_exit ch %d fHEAD " - "%x %x %x\n", - ch->n, - ch->recv->fHEAD, - ch->recv->head, ch->recv->tail); + SMD_DBG("smd_sleep_exit ch %d fHEAD " + "%x %x %x\n", + ch->n, + ch->recv->fHEAD, + ch->recv->head, ch->recv->tail); need_int = 1; break; } if (ch->recv->fTAIL) { - SMD_INFO("smd_sleep_exit ch %d fTAIL " - "%x %x %x\n", - ch->n, - ch->recv->fTAIL, - ch->send->head, ch->send->tail); + SMD_DBG("smd_sleep_exit ch %d fTAIL " + "%x %x %x\n", + ch->n, + ch->recv->fTAIL, + ch->send->head, ch->send->tail); need_int = 1; break; } if (ch->recv->fSTATE) { - SMD_INFO("smd_sleep_exit ch %d fSTATE %x" - "\n", ch->n, - ch->recv->fSTATE); + SMD_DBG("smd_sleep_exit ch %d fSTATE %x" + "\n", ch->n, + ch->recv->fSTATE); need_int = 1; break; } tmp = ch->recv->state; if (tmp != ch->last_state) { - SMD_INFO("smd_sleep_exit ch %d " - "state %x != %x\n", - ch->n, tmp, - ch->last_state); + SMD_DBG("smd_sleep_exit ch %d " + "state %x != %x\n", + ch->n, tmp, + ch->last_state); need_int = 1; break; } @@ -641,7 +641,7 @@ void smd_sleep_exit(void) spin_unlock_irqrestore(&smd_lock, flags); do_smd_probe(); if (need_int) { - SMD_INFO("smd_sleep_exit need interrupt\n"); + SMD_DBG("smd_sleep_exit need interrupt\n"); tasklet_schedule(&smd_fake_irq_tasklet); } } @@ -1199,7 +1199,7 @@ static irqreturn_t smsm_irq_handler(int irq, void *data) old_apps = apps = smsm[SMSM_APPS_STATE]; - SMSM_INFO("\n", apps, modm); + SMSM_DBG("\n", apps, modm); if (apps & SMSM_RESET) { /* If we get an interrupt and the apps SMSM_RESET bit is already set, the modem is acking the @@ -1228,7 +1228,7 @@ static irqreturn_t smsm_irq_handler(int irq, void *data) } if (smsm[SMSM_APPS_STATE] != apps) { - SMSM_INFO("\n", apps); + SMSM_DBG("\n", apps); smsm[SMSM_APPS_STATE] = apps; do_smd_probe(); notify_other_smsm(SMSM_APPS_STATE, old_apps, apps); @@ -1259,7 +1259,7 @@ int smsm_change_state(uint32_t smsm_entry, if (smsm) { old_state = smsm[smsm_entry]; smsm[smsm_entry] = (smsm[smsm_entry] & ~clear_mask) | set_mask; - SMSM_INFO("smsm_change_state %x\n", smsm[smsm_entry]); + SMSM_DBG("smsm_change_state %x\n", smsm[smsm_entry]); notify_other_smsm(SMSM_APPS_STATE, old_state, smsm[smsm_entry]); } -- cgit v1.2.3 From 02450b1517322b2ad4f7d1813c7a3c872ebb91c9 Mon Sep 17 00:00:00 2001 From: "Vishwanathapura, Niranjana" Date: Thu, 3 Sep 2009 15:12:33 -0600 Subject: msm: Check for correct RPC version and program in callback request Check for correct RPC version and program in callback request. This check is done if callback is processed in a separate thread. Add the check when callback is processed in client's read thread. Signed-off-by: Niranjana Vishwanathapura --- arch/arm/mach-msm/smd_rpcrouter_clients.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/smd_rpcrouter_clients.c b/arch/arm/mach-msm/smd_rpcrouter_clients.c index d7399261aceb..5baf79a7ae4b 100644 --- a/arch/arm/mach-msm/smd_rpcrouter_clients.c +++ b/arch/arm/mach-msm/smd_rpcrouter_clients.c @@ -129,6 +129,7 @@ static int rpc_clients_thread(void *data) struct msm_rpc_client *client; int rc = 0; struct msm_rpc_client_cb_item *cb_item; + struct rpc_request_hdr *req; client = data; for (;;) { @@ -152,7 +153,12 @@ static int rpc_clients_thread(void *data) } if (client->cb_thread == NULL) { - client->cb_func(client, buffer, rc); + req = (struct rpc_request_hdr *)buffer; + + if ((be32_to_cpu(req->rpc_vers) == 2) && + (be32_to_cpu(req->prog) == + (client->prog | 0x01000000))) + client->cb_func(client, buffer, rc); kfree(buffer); } else { INIT_LIST_HEAD(&cb_item->list); -- cgit v1.2.3 From 4a8ed59ebf0a82008ca25e0d5417e6b5c0731274 Mon Sep 17 00:00:00 2001 From: "Ruigrok, Richard" Date: Thu, 3 Sep 2009 17:16:21 -0600 Subject: msm: rpc: Add support for PING control message. Modem processor may send a PING control message if the application processor does not respond for more than 20ms to a flow control request. Support for this feature only requires that we receive the message. Signed-off-by: Richard Ruigrok --- arch/arm/mach-msm/smd_rpcrouter.c | 4 ++++ arch/arm/mach-msm/smd_rpcrouter.h | 1 + 2 files changed, 5 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/smd_rpcrouter.c b/arch/arm/mach-msm/smd_rpcrouter.c index 6aa43a7758d0..c0530243a4d5 100644 --- a/arch/arm/mach-msm/smd_rpcrouter.c +++ b/arch/arm/mach-msm/smd_rpcrouter.c @@ -704,6 +704,10 @@ static int process_control_msg(union rr_control_msg *msg, int len) printk(KERN_ERR "rpcrouter: LOCAL NOTIFICATION NOT IMP\n"); rc = -ENOSYS; + break; + case RPCROUTER_CTRL_CMD_PING: + /* No action needed for ping messages received */ + RR("o PING\n"); break; default: RR("o UNKNOWN(%08x)\n", msg->cmd); diff --git a/arch/arm/mach-msm/smd_rpcrouter.h b/arch/arm/mach-msm/smd_rpcrouter.h index 419befe151be..6872f5441472 100644 --- a/arch/arm/mach-msm/smd_rpcrouter.h +++ b/arch/arm/mach-msm/smd_rpcrouter.h @@ -48,6 +48,7 @@ #define RPCROUTER_CTRL_CMD_REMOVE_CLIENT 6 #define RPCROUTER_CTRL_CMD_RESUME_TX 7 #define RPCROUTER_CTRL_CMD_EXIT 8 +#define RPCROUTER_CTRL_CMD_PING 9 #define RPCROUTER_DEFAULT_RX_QUOTA 5 -- cgit v1.2.3 From 0a63a131615cd1af68ed2cad7e11cf34fa2e736a Mon Sep 17 00:00:00 2001 From: "Ruigrok, Richard" Date: Tue, 8 Sep 2009 17:08:07 -0600 Subject: msm: proc_comm add commands for clkctl PCOM_CLKCTL_RPC_RAIL_ENABLE PCOM_CLKCTL_RPC_RAIL_DISABLE PCOM_CLKCTL_RPC_RAIL_CONTROL PCOM_CLKCTL_RPC_MIN_MSMC1 Signed-off-by: Richard Ruigrok --- arch/arm/mach-msm/proc_comm.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/proc_comm.h b/arch/arm/mach-msm/proc_comm.h index 4d236dcbea2e..c53e39e47dcd 100644 --- a/arch/arm/mach-msm/proc_comm.h +++ b/arch/arm/mach-msm/proc_comm.h @@ -131,6 +131,10 @@ enum { PCOM_CLKCTL_RPC_RESET_DEASSERT, PCOM_CLKCTL_RPC_RAIL_ON, PCOM_CLKCTL_RPC_RAIL_OFF, + PCOM_CLKCTL_RPC_RAIL_ENABLE, + PCOM_CLKCTL_RPC_RAIL_DISABLE, + PCOM_CLKCTL_RPC_RAIL_CONTROL, + PCOM_CLKCTL_RPC_MIN_MSMC1, PCOM_NUM_CMDS, }; -- cgit v1.2.3 From 91775413e29b113387e725d141535a675567cfe6 Mon Sep 17 00:00:00 2001 From: "Lai, Patrick" Date: Tue, 8 Sep 2009 17:39:00 -0700 Subject: msm: clock: Add MI2S codec clocks in 7x30 clock list Signed-off-by: Patrick Lai --- arch/arm/mach-msm/devices.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/devices.c b/arch/arm/mach-msm/devices.c index ad39a350a320..b7f7cbdb3a53 100644 --- a/arch/arm/mach-msm/devices.c +++ b/arch/arm/mach-msm/devices.c @@ -599,6 +599,10 @@ struct clk msm_clocks_7x30[] = { CLK_PCOM("mfc_pclk", MFC_PCLK, NULL, 0), CLK_PCOM("grp_2d_clk", GRP_2D_CLK, NULL, 0), CLK_PCOM("grp_2d_pclk", GRP_2D_PCLK, NULL, 0), + CLK_PCOM("mi2s_codec_rx_m_clk", MI2S_CODEC_RX_MCLK, NULL, 0), + CLK_PCOM("mi2s_codec_rx_s_clk", MI2S_CODEC_RX_SCLK, NULL, 0), + CLK_PCOM("mi2s_codec_tx_m_clk", MI2S_CODEC_TX_MCLK, NULL, 0), + CLK_PCOM("mi2s_codec_tx_s_clk", MI2S_CODEC_TX_SCLK, NULL, 0), }; unsigned msm_num_clocks_7x30 = ARRAY_SIZE(msm_clocks_7x30); -- cgit v1.2.3 From 4cde1f4b4b1fae3be033fd6761b87e0ec4e28686 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Thu, 16 Jul 2009 14:39:42 -0700 Subject: msm: allow users to disable smem logger add/remove: 0/38 grow/shrink: 0/8 up/down: 0/-17104 (-17104) This also slightly reduces kernel init time by removing smem_log_init(). Acked-by: Stephen Boyd Signed-off-by: Michael Bohan --- arch/arm/mach-msm/Kconfig | 10 ++++++++++ arch/arm/mach-msm/Makefile | 3 ++- arch/arm/mach-msm/include/mach/smem_log.h | 13 +++++++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index bdc666f8c3be..94ad498f69ce 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -412,6 +412,16 @@ config MSM_RESET_MODEM help Allows the user to reset the modem through a device node. +config MSM_SMD_LOGGING + depends on MSM_SMD + default y + bool "MSM Shared Memory Logger" + help + This option exposes the shared memory logger at /dev/smem_log + and a debugfs node named smem_log. + + If in doubt, say yes. + config MSM_ONCRPCROUTER depends on MSM_SMD default y diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 523db55ad00f..fa62a841a9c1 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -22,7 +22,8 @@ obj-$(CONFIG_MSM_JTAG_V7) += jtag-v7.o obj-$(CONFIG_ARCH_QSD8X50) += sirc.o obj-$(CONFIG_MSM_FIQ_SUPPORT) += fiq_glue.o obj-$(CONFIG_MACH_TROUT) += board-trout-rfkill.o -obj-$(CONFIG_MSM_SMD) += smd.o smd_tty.o smd_qmi.o smem_log.o +obj-$(CONFIG_MSM_SMD) += smd.o smd_tty.o smd_qmi.o +obj-$(CONFIG_MSM_SMD_LOGGING) += smem_log.o obj-$(CONFIG_MSM_SMD) += smd_ctl2.o smd_nmea.o obj-$(CONFIG_DEBUG_FS) += pmic_debugfs.o obj-$(CONFIG_MSM_RESET_MODEM) += reset_modem.o diff --git a/arch/arm/mach-msm/include/mach/smem_log.h b/arch/arm/mach-msm/include/mach/smem_log.h index 65a42a27f76f..bd94bacc4809 100644 --- a/arch/arm/mach-msm/include/mach/smem_log.h +++ b/arch/arm/mach-msm/include/mach/smem_log.h @@ -219,6 +219,7 @@ #define RPC_ROUTER_LOG_EVENT_MID_WRITTEN (SMEM_LOG_RPC_ROUTER_EVENT_BASE + 6) #define RPC_ROUTER_LOG_EVENT_MID_CFM_REQ (SMEM_LOG_RPC_ROUTER_EVENT_BASE + 7) +#ifdef CONFIG_MSM_SMD_LOGGING void smem_log_event(uint32_t id, uint32_t data1, uint32_t data2, uint32_t data3); void smem_log_event6(uint32_t id, uint32_t data1, uint32_t data2, @@ -229,4 +230,16 @@ void smem_log_event_to_static(uint32_t id, uint32_t data1, uint32_t data2, void smem_log_event6_to_static(uint32_t id, uint32_t data1, uint32_t data2, uint32_t data3, uint32_t data4, uint32_t data5, uint32_t data6); +#else +void smem_log_event(uint32_t id, uint32_t data1, uint32_t data2, + uint32_t data3) { } +void smem_log_event6(uint32_t id, uint32_t data1, uint32_t data2, + uint32_t data3, uint32_t data4, uint32_t data5, + uint32_t data6) { } +void smem_log_event_to_static(uint32_t id, uint32_t data1, uint32_t data2, + uint32_t data3) { } +void smem_log_event6_to_static(uint32_t id, uint32_t data1, uint32_t data2, + uint32_t data3, uint32_t data4, uint32_t data5, + uint32_t data6) { } +#endif -- cgit v1.2.3 From 498c93d21157dd15e746816fc44959446f96ad67 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 21 Jul 2009 15:31:21 -0700 Subject: msm: Add kconfig option to disable NMEA driver Acked-by: Stephen Boyd Signed-off-by: Michael Bohan --- arch/arm/mach-msm/Kconfig | 7 +++++++ arch/arm/mach-msm/Makefile | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index 94ad498f69ce..4268d6e4b000 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -422,6 +422,13 @@ config MSM_SMD_LOGGING If in doubt, say yes. +config MSM_SMD_NMEA + bool "NMEA GPS Driver" + depends on MSM_SMD + default y + help + Enable this to support the NMEA GPS device. + config MSM_ONCRPCROUTER depends on MSM_SMD default y diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index fa62a841a9c1..a9d1c74bdec8 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -24,7 +24,8 @@ obj-$(CONFIG_MSM_FIQ_SUPPORT) += fiq_glue.o obj-$(CONFIG_MACH_TROUT) += board-trout-rfkill.o obj-$(CONFIG_MSM_SMD) += smd.o smd_tty.o smd_qmi.o obj-$(CONFIG_MSM_SMD_LOGGING) += smem_log.o -obj-$(CONFIG_MSM_SMD) += smd_ctl2.o smd_nmea.o +obj-$(CONFIG_MSM_SMD) += smd_ctl2.o +obj-$(CONFIG_MSM_SMD_NMEA) += smd_nmea.o obj-$(CONFIG_DEBUG_FS) += pmic_debugfs.o obj-$(CONFIG_MSM_RESET_MODEM) += reset_modem.o obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter.o -- cgit v1.2.3 From 1085cca75bf829b667858e7691a2213f75dc18f7 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 22 Jul 2009 10:23:18 -0700 Subject: msm: smd: split into separately configurable pieces Some users don't want the whole SMD package, instead they want just the bare essentials. Add kconfig options to compile out pieces of the SMD driver. The new options cover: MSM_SMD_TTY, MSM_SMD_QMI, and MSM_SMD_CTL. Acked-by: Stephen Boyd Signed-off-by: Michael Bohan --- arch/arm/mach-msm/Kconfig | 29 +++++++++++++++++++++++++++++ arch/arm/mach-msm/Makefile | 6 ++++-- 2 files changed, 33 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index 4268d6e4b000..50e7c05bb3ad 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -429,6 +429,35 @@ config MSM_SMD_NMEA help Enable this to support the NMEA GPS device. + If in doubt, say yes. + +config MSM_SMD_TTY + bool "SMD TTY Driver" + depends on MSM_SMD + default y + help + Provides TTY interfaces to interact with the modem. + + If in doubt, say yes. + +config MSM_SMD_QMI + bool "SMD QMI Driver" + depends on MSM_SMD + default y + help + Manages network data connections. + + If in doubt, say yes. + +config MSM_SMD_CTL + bool "SMD Control Driver" + depends on MSM_SMD + default y + help + Provides a binary SMD non-muxed control port interface. + + If in doubt, say yes. + config MSM_ONCRPCROUTER depends on MSM_SMD default y diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index a9d1c74bdec8..8483d0881c29 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -22,9 +22,11 @@ obj-$(CONFIG_MSM_JTAG_V7) += jtag-v7.o obj-$(CONFIG_ARCH_QSD8X50) += sirc.o obj-$(CONFIG_MSM_FIQ_SUPPORT) += fiq_glue.o obj-$(CONFIG_MACH_TROUT) += board-trout-rfkill.o -obj-$(CONFIG_MSM_SMD) += smd.o smd_tty.o smd_qmi.o +obj-$(CONFIG_MSM_SMD) += smd.o obj-$(CONFIG_MSM_SMD_LOGGING) += smem_log.o -obj-$(CONFIG_MSM_SMD) += smd_ctl2.o +obj-$(CONFIG_MSM_SMD_TTY) += smd_tty.o +obj-$(CONFIG_MSM_SMD_QMI) += smd_qmi.o +obj-$(CONFIG_MSM_SMD_CTL) += smd_ctl2.o obj-$(CONFIG_MSM_SMD_NMEA) += smd_nmea.o obj-$(CONFIG_DEBUG_FS) += pmic_debugfs.o obj-$(CONFIG_MSM_RESET_MODEM) += reset_modem.o -- cgit v1.2.3 From 6a107d8d93b100919ecfb5d6908031a711162e2c Mon Sep 17 00:00:00 2001 From: Matt Wagantall Date: Fri, 11 Sep 2009 01:17:21 -0700 Subject: msm: clock: Fix AXI rate voting use of magic value PM QOS passes only s32 integer rates through to the clock driver. The MSM_AXI_MAX_FREQ magic value, which is used to vote for the maximum supported AXI bus rate, is changed to respect this restriction. The behavior and use of the magic value is also changed so that it represents the maximium AXI rate in the correct units, regardless of whether it's passed to ebi1_clk_set_min_rate() directly, or used with PM QOS. Signed-off-by: Matt Wagantall --- arch/arm/mach-msm/clock.c | 10 +++++++--- arch/arm/mach-msm/include/mach/clk.h | 6 +++--- 2 files changed, 10 insertions(+), 6 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c index 7e1d2a95d527..45e78d74ddb6 100644 --- a/arch/arm/mach-msm/clock.c +++ b/arch/arm/mach-msm/clock.c @@ -174,8 +174,8 @@ int ebi1_clk_set_min_rate(enum clkvote_client client, unsigned long rate) spin_lock_irqsave(&ebi1_vote_lock, flags); - ebi1_min_rate[client] = (rate == MSM_AXI_MAX_FREQ_KHZ) ? - clk_get_max_axi_khz() : rate; + ebi1_min_rate[client] = (rate == MSM_AXI_MAX_FREQ) ? + (clk_get_max_axi_khz() * 1000) : rate; new_val = ebi1_min_rate[0]; for (i = 1; i < CLKVOTE_MAX; i++) @@ -203,7 +203,11 @@ int ebi1_clk_set_min_rate(enum clkvote_client client, unsigned long rate) static int axi_freq_notifier_handler(struct notifier_block *block, unsigned long min_freq, void *v) { - return ebi1_clk_set_min_rate(CLKVOTE_PMQOS, min_freq * 1000); + /* convert min_freq from KHz to Hz, unless it's a magic value */ + if (min_freq != MSM_AXI_MAX_FREQ) + min_freq *= 1000; + + return ebi1_clk_set_min_rate(CLKVOTE_PMQOS, min_freq); } /* diff --git a/arch/arm/mach-msm/include/mach/clk.h b/arch/arm/mach-msm/include/mach/clk.h index 39cec947b365..53ec86e6bc58 100644 --- a/arch/arm/mach-msm/include/mach/clk.h +++ b/arch/arm/mach-msm/include/mach/clk.h @@ -29,10 +29,10 @@ #define __MACH_CLK_H /* Magic rate value for use with PM QOS to request the board's maximum - * supported AXI rate. This value is chosen to not collide with - * PM_QOS_DEFAULT_VALUE which may also be used to vote on the AXI rate. + * supported AXI rate. PM QOS will only pass positive s32 rate values + * through to the clock driver, so INT_MAX is used. */ -#define MSM_AXI_MAX_FREQ_KHZ -2 +#define MSM_AXI_MAX_FREQ LONG_MAX struct clk; -- cgit v1.2.3 From dcaf08857cb90deb2011bfd1740bb36bb91a9bd2 Mon Sep 17 00:00:00 2001 From: Anoop Krishnan Jayasankaran Date: Mon, 14 Sep 2009 11:57:55 -0700 Subject: msm: acpuclock: Reduce AXI freq to 61.44 MHz at ACPU freq of 245.76 MHz Reduce AXI freq to 61.44 MHz when ACPU runs at 245.76 MHz. This provides significant power savings during audio playback. Tests indicate that this change doesn't impact performance since the actions of other drivers end up increasing the AXI frequency when the display is on. Signed-off-by: Anoop Krishnan Jayasankaran --- arch/arm/mach-msm/acpuclock.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/acpuclock.c b/arch/arm/mach-msm/acpuclock.c index f46f8df25b7c..61984500f91f 100644 --- a/arch/arm/mach-msm/acpuclock.c +++ b/arch/arm/mach-msm/acpuclock.c @@ -168,7 +168,7 @@ static struct clkctl_acpu_speed pll0_245_pll1_960_pll2_1200[] = { { 0, 120000, ACPU_PLL_1, 1, 7, 60000, 1, 61440, 3 }, { 1, 122880, ACPU_PLL_0, 4, 1, 61440, 1, 61440, 3 }, { 0, 200000, ACPU_PLL_2, 2, 5, 66667, 2, 61440, 4 }, - { 1, 245760, ACPU_PLL_0, 4, 0, 122880, 1, 122880, 4 }, + { 1, 245760, ACPU_PLL_0, 4, 0, 122880, 1, 61440, 4 }, { 1, 320000, ACPU_PLL_1, 1, 2, 160000, 1, 122880, 5 }, { 0, 400000, ACPU_PLL_2, 2, 2, 133333, 2, 122880, 5 }, { 1, 480000, ACPU_PLL_1, 1, 1, 160000, 2, 122880, 6 }, @@ -196,7 +196,7 @@ static struct clkctl_acpu_speed pll0_960_pll1_245_pll2_1200[] = { { 0, 120000, ACPU_PLL_0, 4, 7, 60000, 1, 61440, 3 }, { 1, 122880, ACPU_PLL_1, 1, 1, 61440, 1, 61440, 3 }, { 0, 200000, ACPU_PLL_2, 2, 5, 66667, 2, 61440, 4 }, - { 1, 245760, ACPU_PLL_1, 1, 0, 122880, 1, 122880, 4 }, + { 1, 245760, ACPU_PLL_1, 1, 0, 122880, 1, 61440, 4 }, { 1, 320000, ACPU_PLL_0, 4, 2, 160000, 1, 122880, 5 }, { 0, 400000, ACPU_PLL_2, 2, 2, 133333, 2, 122880, 5 }, { 1, 480000, ACPU_PLL_0, 4, 1, 160000, 2, 122880, 6 }, -- cgit v1.2.3 From e43a8bfbc12fd08ea3ba75290a81b0b4b9ad54b0 Mon Sep 17 00:00:00 2001 From: Matt Wagantall Date: Tue, 1 Sep 2009 12:18:31 -0700 Subject: msm: acpuclock: Restore VDD when returning from power collapse Restore the apps processor's VDD level when coming out of power collapse, since the modem may have changed it after the apps processor went down. CRs-fixed: 193493 Signed-off-by: Matt Wagantall --- arch/arm/mach-msm/acpuclock.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/acpuclock.c b/arch/arm/mach-msm/acpuclock.c index 61984500f91f..6cbc2fcfaf0a 100644 --- a/arch/arm/mach-msm/acpuclock.c +++ b/arch/arm/mach-msm/acpuclock.c @@ -469,6 +469,11 @@ int acpuclk_set_rate(unsigned long rate, enum setrate_reason reason) } plls_enabled |= 1 << tgt_s->pll; } + } + /* Need to do this when coming out of power collapse since some modem + * firmwares reset the VDD when the application processor enters power + * collapse. */ + if (reason == SETRATE_CPUFREQ || reason == SETRATE_PC) { /* Increase VDD if needed. */ if (tgt_s->vdd > cur_s->vdd) { if ((rc = acpuclk_set_vdd_level(tgt_s->vdd)) < 0) { -- cgit v1.2.3 From c4990dc9f0185d87bf772e4dc973868f104e4633 Mon Sep 17 00:00:00 2001 From: "Vishwanathapura, Niranjana" Date: Sun, 23 Aug 2009 15:22:52 -0600 Subject: msm: Add more support in RPC server infrastucture Add machanism to send payload along with reply message. Add support for servers to do callback requests. 1)The below interface is to be used to initiate a reply message void *msm_rpc_server_start_accepted_reply(struct msm_rpc_server *server, uint32_t xid, uint32_t accept_status); where, 'server' is pointer to server data structure, 'xid' the xid; has to be same as in request message, 'accept_status' is acceptance status. it returns pointer to buffer where payload can be attached. 2)The below interface is to be used to send a reply message int msm_rpc_server_send_accepted_reply(struct msm_rpc_server *server, uint32_t size); where, 'server' is pointer to server data structure, 'size' is size of the payload attached. 3)The below interface to be used to do a callback request int msm_rpc_server_cb_req(struct msm_rpc_server *server, struct msm_rpc_client_info *clnt_info, uint32_t cb_proc, int (*arg_func)(struct msm_rpc_server *server, void *buf, void *data), void *arg_data, int (*ret_func)(struct msm_rpc_server *server, void *buf, void *data), void *ret_data, long timeout); where, 'server' is pointer to server data structure, 'clnt_info' is pointer to client information data structure. callback will be sent to this client. 'cb_proc' is the callback procedure number. 'arg_func' is argument function pointer. 'buf' is where arguments needs to be filled. 'data' is arg_data 'ret_func' is return function pointer. 'buf' is where returned data should be read from. 'data' is ret_data 'arg_data' is passed as an input parameter to argument function. 'ret_data' is passed as an input parameter to return function. 'timeout' is timeout for reply wait in jiffies. If -ve timeout is specified a default timeout of 10s is used. it returns 0 on success, otherwise an error code is returned. 4)The below interface to be used to get requesting client's information. This information is needed while doing callback requests. void msm_rpc_server_get_requesting_client( struct msm_rpc_client_info *clnt_info) where, 'clnt_info' is pointer to client information data structure. user of this call has to handle allocating and freeing memory for this data structure. Signed-off-by: Niranjana Vishwanathapura --- arch/arm/mach-msm/include/mach/msm_rpcrouter.h | 33 ++++ arch/arm/mach-msm/smd_rpcrouter.c | 26 +++ arch/arm/mach-msm/smd_rpcrouter.h | 5 + arch/arm/mach-msm/smd_rpcrouter_servers.c | 235 +++++++++++++++++++++++-- 4 files changed, 287 insertions(+), 12 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/include/mach/msm_rpcrouter.h b/arch/arm/mach-msm/include/mach/msm_rpcrouter.h index b50a074af64c..a1f357f574f6 100644 --- a/arch/arm/mach-msm/include/mach/msm_rpcrouter.h +++ b/arch/arm/mach-msm/include/mach/msm_rpcrouter.h @@ -169,6 +169,13 @@ struct msm_rpc_server uint32_t prog; uint32_t vers; + struct mutex cb_req_lock; + struct mutex reply_lock; + char *cb_req; + char *reply; + + struct msm_rpc_endpoint *cb_ept; + int (*rpc_call)(struct msm_rpc_server *server, struct rpc_request_hdr *req, unsigned len); }; @@ -215,6 +222,13 @@ struct msm_rpc_client { char *reply; }; +struct msm_rpc_client_info { + uint32_t pid; + uint32_t cid; + uint32_t prog; + uint32_t vers; +}; + struct msm_rpc_client *msm_rpc_register_client( const char *name, uint32_t prog, uint32_t ver, @@ -235,10 +249,29 @@ void *msm_rpc_start_accepted_reply(struct msm_rpc_client *client, int msm_rpc_send_accepted_reply(struct msm_rpc_client *client, uint32_t size); +void *msm_rpc_server_start_accepted_reply(struct msm_rpc_server *server, + uint32_t xid, uint32_t accept_status); + +int msm_rpc_server_send_accepted_reply(struct msm_rpc_server *server, + uint32_t size); + int msm_rpc_add_cb_func(struct msm_rpc_client *client, void *cb_func); void *msm_rpc_get_cb_func(struct msm_rpc_client *client, uint32_t cb_id); void msm_rpc_remove_cb_func(struct msm_rpc_client *client, void *cb_func); +int msm_rpc_server_cb_req(struct msm_rpc_server *server, + struct msm_rpc_client_info *clnt_info, + uint32_t cb_proc, + int (*arg_func)(struct msm_rpc_server *server, + void *buf, void *data), + void *arg_data, + int (*ret_func)(struct msm_rpc_server *server, + void *buf, void *data), + void *ret_data, long timeout); + +void msm_rpc_server_get_requesting_client( + struct msm_rpc_client_info *clnt_info); + #endif diff --git a/arch/arm/mach-msm/smd_rpcrouter.c b/arch/arm/mach-msm/smd_rpcrouter.c index c0530243a4d5..b3cee4078c3f 100644 --- a/arch/arm/mach-msm/smd_rpcrouter.c +++ b/arch/arm/mach-msm/smd_rpcrouter.c @@ -1219,6 +1219,30 @@ static struct msm_rpc_reply *get_pend_reply(struct msm_rpc_endpoint *ept, return NULL; } +void get_requesting_client(struct msm_rpc_endpoint *ept, uint32_t xid, + struct msm_rpc_client_info *clnt_info) +{ + unsigned long flags; + struct msm_rpc_reply *reply; + + if (!clnt_info) + return; + + spin_lock_irqsave(&ept->reply_q_lock, flags); + list_for_each_entry(reply, &ept->reply_pend_q, list) { + if (reply->xid == xid) { + clnt_info->pid = reply->pid; + clnt_info->cid = reply->cid; + clnt_info->prog = reply->prog; + clnt_info->vers = reply->vers; + spin_unlock_irqrestore(&ept->reply_q_lock, flags); + return; + } + } + spin_unlock_irqrestore(&ept->reply_q_lock, flags); + return; +} + static void set_avail_reply(struct msm_rpc_endpoint *ept, struct msm_rpc_reply *reply) { @@ -1581,6 +1605,8 @@ int __msm_rpc_read(struct msm_rpc_endpoint *ept, reply->cid = pkt->hdr.src_cid; reply->pid = pkt->hdr.src_pid; reply->xid = rq->xid; + reply->prog = rq->prog; + reply->vers = rq->vers; set_pend_reply(ept, reply); } diff --git a/arch/arm/mach-msm/smd_rpcrouter.h b/arch/arm/mach-msm/smd_rpcrouter.h index 6872f5441472..f8975336a359 100644 --- a/arch/arm/mach-msm/smd_rpcrouter.h +++ b/arch/arm/mach-msm/smd_rpcrouter.h @@ -142,6 +142,8 @@ struct msm_rpc_reply { struct list_head list; uint32_t pid; uint32_t cid; + uint32_t prog; /* be32 */ + uint32_t vers; /* be32 */ uint32_t xid; /* be32 */ }; @@ -202,6 +204,9 @@ int msm_rpcrouter_create_server_pdev(struct rr_server *server); int msm_rpcrouter_init_devices(void); void msm_rpcrouter_exit_devices(void); +void get_requesting_client(struct msm_rpc_endpoint *ept, uint32_t xid, + struct msm_rpc_client_info *clnt_info); + extern dev_t msm_rpcrouter_devno; extern struct class *msm_rpcrouter_class; #endif diff --git a/arch/arm/mach-msm/smd_rpcrouter_servers.c b/arch/arm/mach-msm/smd_rpcrouter_servers.c index 931c30118fb5..eb74f50c79b4 100644 --- a/arch/arm/mach-msm/smd_rpcrouter_servers.c +++ b/arch/arm/mach-msm/smd_rpcrouter_servers.c @@ -40,6 +40,7 @@ static struct msm_rpc_endpoint *endpoint; static LIST_HEAD(rpc_server_list); static DEFINE_MUTEX(rpc_server_list_lock); static int rpc_servers_active; +static uint32_t current_xid; static void rpc_server_register(struct msm_rpc_server *server) { @@ -85,6 +86,29 @@ int msm_rpc_create_server(struct msm_rpc_server *server) /* make sure we're in a sane state first */ server->flags = 0; INIT_LIST_HEAD(&server->list); + mutex_init(&server->cb_req_lock); + mutex_init(&server->reply_lock); + + server->reply = kmalloc(MSM_RPC_MSGSIZE_MAX, GFP_KERNEL); + if (!server->reply) + return -ENOMEM; + + server->cb_req = kmalloc(MSM_RPC_MSGSIZE_MAX, GFP_KERNEL); + if (!server->cb_req) { + kfree(server->reply); + return -ENOMEM; + } + + server->cb_ept = msm_rpc_open(); + if (IS_ERR(server->cb_ept)) { + kfree(server->reply); + kfree(server->cb_req); + return PTR_ERR(server->cb_ept); + } + + server->cb_ept->flags = MSM_RPC_UNINTERRUPTIBLE; + server->cb_ept->dst_prog = cpu_to_be32(server->prog | 0x01000000); + server->cb_ept->dst_vers = cpu_to_be32(server->vers); mutex_lock(&rpc_server_list_lock); list_add(&server->list, &rpc_server_list); @@ -126,6 +150,190 @@ static int rpc_send_accepted_void_reply(struct msm_rpc_endpoint *client, return rc; } +/* + * Interface to be used to start accepted reply message for a + * request. Returns the buffer pointer to attach any payload. + * Should call msm_rpc_server_send_accepted_reply to complete sending + * reply. Marshaling should be handled by user for the payload. + * + * server: pointer to server data structure + * + * xid: transaction id. Has to be same as the one in request. + * + * accept_status: acceptance status + * + * Return Value: + * pointer to buffer to attach the payload. + */ +void *msm_rpc_server_start_accepted_reply(struct msm_rpc_server *server, + uint32_t xid, uint32_t accept_status) +{ + struct rpc_reply_hdr *reply; + + mutex_lock(&server->reply_lock); + + reply = (struct rpc_reply_hdr *)server->reply; + + reply->xid = cpu_to_be32(xid); + reply->type = cpu_to_be32(1); /* reply */ + reply->reply_stat = cpu_to_be32(RPCMSG_REPLYSTAT_ACCEPTED); + + reply->data.acc_hdr.accept_stat = cpu_to_be32(accept_status); + reply->data.acc_hdr.verf_flavor = 0; + reply->data.acc_hdr.verf_length = 0; + + return reply + 1; +} +EXPORT_SYMBOL(msm_rpc_server_start_accepted_reply); + +/* + * Interface to be used to send accepted reply for a request. + * msm_rpc_server_start_accepted_reply should have been called before. + * Marshaling should be handled by user for the payload. + * + * server: pointer to server data structure + * + * size: additional payload size + * + * Return Value: + * 0 on success, otherwise returns an error code. + */ +int msm_rpc_server_send_accepted_reply(struct msm_rpc_server *server, + uint32_t size) +{ + int rc = 0; + + size += sizeof(struct rpc_reply_hdr); + rc = msm_rpc_write(endpoint, server->reply, size); + if (rc > 0) + rc = 0; + + mutex_unlock(&server->reply_lock); + return rc; +} +EXPORT_SYMBOL(msm_rpc_server_send_accepted_reply); + +/* + * Interface to be used to send a server callback request. + * If the request takes any arguments or expects any return, the user + * should handle it in 'arg_func' and 'ret_func' respectively. + * Marshaling and Unmarshaling should be handled by the user in argument + * and return functions. + * + * server: pointer to server data sturcture + * + * clnt_info: pointer to client information data structure. + * callback will be sent to this client. + * + * cb_proc: callback procedure being requested + * + * arg_func: argument function pointer. 'buf' is where arguments needs to + * be filled. 'data' is arg_data. + * + * ret_func: return function pointer. 'buf' is where returned data should + * be read from. 'data' is ret_data. + * + * arg_data: passed as an input parameter to argument function. + * + * ret_data: passed as an input parameter to return function. + * + * timeout: timeout for reply wait in jiffies. If negative timeout is + * specified a default timeout of 10s is used. + * + * Return Value: + * 0 on success, otherwise an error code is returned. + */ +int msm_rpc_server_cb_req(struct msm_rpc_server *server, + struct msm_rpc_client_info *clnt_info, + uint32_t cb_proc, + int (*arg_func)(struct msm_rpc_server *server, + void *buf, void *data), + void *arg_data, + int (*ret_func)(struct msm_rpc_server *server, + void *buf, void *data), + void *ret_data, long timeout) +{ + int size = 0; + struct rpc_reply_hdr *rpc_rsp; + void *buffer; + int rc = 0; + + if (!clnt_info) + return -EINVAL; + + mutex_lock(&server->cb_req_lock); + + msm_rpc_setup_req((struct rpc_request_hdr *)server->cb_req, + (server->prog | 0x01000000), + be32_to_cpu(clnt_info->vers), cb_proc); + size = sizeof(struct rpc_request_hdr); + + if (arg_func) { + rc = arg_func(server, (void *)((struct rpc_request_hdr *) + server->cb_req + 1), arg_data); + if (rc < 0) + goto release_locks; + else + size += rc; + } + + server->cb_ept->dst_pid = clnt_info->pid; + server->cb_ept->dst_cid = clnt_info->cid; + rc = msm_rpc_write(server->cb_ept, server->cb_req, size); + if (rc < 0) { + pr_err("%s: couldn't send RPC CB request:%d\n", __func__, rc); + goto release_locks; + } else + rc = 0; + + if (timeout < 0) + timeout = msecs_to_jiffies(10000); + + rc = msm_rpc_read(server->cb_ept, &buffer, -1, timeout); + if ((rc < ((int)(sizeof(uint32_t) * 2))) || + (be32_to_cpu(*((uint32_t *)buffer + 1)) != 1)) { + printk(KERN_ERR "%s: could not read: %d\n", __func__, rc); + kfree(buffer); + goto free_and_release; + } else + rc = 0; + + rpc_rsp = (struct rpc_reply_hdr *)buffer; + + if (be32_to_cpu(rpc_rsp->reply_stat) != RPCMSG_REPLYSTAT_ACCEPTED) { + pr_err("%s: RPC cb req was denied! %d\n", __func__, + be32_to_cpu(rpc_rsp->reply_stat)); + rc = -EPERM; + goto free_and_release; + } + + if (be32_to_cpu(rpc_rsp->data.acc_hdr.accept_stat) != + RPC_ACCEPTSTAT_SUCCESS) { + pr_err("%s: RPC cb req was not successful (%d)\n", __func__, + be32_to_cpu(rpc_rsp->data.acc_hdr.accept_stat)); + rc = -EINVAL; + goto free_and_release; + } + + if (ret_func) + rc = ret_func(server, (void *)(rpc_rsp + 1), ret_data); + +free_and_release: + kfree(buffer); +release_locks: + mutex_unlock(&server->cb_req_lock); + return rc; +} +EXPORT_SYMBOL(msm_rpc_server_cb_req); + +void msm_rpc_server_get_requesting_client(struct msm_rpc_client_info *clnt_info) +{ + if (!clnt_info) + return; + + get_requesting_client(endpoint, current_xid, clnt_info); +} + static int rpc_servers_thread(void *data) { void *buffer; @@ -134,14 +342,19 @@ static int rpc_servers_thread(void *data) int rc; for (;;) { + rc = wait_event_interruptible(endpoint->wait_q, + !list_empty(&endpoint->read_q)); rc = msm_rpc_read(endpoint, &buffer, -1, -1); if (rc < 0) { printk(KERN_ERR "%s: could not read: %d\n", __FUNCTION__, rc); break; } + req = (struct rpc_request_hdr *)buffer; + current_xid = req->xid; + req->type = be32_to_cpu(req->type); req->xid = be32_to_cpu(req->xid); req->rpc_vers = be32_to_cpu(req->rpc_vers); @@ -164,22 +377,19 @@ static int rpc_servers_thread(void *data) rc = server->rpc_call(server, req, rc); - switch (rc) { - case 0: - rpc_send_accepted_void_reply( - endpoint, req->xid, + if (rc == 0) { + msm_rpc_server_start_accepted_reply( + server, req->xid, RPC_ACCEPTSTAT_SUCCESS); - break; - default: - rpc_send_accepted_void_reply( - endpoint, req->xid, - RPC_ACCEPTSTAT_PROG_UNAVAIL); - break; + msm_rpc_server_send_accepted_reply(server, 0); + } else if (rc < 0) { + msm_rpc_server_start_accepted_reply( + server, req->xid, + RPC_ACCEPTSTAT_PROC_UNAVAIL); + msm_rpc_server_send_accepted_reply(server, 0); } - kfree(buffer); } - do_exit(0); } @@ -193,6 +403,7 @@ static int rpcservers_probe(struct platform_device *pdev) /* we're online -- register any servers installed beforehand */ rpc_servers_active = 1; + current_xid = 0; rpc_server_register_all(); /* start the kernel thread */ -- cgit v1.2.3 From 4e13de78ba3700954a0d07d214fdb28daeb7eda9 Mon Sep 17 00:00:00 2001 From: Sankalp Bose Date: Wed, 16 Sep 2009 15:20:17 +0530 Subject: serial: msm_serial_hs: Change IRQ numbers for UART2DM CRs-fixed: 210231 Signed-off-by: Sankalp Bose --- arch/arm/mach-msm/include/mach/irqs-7xxx.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/include/mach/irqs-7xxx.h b/arch/arm/mach-msm/include/mach/irqs-7xxx.h index 63fd5ed417be..1b3c73d38073 100644 --- a/arch/arm/mach-msm/include/mach/irqs-7xxx.h +++ b/arch/arm/mach-msm/include/mach/irqs-7xxx.h @@ -63,8 +63,8 @@ #define INT_SDC3_1 (32 + 17) #define INT_SDC4_0 (32 + 18) #define INT_SDC4_1 (32 + 19) -#define INT_UART2DM_RX (32 + 20) -#define INT_UART2DM_IRQ (32 + 21) +#define INT_UART2DM_IRQ (32 + 20) +#define INT_UART2DM_RX (32 + 21) /* 22-31 are reserved */ -- cgit v1.2.3 From df2e1e08cd32c64ebdd9e9371747b2e72a143041 Mon Sep 17 00:00:00 2001 From: Matt Wagantall Date: Fri, 21 Aug 2009 12:14:41 -0700 Subject: msm: acpuclock: Rewrite frequency stepping For certain configurations of SoC and modem firmware, given a starting frequency, the list of optimal stepping frequencies to use will vary depending on the target frequency. This is now handled by having, for each frequency in the table, one 'up' and one 'down' entry for each PLL. The up/down indices are also replaced with pointers to the corresponding table entries. These pointers are calculated during boot since manual maintenance of indices is error prone. Signed-off-by: Matt Wagantall --- arch/arm/mach-msm/acpuclock.c | 284 +++++++++++++++++++++--------------------- 1 file changed, 145 insertions(+), 139 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/acpuclock.c b/arch/arm/mach-msm/acpuclock.c index 6cbc2fcfaf0a..0946684b9071 100644 --- a/arch/arm/mach-msm/acpuclock.c +++ b/arch/arm/mach-msm/acpuclock.c @@ -80,12 +80,12 @@ struct clkctl_acpu_speed { unsigned int a11clk_src_div; unsigned int ahbclk_khz; unsigned int ahbclk_div; - unsigned int axiclk_khz; int vdd; + unsigned int axiclk_khz; unsigned long lpj; /* loops_per_jiffy */ -/* Index in acpu_freq_tbl[] for steppings. */ - short down; - short up; +/* Pointers in acpu_freq_tbl[] for max up/down steppings. */ + struct clkctl_acpu_speed *down[3]; + struct clkctl_acpu_speed *up[3]; }; static remote_spinlock_t pll_lock; @@ -99,123 +99,120 @@ static void __init acpuclk_init(void); * ACPU freq tables used for different PLLs frequency combinations. The * correct table is selected during init. * - * Table stepping up/down is calculated during boot to choose the largest - * frequency jump that's less than max_speed_delta_khz and preferrably on the - * same PLL. If no frequencies using the same PLL are within - * max_speed_delta_khz, then the farthest frequency that is within - * max_speed_delta_khz is chosen. + * Table stepping up/down entries are calculated during boot to choose the + * largest frequency jump that's less than max_speed_delta_khz on each PLL. */ /* 7x01/7x25 normal with GSM capable modem */ static struct clkctl_acpu_speed pll0_245_pll1_768_pll2_1056[] = { - { 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 30720, 0 }, - { 1, 122880, ACPU_PLL_0, 4, 1, 61440, 1, 61440, 3 }, - { 0, 128000, ACPU_PLL_1, 1, 5, 64000, 1, 61440, 3 }, - { 0, 176000, ACPU_PLL_2, 2, 5, 88000, 1, 61440, 3 }, - { 1, 245760, ACPU_PLL_0, 4, 0, 81920, 2, 61440, 4 }, - { 1, 256000, ACPU_PLL_1, 1, 2, 128000, 1, 128000, 5 }, - { 0, 352000, ACPU_PLL_2, 2, 2, 88000, 3, 128000, 5 }, - { 1, 384000, ACPU_PLL_1, 1, 1, 128000, 2, 128000, 6 }, - { 1, 528000, ACPU_PLL_2, 2, 1, 132000, 3, 128000, 7 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 0, 30720 }, + { 1, 122880, ACPU_PLL_0, 4, 1, 61440, 1, 3, 61440 }, + { 0, 128000, ACPU_PLL_1, 1, 5, 64000, 1, 3, 61440 }, + { 0, 176000, ACPU_PLL_2, 2, 5, 88000, 1, 3, 61440 }, + { 1, 245760, ACPU_PLL_0, 4, 0, 81920, 2, 4, 61440 }, + { 1, 256000, ACPU_PLL_1, 1, 2, 128000, 1, 5, 128000 }, + { 0, 352000, ACPU_PLL_2, 2, 2, 88000, 3, 5, 128000 }, + { 1, 384000, ACPU_PLL_1, 1, 1, 128000, 2, 6, 128000 }, + { 1, 528000, ACPU_PLL_2, 2, 1, 132000, 3, 7, 128000 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, {0, 0, 0} } }; /* 7x01/7x25 normal with CDMA-only modem */ static struct clkctl_acpu_speed pll0_196_pll1_768_pll2_1056[] = { - { 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 24576, 0 }, - { 1, 98304, ACPU_PLL_0, 4, 1, 49152, 1, 24576, 3 }, - { 0, 128000, ACPU_PLL_1, 1, 5, 64000, 1, 24576, 3 }, - { 0, 176000, ACPU_PLL_2, 2, 5, 88000, 1, 24576, 3 }, - { 1, 196608, ACPU_PLL_0, 4, 0, 65536, 2, 24576, 4 }, - { 1, 256000, ACPU_PLL_1, 1, 2, 128000, 1, 128000, 5 }, - { 0, 352000, ACPU_PLL_2, 2, 2, 88000, 3, 128000, 5 }, - { 1, 384000, ACPU_PLL_1, 1, 1, 128000, 2, 128000, 6 }, - { 1, 528000, ACPU_PLL_2, 2, 1, 132000, 3, 128000, 7 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 0, 24576 }, + { 1, 98304, ACPU_PLL_0, 4, 1, 49152, 1, 3, 24576 }, + { 0, 128000, ACPU_PLL_1, 1, 5, 64000, 1, 3, 24576 }, + { 0, 176000, ACPU_PLL_2, 2, 5, 88000, 1, 3, 24576 }, + { 1, 196608, ACPU_PLL_0, 4, 0, 65536, 2, 4, 24576 }, + { 1, 256000, ACPU_PLL_1, 1, 2, 128000, 1, 5, 128000 }, + { 0, 352000, ACPU_PLL_2, 2, 2, 88000, 3, 5, 128000 }, + { 1, 384000, ACPU_PLL_1, 1, 1, 128000, 2, 6, 128000 }, + { 1, 528000, ACPU_PLL_2, 2, 1, 132000, 3, 7, 128000 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, {0, 0, 0} } }; /* 7x01/7x25 turbo with GSM capable modem */ static struct clkctl_acpu_speed pll0_245_pll1_960_pll2_1056[] = { - { 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 30720, 0 }, - { 0, 120000, ACPU_PLL_1, 1, 7, 60000, 1, 61440, 3 }, - { 1, 122880, ACPU_PLL_0, 4, 1, 61440, 1, 61440, 3 }, - { 0, 176000, ACPU_PLL_2, 2, 5, 88000, 1, 61440, 3 }, - { 1, 245760, ACPU_PLL_0, 4, 0, 81920, 2, 61440, 4 }, - { 1, 320000, ACPU_PLL_1, 1, 2, 107000, 2, 120000, 5 }, - { 0, 352000, ACPU_PLL_2, 2, 2, 88000, 3, 120000, 5 }, - { 1, 480000, ACPU_PLL_1, 1, 1, 120000, 3, 120000, 6 }, - { 1, 528000, ACPU_PLL_2, 2, 1, 132000, 3, 122880, 7 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 0, 30720 }, + { 0, 120000, ACPU_PLL_1, 1, 7, 60000, 1, 3, 61440 }, + { 1, 122880, ACPU_PLL_0, 4, 1, 61440, 1, 3, 61440 }, + { 0, 176000, ACPU_PLL_2, 2, 5, 88000, 1, 3, 61440 }, + { 1, 245760, ACPU_PLL_0, 4, 0, 81920, 2, 4, 61440 }, + { 1, 320000, ACPU_PLL_1, 1, 2, 107000, 2, 5, 120000 }, + { 0, 352000, ACPU_PLL_2, 2, 2, 88000, 3, 5, 120000 }, + { 1, 480000, ACPU_PLL_1, 1, 1, 120000, 3, 6, 120000 }, + { 1, 528000, ACPU_PLL_2, 2, 1, 132000, 3, 7, 122880 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, {0, 0, 0} } }; /* 7x01/7x25 turbo with CDMA-only modem */ static struct clkctl_acpu_speed pll0_196_pll1_960_pll2_1056[] = { - { 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 24576, 0 }, - { 1, 98304, ACPU_PLL_0, 4, 1, 49152, 1, 24576, 3 }, - { 0, 120000, ACPU_PLL_1, 1, 7, 60000, 1, 24576, 3 }, - { 0, 176000, ACPU_PLL_2, 2, 5, 88000, 1, 24576, 3 }, - { 1, 196608, ACPU_PLL_0, 4, 0, 65536, 2, 24576, 4 }, - { 1, 320000, ACPU_PLL_1, 1, 2, 107000, 2, 120000, 5 }, - { 0, 352000, ACPU_PLL_2, 2, 2, 88000, 3, 120000, 5 }, - { 1, 480000, ACPU_PLL_1, 1, 1, 120000, 3, 120000, 6 }, - { 1, 528000, ACPU_PLL_2, 2, 1, 132000, 3, 120000, 7 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 0, 24576 }, + { 1, 98304, ACPU_PLL_0, 4, 1, 49152, 1, 3, 24576 }, + { 0, 120000, ACPU_PLL_1, 1, 7, 60000, 1, 3, 24576 }, + { 0, 176000, ACPU_PLL_2, 2, 5, 88000, 1, 3, 24576 }, + { 1, 196608, ACPU_PLL_0, 4, 0, 65536, 2, 4, 24576 }, + { 1, 320000, ACPU_PLL_1, 1, 2, 107000, 2, 5, 120000 }, + { 0, 352000, ACPU_PLL_2, 2, 2, 88000, 3, 5, 120000 }, + { 1, 480000, ACPU_PLL_1, 1, 1, 120000, 3, 6, 120000 }, + { 1, 528000, ACPU_PLL_2, 2, 1, 132000, 3, 7, 120000 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, {0, 0, 0} } }; /* 7x27 normal with GSM capable modem */ static struct clkctl_acpu_speed pll0_245_pll1_960_pll2_1200[] = { - { 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 30720, 0 }, - { 0, 120000, ACPU_PLL_1, 1, 7, 60000, 1, 61440, 3 }, - { 1, 122880, ACPU_PLL_0, 4, 1, 61440, 1, 61440, 3 }, - { 0, 200000, ACPU_PLL_2, 2, 5, 66667, 2, 61440, 4 }, - { 1, 245760, ACPU_PLL_0, 4, 0, 122880, 1, 61440, 4 }, - { 1, 320000, ACPU_PLL_1, 1, 2, 160000, 1, 122880, 5 }, - { 0, 400000, ACPU_PLL_2, 2, 2, 133333, 2, 122880, 5 }, - { 1, 480000, ACPU_PLL_1, 1, 1, 160000, 2, 122880, 6 }, - { 1, 600000, ACPU_PLL_2, 2, 1, 200000, 2, 122880, 7 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 0, 30720 }, + { 0, 120000, ACPU_PLL_1, 1, 7, 60000, 1, 3, 61440 }, + { 1, 122880, ACPU_PLL_0, 4, 1, 61440, 1, 3, 61440 }, + { 0, 200000, ACPU_PLL_2, 2, 5, 66667, 2, 4, 61440 }, + { 1, 245760, ACPU_PLL_0, 4, 0, 122880, 1, 4, 61440 }, + { 1, 320000, ACPU_PLL_1, 1, 2, 160000, 1, 5, 122880 }, + { 0, 400000, ACPU_PLL_2, 2, 2, 133333, 2, 5, 122880 }, + { 1, 480000, ACPU_PLL_1, 1, 1, 160000, 2, 6, 122880 }, + { 1, 600000, ACPU_PLL_2, 2, 1, 200000, 2, 7, 122880 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, {0, 0, 0} } }; /* 7x27 normal with CDMA-only modem */ static struct clkctl_acpu_speed pll0_196_pll1_960_pll2_1200[] = { - { 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 24576, 0 }, - { 1, 98304, ACPU_PLL_0, 4, 1, 98304, 0, 49152, 3 }, - { 0, 120000, ACPU_PLL_1, 1, 7, 60000, 1, 49152, 3 }, - { 1, 196608, ACPU_PLL_0, 4, 0, 65536, 2, 98304, 4 }, - { 0, 200000, ACPU_PLL_2, 2, 5, 66667, 2, 98304, 4 }, - { 1, 320000, ACPU_PLL_1, 1, 2, 160000, 1, 120000, 5 }, - { 0, 400000, ACPU_PLL_2, 2, 2, 133333, 2, 120000, 5 }, - { 1, 480000, ACPU_PLL_1, 1, 1, 160000, 2, 120000, 6 }, - { 1, 600000, ACPU_PLL_2, 2, 1, 200000, 2, 120000, 7 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 0, 24576 }, + { 1, 98304, ACPU_PLL_0, 4, 1, 98304, 0, 3, 49152 }, + { 0, 120000, ACPU_PLL_1, 1, 7, 60000, 1, 3, 49152 }, + { 1, 196608, ACPU_PLL_0, 4, 0, 65536, 2, 4, 98304 }, + { 0, 200000, ACPU_PLL_2, 2, 5, 66667, 2, 4, 98304 }, + { 1, 320000, ACPU_PLL_1, 1, 2, 160000, 1, 5, 120000 }, + { 0, 400000, ACPU_PLL_2, 2, 2, 133333, 2, 5, 120000 }, + { 1, 480000, ACPU_PLL_1, 1, 1, 160000, 2, 6, 120000 }, + { 1, 600000, ACPU_PLL_2, 2, 1, 200000, 2, 7, 120000 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, {0, 0, 0} } }; /* 7x27 normal with GSM capable modem - PLL0 and PLL1 swapped */ static struct clkctl_acpu_speed pll0_960_pll1_245_pll2_1200[] = { - { 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 30720, 0 }, - { 0, 120000, ACPU_PLL_0, 4, 7, 60000, 1, 61440, 3 }, - { 1, 122880, ACPU_PLL_1, 1, 1, 61440, 1, 61440, 3 }, - { 0, 200000, ACPU_PLL_2, 2, 5, 66667, 2, 61440, 4 }, - { 1, 245760, ACPU_PLL_1, 1, 0, 122880, 1, 61440, 4 }, - { 1, 320000, ACPU_PLL_0, 4, 2, 160000, 1, 122880, 5 }, - { 0, 400000, ACPU_PLL_2, 2, 2, 133333, 2, 122880, 5 }, - { 1, 480000, ACPU_PLL_0, 4, 1, 160000, 2, 122880, 6 }, - { 1, 600000, ACPU_PLL_2, 2, 1, 200000, 2, 122880, 7 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 0, 30720 }, + { 0, 120000, ACPU_PLL_0, 4, 7, 60000, 1, 3, 61440 }, + { 1, 122880, ACPU_PLL_1, 1, 1, 61440, 1, 3, 61440 }, + { 0, 200000, ACPU_PLL_2, 2, 5, 66667, 2, 4, 61440 }, + { 1, 245760, ACPU_PLL_1, 1, 0, 122880, 1, 4, 61440 }, + { 1, 320000, ACPU_PLL_0, 4, 2, 160000, 1, 5, 122880 }, + { 0, 400000, ACPU_PLL_2, 2, 2, 133333, 2, 5, 122880 }, + { 1, 480000, ACPU_PLL_0, 4, 1, 160000, 2, 6, 122880 }, + { 1, 600000, ACPU_PLL_2, 2, 1, 200000, 2, 7, 122880 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, {0, 0, 0} } }; /* 7x27 normal with CDMA-only modem - PLL0 and PLL1 swapped */ static struct clkctl_acpu_speed pll0_960_pll1_196_pll2_1200[] = { - { 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 24576, 0 }, - { 1, 98304, ACPU_PLL_1, 1, 1, 98304, 0, 49152, 3 }, - { 0, 120000, ACPU_PLL_0, 4, 7, 60000, 1, 49152, 3 }, - { 1, 196608, ACPU_PLL_1, 1, 0, 65536, 2, 98304, 4 }, - { 0, 200000, ACPU_PLL_2, 2, 5, 66667, 2, 98304, 4 }, - { 1, 320000, ACPU_PLL_0, 4, 2, 160000, 1, 120000, 5 }, - { 0, 400000, ACPU_PLL_2, 2, 2, 133333, 2, 120000, 5 }, - { 1, 480000, ACPU_PLL_0, 4, 1, 160000, 2, 120000, 6 }, - { 1, 600000, ACPU_PLL_2, 2, 1, 200000, 2, 120000, 7 }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 0, 24576 }, + { 1, 98304, ACPU_PLL_1, 1, 1, 98304, 0, 3, 49152 }, + { 0, 120000, ACPU_PLL_0, 4, 7, 60000, 1, 3, 49152 }, + { 1, 196608, ACPU_PLL_1, 1, 0, 65536, 2, 4, 98304 }, + { 0, 200000, ACPU_PLL_2, 2, 5, 66667, 2, 4, 98304 }, + { 1, 320000, ACPU_PLL_0, 4, 2, 160000, 1, 5, 120000 }, + { 0, 400000, ACPU_PLL_2, 2, 2, 133333, 2, 5, 120000 }, + { 1, 480000, ACPU_PLL_0, 4, 1, 160000, 2, 6, 120000 }, + { 1, 600000, ACPU_PLL_2, 2, 1, 200000, 2, 7, 120000 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, {0, 0, 0} } }; #define PLL_196_MHZ 10 @@ -332,9 +329,9 @@ static int pc_pll_request(unsigned id, unsigned on) #if PERF_SWITCH_DEBUG if (on) - printk(KERN_DEBUG "PLL %d enabled\n", id); + printk(KERN_DEBUG "PLL enabled\n"); else - printk(KERN_DEBUG "PLL %d disabled\n", id); + printk(KERN_DEBUG "PLL disabled\n"); #endif return res; } @@ -501,16 +498,33 @@ int acpuclk_set_rate(unsigned long rate, enum setrate_reason reason) */ int d = abs((int)(cur_s->a11clk_khz - tgt_s->a11clk_khz)); if (d > drv_state.max_speed_delta_khz) { - /* Step up or down depending on target vs current. */ - int clk_index = tgt_s->a11clk_khz > cur_s->a11clk_khz ? - cur_s->up : cur_s->down; - if (clk_index < 0) { /* This should not happen. */ - printk(KERN_ERR "cur:%u target: %u\n", - cur_s->a11clk_khz, tgt_s->a11clk_khz); + + if (tgt_s->a11clk_khz > cur_s->a11clk_khz) { + /* Step up: jump to target PLL as early as + * possible so indexing using TCXO (up[-1]) + * never occurs. */ + if (likely(cur_s->up[tgt_s->pll])) + cur_s = cur_s->up[tgt_s->pll]; + else + cur_s = cur_s->up[cur_s->pll]; + } else { + /* Step down: stay on current PLL as long as + * possible so indexing using TCXO (down[-1]) + * never occurs. */ + if (likely(cur_s->down[cur_s->pll])) + cur_s = cur_s->down[cur_s->pll]; + else + cur_s = cur_s->down[tgt_s->pll]; + } + + if (cur_s == NULL) { /* This should not happen. */ + pr_err("No stepping frequencies found. " + "strt_s:%u tgt_s:%u\n", + strt_s->a11clk_khz, tgt_s->a11clk_khz); rc = -EINVAL; goto out; } - cur_s = &acpu_freq_tbl[clk_index]; + } else { cur_s = tgt_s; } @@ -747,7 +761,7 @@ static void __init lpj_init(void) static void __init precompute_stepping(void) { - int i, step_idx, step_same_pll_idx; + int i, step_idx; #define cur_freq acpu_freq_tbl[i].a11clk_khz #define step_freq acpu_freq_tbl[step_idx].a11clk_khz @@ -756,59 +770,32 @@ static void __init precompute_stepping(void) for (i = 0; acpu_freq_tbl[i].a11clk_khz; i++) { - /* Calculate "Up" step. */ + /* Calculate max "up" step for each destination PLL */ step_idx = i + 1; - step_same_pll_idx = -1; while (step_freq && (step_freq - cur_freq) <= drv_state.max_speed_delta_khz) { - if (step_pll == cur_pll) - step_same_pll_idx = step_idx; + acpu_freq_tbl[i].up[step_pll] = + &acpu_freq_tbl[step_idx]; step_idx++; } - - /* Highest freq within max_speed_delta_khz. No step needed. */ - if (step_freq == 0) - acpu_freq_tbl[i].up = -1; - else if (step_idx == (i + 1)) { + if (step_idx == (i + 1) && step_freq) { pr_crit("Delta between freqs %u KHz and %u KHz is" " too high!\n", cur_freq, step_freq); BUG(); - } else { - /* There is only one TCXO freq. So don't complain. */ - if (cur_pll == ACPU_PLL_TCXO) - step_same_pll_idx = step_idx - 1; - if (step_same_pll_idx == -1) { - pr_warning("Suboptimal up stepping for CPU " - "freq %u KHz.\n", cur_freq); - acpu_freq_tbl[i].up = step_idx - 1; - } else - acpu_freq_tbl[i].up = step_same_pll_idx; } - /* Calculate "Down" step. */ + /* Calculate max "down" step for each destination PLL */ step_idx = i - 1; - step_same_pll_idx = -1; while (step_idx >= 0 && (cur_freq - step_freq) <= drv_state.max_speed_delta_khz) { - if (step_pll == cur_pll) - step_same_pll_idx = step_idx; + acpu_freq_tbl[i].down[step_pll] = + &acpu_freq_tbl[step_idx]; step_idx--; } - - /* Lowest freq within max_speed_delta_khz. No step needed. */ - if (step_idx == -1) - acpu_freq_tbl[i].down = -1; - else if (step_idx == (i - 1)) { + if (step_idx == (i - 1) && i > 0) { pr_crit("Delta between freqs %u KHz and %u KHz is" " too high!\n", cur_freq, step_freq); BUG(); - } else { - if (step_same_pll_idx == -1) { - pr_warning("Suboptimal down stepping for CPU " - "freq %u KHz.\n", cur_freq); - acpu_freq_tbl[i].down = step_idx + 1; - } else - acpu_freq_tbl[i].down = step_same_pll_idx; } } } @@ -816,12 +803,31 @@ static void __init precompute_stepping(void) static void __init print_acpu_freq_tbl(void) { struct clkctl_acpu_speed *t; - pr_info("CPU-Freq PLL DIV AHB-Freq ADIV AXI-Freq Dn Up\n"); - for (t = &acpu_freq_tbl[0]; t->a11clk_khz != 0; t++) - pr_info("%8d %3d %3d %8d %4d %8d %2d %2d\n", - t->a11clk_khz, t->pll, t->a11clk_src_div + 1, + short down_idx[3]; + short up_idx[3]; + int i, j; + +#define FREQ_IDX(freq_ptr) (freq_ptr - acpu_freq_tbl) + pr_info("Id CPU-KHz PLL DIV AHB-KHz ADIV AXI-KHz " + "D0 D1 D2 U0 U1 U2\n"); + + t = &acpu_freq_tbl[0]; + for (i = 0; t->a11clk_khz != 0; i++) { + + for (j = 0; j < 3; j++) { + down_idx[j] = t->down[j] ? FREQ_IDX(t->down[j]) : -1; + up_idx[j] = t->up[j] ? FREQ_IDX(t->up[j]) : -1; + } + + pr_info("%2d %7d %3d %3d %7d %4d %7d " + "%2d %2d %2d %2d %2d %2d\n", + i, t->a11clk_khz, t->pll, t->a11clk_src_div + 1, t->ahbclk_khz, t->ahbclk_div + 1, t->axiclk_khz, - t->down, t->up); + down_idx[0], down_idx[1], down_idx[2], + up_idx[0], up_idx[1], up_idx[2]); + + t++; + } } static void msm7x25_acpu_pll_hw_bug_fix(void) -- cgit v1.2.3 From 402f3ff5e21c5d4ecabecb5b5d83d7279f100703 Mon Sep 17 00:00:00 2001 From: Matt Wagantall Date: Tue, 8 Sep 2009 11:26:56 -0700 Subject: msm: acpuclock: Grab lock when changing ACPU freq. It is possible for multiple threads to concurrently execute acpuclk_set_rate(). To prevent race conditions, code using data from the drv_state struct must be locked. The mutex is acquired prior to accessing drv_state data, but only when acpuclk_set_rate() is called for a reason other than Power Collapse or SWFI. In these situations a mutex cannot be acquired because interrupts are disabled, and is not needed because the CPU is known to be idle. CRs-fixed: 194883 Signed-off-by: Matt Wagantall --- arch/arm/mach-msm/acpuclock-8x50.c | 18 ++++++++++-------- arch/arm/mach-msm/acpuclock.c | 24 +++++++++++++++--------- 2 files changed, 25 insertions(+), 17 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/acpuclock-8x50.c b/arch/arm/mach-msm/acpuclock-8x50.c index a923c288b36c..c1fd3506d4b5 100644 --- a/arch/arm/mach-msm/acpuclock-8x50.c +++ b/arch/arm/mach-msm/acpuclock-8x50.c @@ -405,22 +405,25 @@ int acpuclk_set_rate(unsigned long rate, enum setrate_reason reason) struct clkctl_acpu_speed *tgt_s, *strt_s; int rc = 0; + if (reason == SETRATE_CPUFREQ) + mutex_lock(&drv_state.lock); + strt_s = drv_state.current_speed; if (rate == (strt_s->a11clk_khz * 1000)) - return 0; + goto out; for (tgt_s = acpu_freq_tbl; tgt_s->a11clk_khz != 0; tgt_s++) { if (tgt_s->a11clk_khz == (rate / 1000)) break; } - if (tgt_s->a11clk_khz == 0) - return -EINVAL; + if (tgt_s->a11clk_khz == 0) { + rc = -EINVAL; + goto out; + } if (reason == SETRATE_CPUFREQ) { - mutex_lock(&drv_state.lock); - /* Increase VDD if needed. */ if (tgt_s->vdd > strt_s->vdd) { rc = acpuclk_set_vdd_level(tgt_s->vdd); @@ -454,7 +457,7 @@ int acpuclk_set_rate(unsigned long rate, enum setrate_reason reason) /* Nothing else to do for SWFI. */ if (reason == SETRATE_SWFI) - return 0; + goto out; if (strt_s->axiclk_khz != tgt_s->axiclk_khz) { rc = ebi1_clk_set_min_rate(CLKVOTE_ACPUCLK, @@ -465,7 +468,7 @@ int acpuclk_set_rate(unsigned long rate, enum setrate_reason reason) /* Nothing else to do for power collapse */ if (reason == SETRATE_PC) - return 0; + goto out; /* Drop VDD level if we can. */ if (tgt_s->vdd < strt_s->vdd) { @@ -477,7 +480,6 @@ int acpuclk_set_rate(unsigned long rate, enum setrate_reason reason) out: if (reason == SETRATE_CPUFREQ) mutex_unlock(&drv_state.lock); - return rc; } diff --git a/arch/arm/mach-msm/acpuclock.c b/arch/arm/mach-msm/acpuclock.c index 0946684b9071..c594b96ad9f2 100644 --- a/arch/arm/mach-msm/acpuclock.c +++ b/arch/arm/mach-msm/acpuclock.c @@ -428,22 +428,29 @@ int acpuclk_set_rate(unsigned long rate, enum setrate_reason reason) int rc = 0; unsigned int plls_enabled = 0, pll; + if (reason == SETRATE_CPUFREQ) + mutex_lock(&drv_state.lock); + strt_s = cur_s = drv_state.current_speed; WARN_ONCE(cur_s == NULL, "acpuclk_set_rate: not initialized\n"); - if (cur_s == NULL) - return -ENOENT; + if (cur_s == NULL) { + rc = -ENOENT; + goto out; + } if (rate == (cur_s->a11clk_khz * 1000)) - return 0; + goto out; for (tgt_s = acpu_freq_tbl; tgt_s->a11clk_khz != 0; tgt_s++) { if (tgt_s->a11clk_khz == (rate / 1000)) break; } - if (tgt_s->a11clk_khz == 0) - return -EINVAL; + if (tgt_s->a11clk_khz == 0) { + rc = -EINVAL; + goto out; + } /* Choose the highest speed at or below 'rate' with same PLL. */ if (reason != SETRATE_CPUFREQ @@ -456,7 +463,6 @@ int acpuclk_set_rate(unsigned long rate, enum setrate_reason reason) plls_enabled |= 1 << strt_s->pll; if (reason == SETRATE_CPUFREQ) { - mutex_lock(&drv_state.lock); if (strt_s->pll != tgt_s->pll && tgt_s->pll != ACPU_PLL_TCXO) { rc = pc_pll_request(tgt_s->pll, 1); if (rc < 0) { @@ -552,7 +558,7 @@ int acpuclk_set_rate(unsigned long rate, enum setrate_reason reason) /* Nothing else to do for SWFI. */ if (reason == SETRATE_SWFI) - return 0; + goto out; /* Change the AXI bus frequency if we can. */ if (strt_s->axiclk_khz != tgt_s->axiclk_khz) { @@ -564,7 +570,7 @@ int acpuclk_set_rate(unsigned long rate, enum setrate_reason reason) /* Nothing else to do for power collapse if not 7x27. */ if (reason == SETRATE_PC && !cpu_is_msm7x27()) - return 0; + goto out; /* Disable PLLs we are not using anymore. */ if (tgt_s->pll != ACPU_PLL_TCXO) @@ -580,7 +586,7 @@ int acpuclk_set_rate(unsigned long rate, enum setrate_reason reason) /* Nothing else to do for power collapse. */ if (reason == SETRATE_PC) - return 0; + goto out; /* Drop VDD level if we can. */ if (tgt_s->vdd < strt_s->vdd) { -- cgit v1.2.3 From 7ca2cce8e518c7be9e455020110aa20cf3950005 Mon Sep 17 00:00:00 2001 From: Matt Wagantall Date: Tue, 22 Sep 2009 11:23:13 -0700 Subject: msm: clock: Add rotator clocks to 7x30 clock list Signed-off-by: Matt Wagantall --- arch/arm/mach-msm/devices.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/devices.c b/arch/arm/mach-msm/devices.c index b7f7cbdb3a53..c9417d00da51 100644 --- a/arch/arm/mach-msm/devices.c +++ b/arch/arm/mach-msm/devices.c @@ -561,6 +561,8 @@ struct clk msm_clocks_7x30[] = { CLK_PCOM("pcm_clk", PCM_CLK, NULL, 0), CLK_PCOM("mddi_clk", PMDH_CLK, NULL, OFF | CLK_MINMAX), CLK_PCOM("mddi_pclk", PMDH_PCLK, NULL, 0), + CLK_PCOM("rotator_imem_clk", ROTATOR_IMEM_CLK, NULL, 0), + CLK_PCOM("rotator_pclk", ROTATOR_PCLK, NULL, 0), CLK_PCOM("sdac_clk", SDAC_CLK, NULL, OFF), CLK_PCOM("sdc_clk", SDC1_CLK, &msm_device_sdc1.dev, OFF), CLK_PCOM("sdc_pclk", SDC1_PCLK, &msm_device_sdc1.dev, OFF), -- cgit v1.2.3 From 5cb74e069efd1c345bdca2cd2b879652a8c92ab4 Mon Sep 17 00:00:00 2001 From: Pavankumar Kondeti Date: Tue, 22 Sep 2009 13:39:48 +0530 Subject: msm: Fix UART base address for MSM7x30 CRs-fixed: 210856 Signed-off-by: Pavankumar Kondeti --- arch/arm/mach-msm/include/mach/msm_iomap.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/include/mach/msm_iomap.h b/arch/arm/mach-msm/include/mach/msm_iomap.h index 74ec54e61eb9..68c2b5ae73dc 100644 --- a/arch/arm/mach-msm/include/mach/msm_iomap.h +++ b/arch/arm/mach-msm/include/mach/msm_iomap.h @@ -122,13 +122,17 @@ #define MSM_SHARED_RAM_BASE IOMEM(0xE0100000) #define MSM_SHARED_RAM_SIZE SZ_1M +#if defined(CONFIG_ARCH_MSM7X30) +#define MSM_UART1_PHYS 0xACA00000 +#define MSM_UART2_PHYS 0xACB00000 +#define MSM_UART3_PHYS 0xACC00000 +#else #define MSM_UART1_PHYS 0xA9A00000 -#define MSM_UART1_SIZE SZ_4K - #define MSM_UART2_PHYS 0xA9B00000 -#define MSM_UART2_SIZE SZ_4K - #define MSM_UART3_PHYS 0xA9C00000 +#endif +#define MSM_UART1_SIZE SZ_4K +#define MSM_UART2_SIZE SZ_4K #define MSM_UART3_SIZE SZ_4K #ifdef CONFIG_MSM_DEBUG_UART -- cgit v1.2.3 From 73838023e58de8b9f51a8188078ccaf4b5723e72 Mon Sep 17 00:00:00 2001 From: Matt Wagantall Date: Thu, 24 Sep 2009 13:27:09 -0700 Subject: msm: acpuclock-8x50: Fix PLL0 speed for CDMA-only targets PLL0 runs at 235MHz instead of 245MHz for CDMA-only targets. The corresponding ACPU frequency table entry is corrected during initialization if the slower rate is detected. Signed-off-by: Matt Wagantall --- arch/arm/mach-msm/acpuclock-8x50.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/acpuclock-8x50.c b/arch/arm/mach-msm/acpuclock-8x50.c index c1fd3506d4b5..2f408bf6f90b 100644 --- a/arch/arm/mach-msm/acpuclock-8x50.c +++ b/arch/arm/mach-msm/acpuclock-8x50.c @@ -574,13 +574,20 @@ unsigned long acpuclk_wait_for_irq(void) #define CT_CSR_PHYS 0xA8700000 #define TCSR_SPARE2_ADDR (ct_csr_base + 0x60) +#define PLL0_M_VAL_ADDR (MSM_CLK_CTL_BASE + 0x308) + static void __init acpu_freq_tbl_fixup(void) { void __iomem *ct_csr_base; - uint32_t tcsr_spare2; - unsigned int max_acpu_khz; + uint32_t tcsr_spare2, pll0_m_val; + unsigned int max_acpu_khz, pll0_fixup; unsigned int i; + /* pll0_m_val will be 36 for CDMA-only and 4 otherwise, + * indicating PLL0 is running at 235MHz, not 245MHz */ + pll0_m_val = readl(PLL0_M_VAL_ADDR) & 0x7FFFF; + pll0_fixup = (pll0_m_val == 36); + ct_csr_base = ioremap(CT_CSR_PHYS, PAGE_SIZE); BUG_ON(ct_csr_base == NULL); @@ -622,6 +629,10 @@ skip_efuse_fixup: iounmap(ct_csr_base); BUG_ON(drv_state.max_vdd == 0); for (i = 0; acpu_freq_tbl[i].a11clk_khz != 0; i++) { + if (pll0_fixup && acpu_freq_tbl[i].pll == ACPU_PLL_0) { + /* PLL0 is 235.93MHz for CDMA-only */ + acpu_freq_tbl[i].a11clk_khz = 235930; + } if (acpu_freq_tbl[i].vdd > drv_state.max_vdd) { acpu_freq_tbl[i].a11clk_khz = 0; break; -- cgit v1.2.3 From 4db7f59739d4343f54d1273dd4204f5d7113c265 Mon Sep 17 00:00:00 2001 From: Pavankumar Kondeti Date: Wed, 26 Aug 2009 23:22:05 +0530 Subject: msm: serial: Add UART support for MSM7x30 Signed-off-by: Pavankumar Kondeti --- arch/arm/mach-msm/board-msm7x30.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c index 4b024988a505..f0a2b7691d33 100644 --- a/arch/arm/mach-msm/board-msm7x30.c +++ b/arch/arm/mach-msm/board-msm7x30.c @@ -100,6 +100,9 @@ static struct platform_device *devices[] __initdata = { &msm_device_dmov, &smc91x_device, &msm_device_nand, +#ifdef CONFIG_SERIAL_MSM_CONSOLE + &msm_device_uart2, +#endif }; static void __init msm7x30_init_irq(void) @@ -134,6 +137,22 @@ static struct msm_pm_platform_data msm_pm_data[MSM_PM_SLEEP_MODE_NR] = { [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].residency = 0, }; +#ifdef CONFIG_SERIAL_MSM_CONSOLE +static struct msm_gpio uart2_config_data[] = { + { GPIO_CFG(49, 2, GPIO_OUTPUT, GPIO_PULL_DOWN, GPIO_2MA), "UART2_RFR"}, + { GPIO_CFG(50, 2, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), "UART2_CTS"}, + { GPIO_CFG(51, 2, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), "UART2_Rx"}, + { GPIO_CFG(52, 2, GPIO_OUTPUT, GPIO_PULL_DOWN, GPIO_2MA), "UART2_Tx"}, +}; + +static void msm7x30_init_uart2(void) +{ + msm_gpios_request_enable(uart2_config_data, + ARRAY_SIZE(uart2_config_data)); + +} +#endif + static void __init msm7x30_init(void) { if (socinfo_init() < 0) @@ -141,6 +160,9 @@ static void __init msm7x30_init(void) __func__); platform_add_devices(devices, ARRAY_SIZE(devices)); msm_pm_set_platform_data(msm_pm_data); +#ifdef CONFIG_SERIAL_MSM_CONSOLE + msm7x30_init_uart2(); +#endif } static void __init msm7x30_map_io(void) -- cgit v1.2.3 From 57d68741a0e23e24088534c1cecf44f1e1708666 Mon Sep 17 00:00:00 2001 From: Dave Estes Date: Mon, 24 Aug 2009 14:12:42 -0400 Subject: msm: qsd8x50: Add adaptive voltage scaling (AVS) The purpose of AVS is to minimize the power used by the CPU by determining and setting the optimal voltage. The optimal voltage is actively determined for each frequency and temperature. AVS actively adjusts the CPU voltage as the CPU frequency and temperature changes. Signed-off-by: Dave Estes --- arch/arm/mach-msm/Kconfig | 10 ++ arch/arm/mach-msm/Makefile | 1 + arch/arm/mach-msm/acpuclock-8x50.c | 47 +++++- arch/arm/mach-msm/avs.c | 323 +++++++++++++++++++++++++++++++++++++ arch/arm/mach-msm/avs.h | 52 ++++++ arch/arm/mach-msm/avs_hw.S | 158 ++++++++++++++++++ arch/arm/mach-msm/idle-v7.S | 20 +++ 7 files changed, 609 insertions(+), 2 deletions(-) create mode 100644 arch/arm/mach-msm/avs.c create mode 100644 arch/arm/mach-msm/avs.h create mode 100644 arch/arm/mach-msm/avs_hw.S (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index 50e7c05bb3ad..d32ceb386d0b 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -558,6 +558,16 @@ config MSM_CPU_FREQ_MIN endif # CPU_FREQ_MSM +config MSM_CPU_AVS + bool "Enable Adaptive Voltage Scaling (AVS)" + depends on (ARCH_MSM_SCORPION && QSD_SVS) + depends on ARCH_QSD8X50 + default y + help + This enables the Adaptive Voltage Scaling feature of + Qualcomm ARMv7 CPUs. It adjusts the voltage for each frequency + based on feedback from three ring oscillators in the CPU. + config MSM_VREG_SWITCH_INVERTED bool "Reverse vreg switch polarity" default n diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 8483d0881c29..12c68ff2ebf6 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -15,6 +15,7 @@ obj-y += pmic.o obj-$(CONFIG_ARCH_MSM_ARM11) += acpuclock.o obj-$(CONFIG_ARCH_MSM_SCORPION) += acpuclock-8x50.o +obj-$(CONFIG_MSM_CPU_AVS) += avs.o avs_hw.o obj-$(CONFIG_CPU_V6) += idle-v6.o obj-$(CONFIG_CPU_V7) += idle-v7.o obj-$(CONFIG_MSM_JTAG_V7) += jtag-v7.o diff --git a/arch/arm/mach-msm/acpuclock-8x50.c b/arch/arm/mach-msm/acpuclock-8x50.c index 2f408bf6f90b..9283a2d5e490 100644 --- a/arch/arm/mach-msm/acpuclock-8x50.c +++ b/arch/arm/mach-msm/acpuclock-8x50.c @@ -67,6 +67,7 @@ #include #include "acpuclock.h" +#include "avs.h" #include "clock.h" #define SHOT_SWITCH 4 @@ -404,6 +405,7 @@ int acpuclk_set_rate(unsigned long rate, enum setrate_reason reason) { struct clkctl_acpu_speed *tgt_s, *strt_s; int rc = 0; + int freq_index = 0; if (reason == SETRATE_CPUFREQ) mutex_lock(&drv_state.lock); @@ -416,6 +418,7 @@ int acpuclk_set_rate(unsigned long rate, enum setrate_reason reason) for (tgt_s = acpu_freq_tbl; tgt_s->a11clk_khz != 0; tgt_s++) { if (tgt_s->a11clk_khz == (rate / 1000)) break; + freq_index++; } if (tgt_s->a11clk_khz == 0) { @@ -424,6 +427,16 @@ int acpuclk_set_rate(unsigned long rate, enum setrate_reason reason) } if (reason == SETRATE_CPUFREQ) { +#ifdef CONFIG_MSM_CPU_AVS + /* Notify avs before changing frequency */ + rc = avs_adjust_freq(freq_index, 1); + if (rc) { + printk(KERN_ERR + "acpuclock: Unable to increase ACPU " + "vdd.\n"); + goto out; + } +#endif /* Increase VDD if needed. */ if (tgt_s->vdd > strt_s->vdd) { rc = acpuclk_set_vdd_level(tgt_s->vdd); @@ -470,6 +483,14 @@ int acpuclk_set_rate(unsigned long rate, enum setrate_reason reason) if (reason == SETRATE_PC) goto out; +#ifdef CONFIG_MSM_CPU_AVS + /* notify avs after changing frequency */ + rc = avs_adjust_freq(freq_index, 0); + if (rc) + printk(KERN_ERR + "acpuclock: Unable to drop ACPU vdd.\n"); +#endif + /* Drop VDD level if we can. */ if (tgt_s->vdd < strt_s->vdd) { rc = acpuclk_set_vdd_level(tgt_s->vdd); @@ -652,10 +673,26 @@ static void __init lpj_init(void) } } +#ifdef CONFIG_MSM_CPU_AVS +static int __init acpu_avs_init(int (*set_vdd) (int), int khz) +{ + int i; + int freq_count = 0; + int freq_index = -1; + + for (i = 0; acpu_freq_tbl[i].a11clk_khz; i++) { + freq_count++; + if (acpu_freq_tbl[i].a11clk_khz == khz) + freq_index = i; + } + + return avs_init(set_vdd, freq_count, freq_index); +} +#endif + void __init msm_acpu_clock_init(struct msm_acpu_clock_platform_data *clkdata) { mutex_init(&drv_state.lock); - drv_state.acpu_switch_time_us = clkdata->acpu_switch_time_us; drv_state.max_speed_delta_khz = clkdata->max_speed_delta_khz; drv_state.vdd_switch_time_us = clkdata->vdd_switch_time_us; @@ -671,5 +708,11 @@ void __init msm_acpu_clock_init(struct msm_acpu_clock_platform_data *clkdata) cpufreq_table_init(); cpufreq_frequency_table_get_attr(freq_table, smp_processor_id()); #endif - +#ifdef CONFIG_MSM_CPU_AVS + if (!acpu_avs_init(drv_state.acpu_set_vdd, + drv_state.current_speed->a11clk_khz)) { + /* avs init successful. avs will handle voltage changes */ + drv_state.acpu_set_vdd = NULL; + } +#endif } diff --git a/arch/arm/mach-msm/avs.c b/arch/arm/mach-msm/avs.c new file mode 100644 index 000000000000..297d3e1a4d52 --- /dev/null +++ b/arch/arm/mach-msm/avs.c @@ -0,0 +1,323 @@ +/* + * Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "avs.h" + +#define AVSDSCR_INPUT 0x01004860 /* magic # from circuit designer */ +#define TSCSR_INPUT 0x00000001 /* enable temperature sense */ + +#define TEMPRS 16 /* total number of temperature regions */ +#define GET_TEMPR() (avs_get_tscsr() >> 28) /* scale TSCSR[CTEMP] to regions */ + +struct mutex avs_lock; + +static struct avs_state_s +{ + u32 freq_cnt; /* Frequencies supported list */ + short *avs_v; /* Dyanmically allocated storage for + * 2D table of voltages over temp & + * freq. Used as a set of 1D tables. + * Each table is for a single temp. + * For usage see avs_get_voltage + */ + int (*set_vdd) (int); /* Function Ptr for setting voltage */ + int changing; /* Clock frequency is changing */ + u32 freq_idx; /* Current frequency index */ + int vdd; /* Current ACPU voltage */ +} avs_state; + +/* + * Update the AVS voltage vs frequency table, for current temperature + * Adjust based on the AVS delay circuit hardware status + */ +static void avs_update_voltage_table(short *vdd_table) +{ + u32 avscsr; + int cpu; + int vu; + int l2; + int i; + u32 cur_freq_idx; + short cur_voltage; + + cur_freq_idx = avs_state.freq_idx; + cur_voltage = avs_state.vdd; + + avscsr = avs_test_delays(); + AVSDEBUG("avscsr=%x, avsdscr=%x\n", avscsr, avs_get_avsdscr()); + + /* + * Read the results for the various unit's AVS delay circuits + * 2=> up, 1=>down, 0=>no-change + */ + cpu = ((avscsr >> 23) & 2) + ((avscsr >> 16) & 1); + vu = ((avscsr >> 28) & 2) + ((avscsr >> 21) & 1); + l2 = ((avscsr >> 29) & 2) + ((avscsr >> 22) & 1); + + if ((cpu == 3) || (vu == 3) || (l2 == 3)) { + printk(KERN_ERR "AVS: Dly Synth O/P error\n"); + } else if ((cpu == 2) || (l2 == 2) || (vu == 2)) { + /* + * even if one oscillator asks for up, increase the voltage, + * as its an indication we are running outside the + * critical acceptable range of v-f combination. + */ + AVSDEBUG("cpu=%d l2=%d vu=%d\n", cpu, l2, vu); + AVSDEBUG("Voltage up at %d\n", cur_freq_idx); + + if (cur_voltage >= VOLTAGE_MAX) + printk(KERN_ERR + "AVS: Voltage can not get high enough!\n"); + + /* Raise the voltage for all frequencies */ + for (i = 0; i < avs_state.freq_cnt; i++) { + vdd_table[i] = cur_voltage + VOLTAGE_STEP; + if (vdd_table[i] > VOLTAGE_MAX) + vdd_table[i] = VOLTAGE_MAX; + } + } else if ((cpu == 1) && (l2 == 1) && (vu == 1)) { + if ((cur_voltage - VOLTAGE_STEP >= VOLTAGE_MIN) && + (cur_voltage <= vdd_table[cur_freq_idx])) { + vdd_table[cur_freq_idx] = cur_voltage - VOLTAGE_STEP; + AVSDEBUG("Voltage down for %d and lower levels\n", + cur_freq_idx); + + /* clamp to this voltage for all lower levels */ + for (i = 0; i < cur_freq_idx; i++) { + if (vdd_table[i] > vdd_table[cur_freq_idx]) + vdd_table[i] = vdd_table[cur_freq_idx]; + } + } + } +} + +/* + * Return the voltage for the target performance freq_idx and optionally + * use AVS hardware to check the present voltage freq_idx + */ +static short avs_get_target_voltage(int freq_idx, bool update_table) +{ + unsigned cur_tempr = GET_TEMPR(); + unsigned temp_index = cur_tempr*avs_state.freq_cnt; + + /* Table of voltages vs frequencies for this temp */ + short *vdd_table = avs_state.avs_v + temp_index; + + if (update_table) + avs_update_voltage_table(vdd_table); + + return vdd_table[freq_idx]; +} + + +/* + * Set the voltage for the freq_idx and optionally + * use AVS hardware to update the voltage + */ +static int avs_set_target_voltage(int freq_idx, bool update_table) +{ + int rc = 0; + int new_voltage = avs_get_target_voltage(freq_idx, update_table); + if (avs_state.vdd != new_voltage) { + AVSDEBUG("AVS setting V to %d mV @%d\n", + new_voltage, freq_idx); + rc = avs_state.set_vdd(new_voltage); + if (rc) + return rc; + avs_state.vdd = new_voltage; + } + return rc; +} + +/* + * Notify avs of clk frquency transition begin & end + */ +int avs_adjust_freq(u32 freq_idx, int begin) +{ + int rc = 0; + + if (!avs_state.set_vdd) { + /* AVS not initialized */ + return 0; + } + + if (freq_idx >= avs_state.freq_cnt) { + AVSDEBUG("Out of range :%d\n", freq_idx); + return -EINVAL; + } + + mutex_lock(&avs_lock); + if ((begin && (freq_idx > avs_state.freq_idx)) || + (!begin && (freq_idx < avs_state.freq_idx))) { + /* Update voltage before increasing frequency & + * after decreasing frequency + */ + rc = avs_set_target_voltage(freq_idx, 0); + if (rc) + goto aaf_out; + + avs_state.freq_idx = freq_idx; + } + avs_state.changing = begin; +aaf_out: + mutex_unlock(&avs_lock); + + return rc; +} + + +static struct delayed_work avs_work; +static struct workqueue_struct *kavs_wq; +#define AVS_DELAY ((CONFIG_HZ * 50 + 999) / 1000) + +static void do_avs_timer(struct work_struct *work) +{ + int cur_freq_idx; + + mutex_lock(&avs_lock); + if (!avs_state.changing) { + /* Only adjust the voltage if clk is stable */ + cur_freq_idx = avs_state.freq_idx; + avs_set_target_voltage(cur_freq_idx, 1); + } + mutex_unlock(&avs_lock); + queue_delayed_work_on(0, kavs_wq, &avs_work, AVS_DELAY); +} + + +static void __init avs_timer_init(void) +{ + INIT_DELAYED_WORK_DEFERRABLE(&avs_work, do_avs_timer); + queue_delayed_work_on(0, kavs_wq, &avs_work, AVS_DELAY); +} + +static void __exit avs_timer_exit(void) +{ + cancel_delayed_work(&avs_work); +} + +static int __init avs_work_init(void) +{ + kavs_wq = create_workqueue("avs"); + if (!kavs_wq) { + printk(KERN_ERR "AVS initialization failed\n"); + return -EFAULT; + } + avs_timer_init(); + + return 1; +} + +static void __exit avs_work_exit(void) +{ + avs_timer_exit(); + destroy_workqueue(kavs_wq); +} + +int __init avs_init(int (*set_vdd)(int), u32 freq_cnt, u32 freq_idx) +{ + int i; + + mutex_init(&avs_lock); + + if (freq_cnt == 0) + return -EINVAL; + + avs_state.freq_cnt = freq_cnt; + + if (freq_idx >= avs_state.freq_cnt) + return -EINVAL; + + avs_state.avs_v = kmalloc(TEMPRS * avs_state.freq_cnt * + sizeof(avs_state.avs_v[0]), GFP_KERNEL); + + if (avs_state.avs_v == 0) + return -ENOMEM; + + for (i = 0; i < TEMPRS*avs_state.freq_cnt; i++) + avs_state.avs_v[i] = VOLTAGE_MAX; + + avs_reset_delays(AVSDSCR_INPUT); + avs_set_tscsr(TSCSR_INPUT); + + avs_state.set_vdd = set_vdd; + avs_state.changing = 0; + avs_state.freq_idx = -1; + avs_state.vdd = -1; + avs_adjust_freq(freq_idx, 0); + + avs_work_init(); + + return 0; +} + +void __exit avs_exit() +{ + avs_work_exit(); + + kfree(avs_state.avs_v); +} + + diff --git a/arch/arm/mach-msm/avs.h b/arch/arm/mach-msm/avs.h new file mode 100644 index 000000000000..daae78938297 --- /dev/null +++ b/arch/arm/mach-msm/avs.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef AVS_H +#define AVS_H + +#define VOLTAGE_MIN 1000 /* mV */ +#define VOLTAGE_MAX 1250 +#define VOLTAGE_STEP 25 + +int __init avs_init(int (*set_vdd)(int), u32 freq_cnt, u32 freq_idx); +void __exit avs_exit(void); + +int avs_adjust_freq(u32 freq_index, int begin); + +/* Routines exported from avs_hw.S */ +u32 avs_test_delays(void); +u32 avs_reset_delays(u32 avsdscr); +u32 avs_get_avscsr(void); +u32 avs_get_avsdscr(void); +u32 avs_get_tscsr(void); +void avs_set_tscsr(u32 to_tscsr); + +/*#define AVSDEBUG(x...) pr_info("AVS: " x);*/ +#define AVSDEBUG(...) + +#endif /* AVS_H */ diff --git a/arch/arm/mach-msm/avs_hw.S b/arch/arm/mach-msm/avs_hw.S new file mode 100644 index 000000000000..57521b60d8f0 --- /dev/null +++ b/arch/arm/mach-msm/avs_hw.S @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + + .text + + .global avs_test_delays +avs_test_delays: + +/* Read r1=CPMR and enable Never Sleep for VSLPDLY */ + mrc p15, 7, r1, c15, c0, 5 + orr r12, r1, #3, 24 + mcr p15, 7, r12, c15, c0, 5 + +/* Read r2=CPACR and enable full access to CP10 and CP11 space */ + mrc p15, 0, r2, c1, c0, 2 + orr r12, r2, #(0xf << 20) + mcr p15, 0, r12, c1, c0, 2 + isb + +/* Read r3=FPEXC and or in FP enable, VFP/ASE enable = FPEXC[30]; */ + fmrx r3, fpexc + orr r12, r3, #1, 2 + fmxr fpexc, r12 + +/* + * Do floating-point operations to prime the VFP pipeline. Use + * fcpyd d0, d0 as a floating point nop. This avoids changing VFP + * state. + */ + fcpyd d0, d0 + fcpyd d0, d0 + fcpyd d0, d0 + +/* Read r0=AVSCSR to get status from CPU, VFP, and L2 ring oscillators */ + mrc p15, 7, r0, c15, c1, 7 + +/* Restore FPEXC */ + fmxr fpexc, r3 + +/* Restore CPACR */ + MCR p15, 0, r2, c1, c0, 2 + +/* Restore CPMR */ + mcr p15, 7, r1, c15, c0, 5 + isb + + bx lr + + + + + .global avs_get_avscsr +/* Read r0=AVSCSR to get status from CPU, VFP, and L2 ring oscillators */ + +avs_get_avscsr: + mrc p15, 7, r0, c15, c1, 7 + bx lr + + .global avs_get_avsdscr +/* Read r0=AVSDSCR to get the AVS Delay Synthesizer control settings */ + +avs_get_avsdscr: + mrc p15, 7, r0, c15, c0, 6 + bx lr + + + + + .global avs_get_tscsr +/* Read r0=TSCSR to get temperature sensor control and status */ + +avs_get_tscsr: + mrc p15, 7, r0, c15, c1, 0 + bx lr + + .global avs_set_tscsr +/* Write TSCSR=r0 to set temperature sensor control and status */ + +avs_set_tscsr: + mcr p15, 7, r0, c15, c1, 0 + bx lr + + + + + + .global avs_reset_delays +avs_reset_delays: + +/* AVSCSR(0x61) to enable CPU, V and L2 AVS module */ + mov r3, #0x61 + mcr p15, 7, r3, c15, c1, 7 + +/* AVSDSCR(dly) to program delay */ + mcr p15, 7, r0, c15, c0, 6 + +/* Read r0=AVSDSCR */ + mrc p15, 7, r0, c15, c0, 6 + + bx lr + + .end + + diff --git a/arch/arm/mach-msm/idle-v7.S b/arch/arm/mach-msm/idle-v7.S index 66f69f879beb..588062813e78 100644 --- a/arch/arm/mach-msm/idle-v7.S +++ b/arch/arm/mach-msm/idle-v7.S @@ -40,6 +40,17 @@ ENTRY(msm_pm_collapse) mrc p15, 0, r9, c13, c0, 3 /* TPIDRURO */ mrc p15, 0, ip, c13, c0, 1 /* context ID */ stmia r0!, {r1-r9, ip} +#ifdef CONFIG_MSM_CPU_AVS + mrc p15, 7, r1, c15, c1, 7 /* AVSCSR is the Adaptive Voltage Scaling + * Control and Status Register */ + mrc p15, 7, r2, c15, c0, 6 /* AVSDSCR is the Adaptive Voltage + * Scaling Delay Synthesizer Control + * Register */ + mrc p15, 7, r3, c15, c1, 0 /* TSCSR is the Temperature Status and + * Control Register + */ + stmia r0!, {r1-r3} +#endif #ifdef CONFIG_MSM_JTAG_V7 bl msm_save_jtag_debug @@ -81,6 +92,12 @@ ENTRY(msm_pm_collapse_exit) adr r3, msm_pm_collapse_exit add r1, r1, r3 sub r1, r1, r2 +#ifdef CONFIG_MSM_CPU_AVS + ldmdb r1!, {r2-r4} + mcr p15, 7, r4, c15, c1, 0 /* TSCSR */ + mcr p15, 7, r3, c15, c0, 6 /* AVSDSCR */ + mcr p15, 7, r2, c15, c1, 7 /* AVSCSR */ +#endif ldmdb r1!, {r2-r11} mcr p15, 0, r4, c3, c0, 0 /* dacr */ mcr p15, 0, r3, c2, c0, 0 /* TTBR0 */ @@ -150,6 +167,9 @@ msm_pm_pa_to_va: saved_state: .space 4 * 11 /* r4-14 */ .space 4 * 10 /* cp15 */ +#ifdef CONFIG_MSM_CPU_AVS + .space 4 * 3 /* AVS control registers */ +#endif saved_state_end: -- cgit v1.2.3 From 71edfb6b255009fba159c7704a92002f5f82b022 Mon Sep 17 00:00:00 2001 From: Lena Salman Date: Tue, 29 Sep 2009 10:40:00 +0200 Subject: msm: dma: Add crypto engine DM channels. SPI core can use crypto channels as predetermined by the SPI mux value. Since SPI core doesn't own its own channels, the mux will determine which channels it will take - crypto, uart1 or uart2. Signed-off-by: Lena Salman --- arch/arm/mach-msm/include/mach/dma.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/include/mach/dma.h b/arch/arm/mach-msm/include/mach/dma.h index 76b545c7e725..7a2fc563333b 100644 --- a/arch/arm/mach-msm/include/mach/dma.h +++ b/arch/arm/mach-msm/include/mach/dma.h @@ -85,6 +85,12 @@ int msm_dmov_exec_cmd(unsigned id, unsigned int cmdptr); #define DMOV_GP_CHAN 4 +#define DMOV_CE_IN_CHAN 5 +#define DMOV_CE_IN_CRCI 1 + +#define DMOV_CE_OUT_CHAN 6 +#define DMOV_CE_OUT_CRCI 2 + #define DMOV_NAND_CHAN 7 #define DMOV_NAND_CRCI_CMD 5 #define DMOV_NAND_CRCI_DATA 4 -- cgit v1.2.3 From cc19fdb3d81eb42e306e072729617dfa93829660 Mon Sep 17 00:00:00 2001 From: Ramesh Garimella Date: Thu, 24 Sep 2009 18:32:33 +0530 Subject: msm: dma_test: allocate minor number dynamically CRs-Fixed: 210475 Signed-off-by: Ramesh Garimella --- arch/arm/mach-msm/dma_test.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/dma_test.c b/arch/arm/mach-msm/dma_test.c index ecde8e3ae8a0..c4967f97f832 100644 --- a/arch/arm/mach-msm/dma_test.c +++ b/arch/arm/mach-msm/dma_test.c @@ -360,7 +360,6 @@ static int dma_test_ioctl(struct inode *inode, struct file *file, /********************************************************************** * Register ourselves as a misc device to be able to test the DMA code * from userspace. */ -#define MSM_DMOV_MINOR 32 static const struct file_operations dma_test_fops = { .owner = THIS_MODULE, @@ -370,7 +369,7 @@ static const struct file_operations dma_test_fops = { }; static struct miscdevice dma_test_dev = { - .minor = MSM_DMOV_MINOR, + .minor = MISC_DYNAMIC_MINOR, .name = "msmdma", .fops = &dma_test_fops, }; -- cgit v1.2.3 From efdf12849ddea4917dfc6a3dfdac89fce4fc113f Mon Sep 17 00:00:00 2001 From: Matt Wagantall Date: Tue, 15 Sep 2009 13:39:25 -0700 Subject: msm: Add API for clock power rail control using proc_comm Previously, an API did not exist to control power rails independent of clocks. The new API provides this functionality using two exported interfaces: int internal_pwr_rail_ctl(unsigned rail_id, bool enable); int internal_pwr_rail_mode(unsigned rail_id, enum rail_ctl_mode mode); where mode is either PWR_RAIL_CONTROL_AUTO or PWR_RAIL_CONTROL_MANUAL. If the control mode is never set, the rail will be controlled automatically (ie. turned on and off with the clock). Signed-off-by: Matt Wagantall --- arch/arm/mach-msm/Makefile | 1 + .../mach-msm/include/mach/internal_power_rail.h | 45 +++++++++++ arch/arm/mach-msm/internal_power_rail.c | 90 ++++++++++++++++++++++ 3 files changed, 136 insertions(+) create mode 100644 arch/arm/mach-msm/include/mach/internal_power_rail.h create mode 100644 arch/arm/mach-msm/internal_power_rail.c (limited to 'arch') diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 12c68ff2ebf6..4d5d8ea03041 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -12,6 +12,7 @@ obj-y += socinfo.o obj-y += cpufreq.o obj-y += nohlt.o obj-y += pmic.o +obj-y += internal_power_rail.o obj-$(CONFIG_ARCH_MSM_ARM11) += acpuclock.o obj-$(CONFIG_ARCH_MSM_SCORPION) += acpuclock-8x50.o diff --git a/arch/arm/mach-msm/include/mach/internal_power_rail.h b/arch/arm/mach-msm/include/mach/internal_power_rail.h new file mode 100644 index 000000000000..1170771ac3bd --- /dev/null +++ b/arch/arm/mach-msm/include/mach/internal_power_rail.h @@ -0,0 +1,45 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _INTERNAL_POWER_RAIL_H +#define _INTERNAL_POWER_RAIL_H + +/* Clock power rail IDs */ +#define PWR_RAIL_GRP_CLK 8 +#define PWR_RAIL_VDC_CLK 39 +#define PWR_RAIL_VFE_CLK 41 + +enum rail_ctl_mode { + PWR_RAIL_CTL_AUTO = 0, + PWR_RAIL_CTL_MANUAL, +}; + +int internal_pwr_rail_ctl(unsigned rail_id, bool enable); +int internal_pwr_rail_mode(unsigned rail_id, enum rail_ctl_mode mode); + +#endif /* _INTERNAL_POWER_RAIL_H */ + diff --git a/arch/arm/mach-msm/internal_power_rail.c b/arch/arm/mach-msm/internal_power_rail.c new file mode 100644 index 000000000000..c2c5e5bed9ce --- /dev/null +++ b/arch/arm/mach-msm/internal_power_rail.c @@ -0,0 +1,90 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include + +#include + +#include "proc_comm.h" + +/* Enable or disable an internal power rail */ +int internal_pwr_rail_ctl(unsigned rail_id, bool enable) +{ + int cmd, rc; + + cmd = enable ? PCOM_CLKCTL_RPC_RAIL_ENABLE : + PCOM_CLKCTL_RPC_RAIL_DISABLE; + + rc = msm_proc_comm(cmd, &rail_id, NULL); + + return rc; + +} +EXPORT_SYMBOL(internal_pwr_rail_ctl); + +/* Specify an internal power rail control mode (ex. auto, manual) */ +int internal_pwr_rail_mode(unsigned rail_id, enum rail_ctl_mode mode) +{ + int rc; + + rc = msm_proc_comm(PCOM_CLKCTL_RPC_RAIL_CONTROL, &rail_id, &mode); + + return rc; +} +EXPORT_SYMBOL(internal_pwr_rail_mode); + -- cgit v1.2.3 From 05a79dd7579677b8305492a2452caed7522f7f56 Mon Sep 17 00:00:00 2001 From: Ai Li Date: Mon, 31 Aug 2009 12:11:59 -0600 Subject: msm: clear SMSM interrupt masks during initialization By the time power collapse or time sync occurs, kernel has already disabled interrupts. Both power collapse and time sync protocols poll for the SMSM bit changes. Clear the SMSM masks so that Modem don't bother sending the unnecessary interrupts. Signed-off-by: Ai Li --- arch/arm/mach-msm/pm2.c | 12 ++++++++++++ arch/arm/mach-msm/timer.c | 15 +++++++++++++++ arch/arm/mach-msm/timer.h | 2 +- 3 files changed, 28 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/pm2.c b/arch/arm/mach-msm/pm2.c index ff096495397a..c8f4334b0f8d 100644 --- a/arch/arm/mach-msm/pm2.c +++ b/arch/arm/mach-msm/pm2.c @@ -1613,6 +1613,7 @@ static int __init msm_pm_init(void) #ifdef CONFIG_MSM_IDLE_STATS struct proc_dir_entry *d_entry; #endif + int ret; pm_power_off = msm_pm_power_off; arm_pm_restart = msm_pm_restart; @@ -1641,6 +1642,17 @@ static int __init msm_pm_init(void) } #endif /* CONFIG_ARCH_MSM_SCORPION */ + ret = msm_timer_init_time_sync(); + if (ret) + return ret; + + ret = smsm_change_intr_mask(SMSM_POWER_MASTER_DEM, 0xFFFFFFFF, 0); + if (ret) { + printk(KERN_ERR "%s: failed to clear interrupt mask, %d\n", + __func__, ret); + return ret; + } + BUG_ON(msm_pm_modes == NULL); atomic_set(&msm_pm_init_done, 1); diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c index fdbad01556bf..f1aafd7dbf86 100644 --- a/arch/arm/mach-msm/timer.c +++ b/arch/arm/mach-msm/timer.c @@ -624,6 +624,21 @@ int64_t msm_timer_get_smem_clock_time(int64_t *period) return tmp; } +int __init msm_timer_init_time_sync(void) +{ +#if defined(CONFIG_MSM_N_WAY_SMSM) + int ret = smsm_change_intr_mask(SMSM_TIME_MASTER_DEM, 0xFFFFFFFF, 0); + + if (ret) { + printk(KERN_ERR "%s: failed to clear interrupt mask, %d\n", + __func__, ret); + return ret; + } +#endif + + return 0; +} + unsigned long long sched_clock(void) { static cycle_t saved_ticks; diff --git a/arch/arm/mach-msm/timer.h b/arch/arm/mach-msm/timer.h index 196a3ebab874..26d20a776160 100644 --- a/arch/arm/mach-msm/timer.h +++ b/arch/arm/mach-msm/timer.h @@ -34,5 +34,5 @@ extern struct sys_timer msm_timer; int64_t msm_timer_enter_idle(void); void msm_timer_exit_idle(int low_power); int64_t msm_timer_get_smem_clock_time(int64_t *period); - +int msm_timer_init_time_sync(void); #endif -- cgit v1.2.3 From e8c97155d903b1a630c8c19b0a3c25c8cd8aa365 Mon Sep 17 00:00:00 2001 From: Ai Li Date: Mon, 31 Aug 2009 12:33:55 -0600 Subject: msm: timer: set SMSM bits for time sync during initialization Setting the bits during initialization also removes the need to set them again during each power collapse. Signed-off-by: Ai Li --- arch/arm/mach-msm/pm2.c | 9 --------- arch/arm/mach-msm/timer.c | 25 +++++++++++++++---------- 2 files changed, 15 insertions(+), 19 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/pm2.c b/arch/arm/mach-msm/pm2.c index c8f4334b0f8d..6ce1b6d883fc 100644 --- a/arch/arm/mach-msm/pm2.c +++ b/arch/arm/mach-msm/pm2.c @@ -838,11 +838,6 @@ write_proc_failed: #define DEM_SLAVE_SMSM_RESET (0x0100) #define DEM_SLAVE_SMSM_PWRC_SUSPEND (0x0200) -/* Time Slave State Bits */ -#define DEM_TIME_SLAVE_TIME_REQUEST (0x0400) -#define DEM_TIME_SLAVE_TIME_POLL (0x0800) -#define DEM_TIME_SLAVE_TIME_INIT (0x1000) - /****************************************************************************** * Shared Memory Data @@ -914,10 +909,6 @@ static int msm_pm_power_collapse msm_pm_smem_data->sleep_time = sleep_delay; msm_pm_smem_data->resources_used = sleep_limit; - smsm_change_state(SMSM_APPS_DEM, - DEM_TIME_SLAVE_TIME_REQUEST | DEM_TIME_SLAVE_TIME_POLL, - DEM_TIME_SLAVE_TIME_INIT); - /* Enter PWRC/PWRC_SUSPEND */ if (from_idle) diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c index f1aafd7dbf86..ba272acbd4a5 100644 --- a/arch/arm/mach-msm/timer.c +++ b/arch/arm/mach-msm/timer.c @@ -64,6 +64,18 @@ module_param_named(debug_mask, msm_timer_debug_mask, int, S_IRUGO | S_IWUSR | S_ #endif #define SCLK_HZ 32768 +#if defined(CONFIG_MSM_N_WAY_SMSM) +/* Time Master State Bits */ +#define MASTER_BITS_PER_CPU 1 +#define MASTER_TIME_PENDING \ + (0x01UL << (MASTER_BITS_PER_CPU * SMSM_APPS_STATE)) + +/* Time Slave State Bits */ +#define SLAVE_TIME_REQUEST 0x0400 +#define SLAVE_TIME_POLL 0x0800 +#define SLAVE_TIME_INIT 0x1000 +#endif + enum { MSM_CLOCK_FLAGS_UNSTABLE_COUNT = 1U << 0, MSM_CLOCK_FLAGS_ODD_MATCH_WRITE = 1U << 1, @@ -243,16 +255,6 @@ static uint32_t msm_timer_sync_sclk( void (*update)(struct msm_timer_sync_data_t *data, uint32_t clk_val), struct msm_timer_sync_data_t *data) { - /* Time Master State Bits */ - #define MASTER_BITS_PER_CPU 1 - #define MASTER_TIME_PENDING \ - (0x01UL << (MASTER_BITS_PER_CPU * SMSM_APPS_STATE)) - - /* Time Slave State Bits */ - #define SLAVE_TIME_REQUEST 0x0400 - #define SLAVE_TIME_POLL 0x0800 - #define SLAVE_TIME_INIT 0x1000 - uint32_t *smem_clock; uint32_t smem_clock_val; uint32_t state; @@ -634,6 +636,9 @@ int __init msm_timer_init_time_sync(void) __func__, ret); return ret; } + + smsm_change_state(SMSM_APPS_DEM, + SLAVE_TIME_REQUEST | SLAVE_TIME_POLL, SLAVE_TIME_INIT); #endif return 0; -- cgit v1.2.3 From 16418f154dc7b6e6dcda5b340cdedc2cb0c666aa Mon Sep 17 00:00:00 2001 From: Matt Wagantall Date: Fri, 25 Sep 2009 11:43:10 -0700 Subject: msm: clock: Add camera clocks to 7x30 clock list Signed-off-by: Matt Wagantall --- arch/arm/mach-msm/devices.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/devices.c b/arch/arm/mach-msm/devices.c index c9417d00da51..0fcea3aa4368 100644 --- a/arch/arm/mach-msm/devices.c +++ b/arch/arm/mach-msm/devices.c @@ -544,6 +544,8 @@ unsigned msm_num_clocks_7x27 = ARRAY_SIZE(msm_clocks_7x27); struct clk msm_clocks_7x30[] = { CLK_PCOM("adm_clk", ADM_CLK, NULL, 0), CLK_PCOM("adsp_clk", ADSP_CLK, NULL, 0), + CLK_PCOM("cam_mclk_clk", CAM_MCLK_CLK, NULL, OFF), + CLK_PCOM("camif_pad_pclk", CAMIF_PAD_PCLK, NULL, OFF), CLK_PCOM("ebi1_clk", EBI1_CLK, NULL, CLK_MIN), CLK_PCOM("ebi2_clk", EBI2_CLK, NULL, 0), CLK_PCOM("ecodec_clk", ECODEC_CLK, NULL, 0), @@ -590,8 +592,10 @@ struct clk msm_clocks_7x30[] = { CLK_PCOM("usb_hs3_core_clk", USB_HS3_CORE_CLK, NULL, OFF), CLK_PCOM("usb_otg_clk", USB_OTG_CLK, NULL, 0), CLK_PCOM("vdc_clk", VDC_CLK, NULL, OFF | CLK_MIN), + CLK_PCOM("vfe_camif_clk", VFE_CAMIF_CLK, NULL, OFF), CLK_PCOM("vfe_clk", VFE_CLK, NULL, OFF), CLK_PCOM("vfe_mdc_clk", VFE_MDC_CLK, NULL, OFF), + CLK_PCOM("vfe_pclk", VFE_PCLK, NULL, 0), CLK_PCOM("grp_pclk", GRP_PCLK, NULL, 0), CLK_PCOM("lpa_codec_clk", LPA_CODEC_CLK, NULL, 0), CLK_PCOM("lpa_core_clk", LPA_CORE_CLK, NULL, 0), -- cgit v1.2.3 From 73e31c80ea59f65bc60907a7efa4733c87478b8c Mon Sep 17 00:00:00 2001 From: "Ruigrok, Richard" Date: Fri, 2 Oct 2009 14:26:02 -0600 Subject: msm: smd_rpcrouter: fix bug in pacmark messages sequence. Bug in router causes packet corruption with multiple packet message is pre-empted with a 2nd write of single packet message. The first message (A) being a multi-packet message is started. which contains packet A1 and A2. A second message (B) is sent during the write sequence of message (A) between A1 and A2 packets. In the buggy version, the packet (B1) would use the same MID as (A1) and would cause message (A) to be corrupted at the far end when re-assembled. Also more, the last packet of (A2) would have a different mid, causing the far-end to never receive the completed message. The failures caused by sending an ill-formatted packet at the far-end are undeterministic. On the local end, The user-space thread will be locked as no reply will be received. CRs-fixed: 211851 Signed-off-by: Richard Ruigrok --- arch/arm/mach-msm/smd_rpcrouter.c | 39 ++++++++++++++++++--------------------- arch/arm/mach-msm/smd_rpcrouter.h | 1 - 2 files changed, 18 insertions(+), 22 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/smd_rpcrouter.c b/arch/arm/mach-msm/smd_rpcrouter.c index b3cee4078c3f..eb69670e2b24 100644 --- a/arch/arm/mach-msm/smd_rpcrouter.c +++ b/arch/arm/mach-msm/smd_rpcrouter.c @@ -143,6 +143,7 @@ static DEFINE_SPINLOCK(smd_lock); static struct workqueue_struct *rpcrouter_workqueue; static atomic_t next_xid = ATOMIC_INIT(1); +static atomic_t pm_mid = ATOMIC_INIT(1); static void do_read_data(struct work_struct *work); static void do_create_pdevs(struct work_struct *work); @@ -886,8 +887,8 @@ static void do_read_data(struct work_struct *work) xid, pm >> 30 & 0x1, pm >> 31 & 0x1, - pm >> 16 & 0xF, - pm & 0xFF, hdr.dst_cid); + pm >> 16 & 0xFF, + pm & 0xFFFF, hdr.dst_cid); } if (smd_rpcrouter_debug_mask & SMEM_LOG) { @@ -1022,7 +1023,8 @@ static int msm_rpc_write_pkt( void *buffer, int count, int first, - int last + int last, + uint32_t mid ) { #if defined(CONFIG_MSM_ONCRPCROUTER_DEBUG) @@ -1115,15 +1117,7 @@ static int msm_rpc_write_pkt( #endif } - - /* bump pacmark while interrupts disabled to avoid race - * probably should be atomic op instead - */ - /* Pacmark maintained by ept and incremented for next - * messages when last fragment is set. - */ - pacmark = PACMARK(count, ept->next_pm, first, last); - ept->next_pm += last; + pacmark = PACMARK(count, mid, first, last); spin_unlock_irqrestore(&r_ept->quota_lock, flags); @@ -1173,8 +1167,8 @@ static int msm_rpc_write_pkt( xid, pacmark >> 30 & 0x1, pacmark >> 31 & 0x1, - pacmark >> 16 & 0xF, - pacmark & 0xFF, hdr->src_cid); + pacmark >> 16 & 0xFF, + pacmark & 0xFFFF, hdr->src_cid); } #endif @@ -1302,6 +1296,7 @@ int msm_rpc_write(struct msm_rpc_endpoint *ept, void *buffer, int count) char *tx_buf; int rc; int first_pkt = 1; + uint32_t mid; /* snoop the RPC packet and enforce permissions */ @@ -1364,7 +1359,7 @@ int msm_rpc_write(struct msm_rpc_endpoint *ept, void *buffer, int count) tx_cnt = count; tx_buf = buffer; - + mid = atomic_add_return(1, &pm_mid) & 0xFF; /* The modem's router can only take 500 bytes of data. The first 8 bytes it uses on the modem side for addressing, the next 4 bytes are for the pacmark header. */ @@ -1374,18 +1369,22 @@ int msm_rpc_write(struct msm_rpc_endpoint *ept, void *buffer, int count) while (tx_cnt > 0) { if (tx_cnt > max_tx) { rc = msm_rpc_write_pkt(&hdr, ept, r_ept, - tx_buf, max_tx, first_pkt, 0); + tx_buf, max_tx, + first_pkt, 0, mid); if (rc < 0) return rc; - IO("Wrote %d bytes First %d, Last 0\n", rc, first_pkt); + IO("Wrote %d bytes First %d, Last 0 mid %d\n", + rc, first_pkt, mid); tx_cnt -= max_tx; tx_buf += max_tx; } else { rc = msm_rpc_write_pkt(&hdr, ept, r_ept, - tx_buf, tx_cnt, first_pkt, 1); + tx_buf, tx_cnt, + first_pkt, 1, mid); if (rc < 0) return rc; - IO("Wrote %d bytes First %d Last 1 \n", rc, first_pkt); + IO("Wrote %d bytes First %d Last 1 mid %d\n", + rc, first_pkt, mid); break; } first_pkt = 0; @@ -2101,8 +2100,6 @@ static int dump_msm_rpc_endpoint(char *buf, int max) be32_to_cpu(ept->dst_vers)); i += scnprintf(buf + i, max - i, "reply_cnt: %i\n", ept->reply_cnt); - i += scnprintf(buf + i, max - i, "next_pm: %i\n", - ept->next_pm); i += scnprintf(buf + i, max - i, "restart_state: %i\n", ept->restart_state); diff --git a/arch/arm/mach-msm/smd_rpcrouter.h b/arch/arm/mach-msm/smd_rpcrouter.h index f8975336a359..dfdd51492f08 100644 --- a/arch/arm/mach-msm/smd_rpcrouter.h +++ b/arch/arm/mach-msm/smd_rpcrouter.h @@ -183,7 +183,6 @@ struct msm_rpc_endpoint { struct list_head reply_avail_q; spinlock_t reply_q_lock; uint32_t reply_cnt; - uint32_t next_pm; /* Pacmark sequence */ /* device node if this endpoint is accessed via userspace */ dev_t dev; -- cgit v1.2.3 From 5957c15e16b21e2fbad4d434ab71af80c0762f88 Mon Sep 17 00:00:00 2001 From: Matt Wagantall Date: Wed, 16 Sep 2009 10:03:56 -0700 Subject: msm: timer: Fix 7x30 debug timer register offsets and clock source The debug timer's register addresses are corrected. To avoid future confusion, the MSM_GPT_* iomap macros are renamed to MSM_TMR_*. This clarifies that they represent the address of the first timer register, which is not necessarily the first GPT register on all targets. Additionally, the debug timer frequency is changed to 24.576 MHz, since the 7x30 uses LPXO as its debug timer clock source. Signed-off-by: Matt Wagantall --- arch/arm/mach-msm/include/mach/msm_iomap.h | 6 +++--- arch/arm/mach-msm/io.c | 8 ++++---- arch/arm/mach-msm/timer.c | 26 +++++++++++--------------- 3 files changed, 18 insertions(+), 22 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/include/mach/msm_iomap.h b/arch/arm/mach-msm/include/mach/msm_iomap.h index 68c2b5ae73dc..6ea60e0872d2 100644 --- a/arch/arm/mach-msm/include/mach/msm_iomap.h +++ b/arch/arm/mach-msm/include/mach/msm_iomap.h @@ -62,9 +62,9 @@ #endif #define MSM_CSR_SIZE SZ_4K -#define MSM_GPT_PHYS MSM_CSR_PHYS -#define MSM_GPT_BASE MSM_CSR_BASE -#define MSM_GPT_SIZE SZ_4K +#define MSM_TMR_PHYS MSM_CSR_PHYS +#define MSM_TMR_BASE MSM_CSR_BASE +#define MSM_TMR_SIZE SZ_4K #define MSM_DMOV_BASE IOMEM(0xE0002000) #if defined(CONFIG_ARCH_MSM7X30) diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c index 830eb43f5bc1..e0375c7ea0a2 100644 --- a/arch/arm/mach-msm/io.c +++ b/arch/arm/mach-msm/io.c @@ -57,7 +57,7 @@ static void msm_map_io(struct map_desc *io_desc, int size) static struct map_desc msm_io_desc[] __initdata = { MSM_DEVICE(VIC), MSM_DEVICE(CSR), - MSM_DEVICE(GPT), + MSM_DEVICE(TMR), MSM_DEVICE(DMOV), MSM_DEVICE(GPIO1), MSM_DEVICE(GPIO2), @@ -95,7 +95,7 @@ void __init msm_map_common_io(void) static struct map_desc qsd8x50_io_desc[] __initdata = { MSM_DEVICE(VIC), MSM_DEVICE(CSR), - MSM_DEVICE(GPT), + MSM_DEVICE(TMR), MSM_DEVICE(DMOV), MSM_DEVICE(GPIO1), MSM_DEVICE(GPIO2), @@ -124,7 +124,7 @@ void __init msm_map_qsd8x50_io(void) static struct map_desc msm7x30_io_desc[] __initdata = { MSM_DEVICE(VIC), MSM_DEVICE(CSR), - MSM_DEVICE(GPT), + MSM_DEVICE(TMR), MSM_DEVICE(DMOV), MSM_DEVICE(GPIO1), MSM_DEVICE(GPIO2), @@ -154,7 +154,7 @@ void __init msm_map_msm7x30_io(void) static struct map_desc comet_io_desc[] __initdata = { MSM_DEVICE(VIC), MSM_DEVICE(CSR), - MSM_DEVICE(GPT), + MSM_DEVICE(TMR), MSM_DEVICE(DMOV), MSM_DEVICE(GPIO1), MSM_DEVICE(GPIO2), diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c index ba272acbd4a5..947e1980273a 100644 --- a/arch/arm/mach-msm/timer.c +++ b/arch/arm/mach-msm/timer.c @@ -36,17 +36,12 @@ static int msm_timer_debug_mask; module_param_named(debug_mask, msm_timer_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP); #if defined(CONFIG_ARCH_MSM7X30) -#define MSM_DGT_BASE (MSM_GPT_BASE + 0x24) -#define MSM_DGT_SHIFT (5) - -#define TIMER_MATCH_VAL 0x0004 -#define TIMER_COUNT_VAL 0x0008 -#define TIMER_ENABLE 0x000C -#define TIMER_ENABLE_EN 1 - +#define MSM_GPT_BASE (MSM_TMR_BASE + 0x4) +#define MSM_DGT_BASE (MSM_TMR_BASE + 0x24) #else - -#define MSM_DGT_BASE (MSM_GPT_BASE + 0x10) +#define MSM_GPT_BASE MSM_TMR_BASE +#define MSM_DGT_BASE (MSM_TMR_BASE + 0x10) +#endif #define MSM_DGT_SHIFT (5) #define TIMER_MATCH_VAL 0x0000 @@ -54,14 +49,15 @@ module_param_named(debug_mask, msm_timer_debug_mask, int, S_IRUGO | S_IWUSR | S_ #define TIMER_ENABLE 0x0008 #define TIMER_ENABLE_EN 1 +#if defined(CONFIG_ARCH_QSD8X50) +#define DGT_HZ 4800000 /* Uses TCXO/4 (19.2 MHz / 4) */ +#elif defined(CONFIG_ARCH_MSM7X30) +#define DGT_HZ 6144000 /* Uses LPXO/4 (24.576 MHz / 4) */ +#else +#define DGT_HZ 19200000 /* Uses TCXO (19.2 MHz) */ #endif #define GPT_HZ 32768 -#if defined(CONFIG_ARCH_MSM_SCORPION) -#define DGT_HZ 4800000 /* DGT is run with divider of 4 */ -#else -#define DGT_HZ 19200000 /* 19.2 MHz or 600 KHz after shift */ -#endif #define SCLK_HZ 32768 #if defined(CONFIG_MSM_N_WAY_SMSM) -- cgit v1.2.3 From b6fff107fd1a5cddbfc51ba3cf9aec2d38619c4b Mon Sep 17 00:00:00 2001 From: Matt Wagantall Date: Mon, 5 Oct 2009 17:22:26 -0700 Subject: msm: timer: Remove MSM_DGT_SHIFT for Scorpion processors All 32 bits of Scorpion debug timer "COUNT_VAL" registers are useful, unlike ARM11 debug timers, for which the least-significant bits are unreliable and marked as reserved. Signed-off-by: Matt Wagantall --- arch/arm/mach-msm/timer.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c index 947e1980273a..20a21441c024 100644 --- a/arch/arm/mach-msm/timer.c +++ b/arch/arm/mach-msm/timer.c @@ -42,7 +42,12 @@ module_param_named(debug_mask, msm_timer_debug_mask, int, S_IRUGO | S_IWUSR | S_ #define MSM_GPT_BASE MSM_TMR_BASE #define MSM_DGT_BASE (MSM_TMR_BASE + 0x10) #endif + +#if defined(CONFIG_ARCH_MSM_ARM11) #define MSM_DGT_SHIFT (5) +#else +#define MSM_DGT_SHIFT (0) +#endif #define TIMER_MATCH_VAL 0x0000 #define TIMER_COUNT_VAL 0x0004 -- cgit v1.2.3 From 4848c91b728baa50891f755ef537bbea84edc527 Mon Sep 17 00:00:00 2001 From: "Vishwanathapura, Niranjana" Date: Wed, 7 Oct 2009 14:48:12 -0600 Subject: msm: Handle SMD packets with 0 length Users might call smd_write with lenght 0 in which case SMD should not write anything (including packet header). Also, if SMD receives a 0 length packet from other processor, it should skip it and move on to next packet. CRs-fixed: 212417 Signed-off-by: Niranjana Vishwanathapura --- arch/arm/mach-msm/smd.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c index 0fb8c60a04ee..82596828c7e0 100644 --- a/arch/arm/mach-msm/smd.c +++ b/arch/arm/mach-msm/smd.c @@ -429,17 +429,18 @@ static void update_packet_state(struct smd_channel *ch) int r; /* can't do anything if we're in the middle of a packet */ - if (ch->current_packet != 0) - return; + while (ch->current_packet == 0) { + /* discard 0 length packets if any */ - /* don't bother unless we can get the full header */ - if (smd_stream_read_avail(ch) < SMD_HEADER_SIZE) - return; + /* don't bother unless we can get the full header */ + if (smd_stream_read_avail(ch) < SMD_HEADER_SIZE) + return; - r = ch_read(ch, hdr, SMD_HEADER_SIZE); - BUG_ON(r != SMD_HEADER_SIZE); + r = ch_read(ch, hdr, SMD_HEADER_SIZE); + BUG_ON(r != SMD_HEADER_SIZE); - ch->current_packet = hdr[0]; + ch->current_packet = hdr[0]; + } } /* provide a pointer and length to next free space in the fifo */ @@ -673,6 +674,8 @@ static int smd_stream_write(smd_channel_t *ch, const void *_data, int len) SMD_DBG("smd_stream_write() %d -> ch%d\n", len, ch->n); if (len < 0) return -EINVAL; + else if (len == 0) + return 0; while ((xfer = ch_write_buffer(ch, &ptr)) != 0) { if (!ch_is_open(ch)) @@ -701,6 +704,8 @@ static int smd_packet_write(smd_channel_t *ch, const void *_data, int len) SMD_DBG("smd_packet_write() %d -> ch%d\n", len, ch->n); if (len < 0) return -EINVAL; + else if (len == 0) + return 0; if (smd_stream_write_avail(ch) < (len + SMD_HEADER_SIZE)) return -ENOMEM; -- cgit v1.2.3 From b822bb2ce5b9d8b4b38e38454b4bd16924469ba4 Mon Sep 17 00:00:00 2001 From: "Vishwanathapura, Niranjana" Date: Wed, 7 Oct 2009 15:33:22 -0600 Subject: msm: Add OEM proc comm commands enumeration OEM proc comm commands start from base 0x10000000 Thie update helps OEMs to add their own commands easily. Signed-off-by: Niranjana Vishwanathapura --- arch/arm/mach-msm/proc_comm.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/proc_comm.h b/arch/arm/mach-msm/proc_comm.h index c53e39e47dcd..ca773797dc58 100644 --- a/arch/arm/mach-msm/proc_comm.h +++ b/arch/arm/mach-msm/proc_comm.h @@ -135,7 +135,15 @@ enum { PCOM_CLKCTL_RPC_RAIL_DISABLE, PCOM_CLKCTL_RPC_RAIL_CONTROL, PCOM_CLKCTL_RPC_MIN_MSMC1, - PCOM_NUM_CMDS, +}; + +enum { + PCOM_OEM_FIRST_CMD = 0x10000000, + PCOM_OEM_TEST_CMD = PCOM_OEM_FIRST_CMD, + + /* add OEM PROC COMM commands here */ + + PCOM_OEM_LAST = PCOM_OEM_TEST_CMD, }; enum { -- cgit v1.2.3 From d0837899befbee7435022bf57b13946337e9fc63 Mon Sep 17 00:00:00 2001 From: Michael Bohan Date: Thu, 8 Oct 2009 15:34:19 -0700 Subject: msm: socinfo: Add support for hw_smem v3 Version 3 includes support to show which 'hardware platform' we're runnning on. Current possibilities are SURF, FFA, and Fluid. Signed-off-by: Michael Bohan --- arch/arm/mach-msm/socinfo.c | 169 +++++++++++++++++++++++++++++++++++--------- arch/arm/mach-msm/socinfo.h | 1 + 2 files changed, 136 insertions(+), 34 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c index 2dbd6f6fb5f1..3944347ae506 100644 --- a/arch/arm/mach-msm/socinfo.c +++ b/arch/arm/mach-msm/socinfo.c @@ -64,25 +64,48 @@ #include "socinfo.h" #include "smd_private.h" +enum { + HW_PLATFORM_UNKNOWN = 0, + HW_PLATFORM_SURF = 1, + HW_PLATFORM_FFA = 2, + HW_PLATFORM_FLUID = 3, + HW_PLATFORM_INVALID +}; + +char *hw_platform[] = { + "Unknown", + "Surf", + "FFA", + "Fluid" +}; + /* Used to parse shared memory. Must match the modem. */ -struct socinfo_legacy { +struct socinfo_v1 { uint32_t format; uint32_t id; uint32_t version; char build_id[32]; }; -struct socinfo_raw { - struct socinfo_legacy legacy; +struct socinfo_v2 { + struct socinfo_v1 v1; /* only valid when format==2 */ uint32_t raw_id; uint32_t raw_version; }; +struct socinfo_v3 { + struct socinfo_v2 v2; + + /* only valid when format==3 */ + uint32_t hw_platform; +}; + static union { - struct socinfo_legacy legacy; - struct socinfo_raw raw; + struct socinfo_v1 v1; + struct socinfo_v2 v2; + struct socinfo_v3 v3; } *socinfo; static enum msm_cpu cpu_of_id[] = { @@ -134,30 +157,37 @@ static enum msm_cpu cur_cpu; uint32_t socinfo_get_id(void) { - return (socinfo) ? socinfo->legacy.id : 0; + return (socinfo) ? socinfo->v1.id : 0; } uint32_t socinfo_get_version(void) { - return (socinfo) ? socinfo->legacy.version : 0; + return (socinfo) ? socinfo->v1.version : 0; } char *socinfo_get_build_id(void) { - return (socinfo) ? socinfo->legacy.build_id : NULL; + return (socinfo) ? socinfo->v1.build_id : NULL; } uint32_t socinfo_get_raw_id(void) { return socinfo ? - (socinfo->legacy.format == 2 ? socinfo->raw.raw_id : 0) + (socinfo->v1.format == 2 ? socinfo->v2.raw_id : 0) : 0; } uint32_t socinfo_get_raw_version(void) { return socinfo ? - (socinfo->legacy.format == 2 ? socinfo->raw.raw_version : 0) + (socinfo->v1.format == 2 ? socinfo->v2.raw_version : 0) + : 0; +} + +uint32_t socinfo_get_platform_type(void) +{ + return socinfo ? + (socinfo->v1.format == 3 ? socinfo->v3.hw_platform : 0) : 0; } @@ -172,7 +202,7 @@ socinfo_show_id(struct sys_device *dev, char *buf) { if (!socinfo) { - printk(KERN_ERR "%s: No socinfo found!", __func__); + pr_err("%s: No socinfo found!\n", __func__); return 0; } @@ -187,7 +217,7 @@ socinfo_show_version(struct sys_device *dev, uint32_t version; if (!socinfo) { - printk(KERN_ERR "%s: No socinfo found!", __func__); + pr_err("%s: No socinfo found!\n", __func__); return 0; } @@ -203,7 +233,7 @@ socinfo_show_build_id(struct sys_device *dev, char *buf) { if (!socinfo) { - printk(KERN_ERR "%s: No socinfo found!", __func__); + pr_err("%s: No socinfo found!\n", __func__); return 0; } @@ -216,11 +246,11 @@ socinfo_show_raw_id(struct sys_device *dev, char *buf) { if (!socinfo) { - printk(KERN_ERR "%s: No socinfo found!", __func__); + pr_err("%s: No socinfo found!\n", __func__); return 0; } - if (socinfo->legacy.format != 2) { - printk(KERN_ERR "%s: Raw ID not available!", __func__); + if (socinfo->v1.format != 2) { + pr_err("%s: Raw ID not available!\n", __func__); return 0; } @@ -233,28 +263,58 @@ socinfo_show_raw_version(struct sys_device *dev, char *buf) { if (!socinfo) { - printk(KERN_ERR "%s: No socinfo found!", __func__); + pr_err("%s: No socinfo found!\n", __func__); return 0; } - if (socinfo->legacy.format != 2) { - printk(KERN_ERR "%s: Raw version not available!", __func__); + if (socinfo->v1.format != 2) { + pr_err("%s: Raw version not available!\n", __func__); return 0; } return snprintf(buf, PAGE_SIZE, "%u\n", socinfo_get_raw_version()); } -static struct sysdev_attribute socinfo_legacy_files[] = { +static ssize_t +socinfo_show_platform_type(struct sys_device *dev, + struct sysdev_attribute *attr, + char *buf) +{ + uint32_t hw_type; + + if (!socinfo) { + pr_err("%s: No socinfo found!\n", __func__); + return 0; + } + if (socinfo->v1.format != 3) { + pr_err("%s: platform type not available!\n", __func__); + return 0; + } + + hw_type = socinfo_get_platform_type(); + if (hw_type >= HW_PLATFORM_INVALID) { + pr_err("%s: Invalid hardware platform type found\n", + __func__); + hw_type = HW_PLATFORM_UNKNOWN; + } + + return snprintf(buf, PAGE_SIZE, "%-.32s\n", hw_platform[hw_type]); +} + +static struct sysdev_attribute socinfo_v1_files[] = { _SYSDEV_ATTR(id, 0444, socinfo_show_id, NULL), _SYSDEV_ATTR(version, 0444, socinfo_show_version, NULL), _SYSDEV_ATTR(build_id, 0444, socinfo_show_build_id, NULL), }; -static struct sysdev_attribute socinfo_raw_files[] = { +static struct sysdev_attribute socinfo_v2_files[] = { _SYSDEV_ATTR(raw_id, 0444, socinfo_show_raw_id, NULL), _SYSDEV_ATTR(raw_version, 0444, socinfo_show_raw_version, NULL), }; +static struct sysdev_attribute socinfo_v3_files[] = { + _SYSDEV_ATTR(hw_platform, 0444, socinfo_show_platform_type, NULL), +}; + static struct sysdev_class soc_sysdev_class = { .name = "soc", }; @@ -272,7 +332,7 @@ static void __init socinfo_create_files(struct sys_device *dev, for (i = 0; i < size; i++) { int err = sysdev_create_file(dev, &files[i]); if (err) { - printk(KERN_ERR "%s: sysdev_create_file(%s)=%d\n", + pr_err("%s: sysdev_create_file(%s)=%d\n", __func__, files[i].attr.name, err); return; } @@ -285,33 +345,44 @@ static void __init socinfo_init_sysdev(void) err = sysdev_class_register(&soc_sysdev_class); if (err) { - printk(KERN_ERR "%s: sysdev_class_register fail (%d)\n", + pr_err("%s: sysdev_class_register fail (%d)\n", __func__, err); return; } err = sysdev_register(&soc_sys_device); if (err) { - printk(KERN_ERR "%s: sysdev_register fail (%d)\n", + pr_err("%s: sysdev_register fail (%d)\n", __func__, err); return; } - socinfo_create_files(&soc_sys_device, socinfo_legacy_files, - ARRAY_SIZE(socinfo_legacy_files)); - if (socinfo->legacy.format != 2) + socinfo_create_files(&soc_sys_device, socinfo_v1_files, + ARRAY_SIZE(socinfo_v1_files)); + if (socinfo->v1.format < 2) return; - socinfo_create_files(&soc_sys_device, socinfo_raw_files, - ARRAY_SIZE(socinfo_raw_files)); + socinfo_create_files(&soc_sys_device, socinfo_v2_files, + ARRAY_SIZE(socinfo_v2_files)); + + if (socinfo->v1.format < 3) + return; + + socinfo_create_files(&soc_sys_device, socinfo_v3_files, + ARRAY_SIZE(socinfo_v3_files)); + } int __init socinfo_init(void) { - socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID, sizeof(struct socinfo_raw)); + socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID, sizeof(struct socinfo_v3)); if (!socinfo) socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID, - sizeof(struct socinfo_legacy)); + sizeof(struct socinfo_v2)); + + if (!socinfo) + socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID, + sizeof(struct socinfo_v1)); if (!socinfo) { - printk(KERN_ERR "%s: Can't find SMEM_HW_SW_BUILD_ID\n", + pr_err("%s: Can't find SMEM_HW_SW_BUILD_ID\n", __func__); return -EIO; } @@ -320,9 +391,39 @@ int __init socinfo_init(void) WARN(socinfo_get_id() >= ARRAY_SIZE(cpu_of_id), "New IDs added! ID => CPU mapping might need an update.\n"); - if (socinfo->legacy.id < ARRAY_SIZE(cpu_of_id)) - cur_cpu = cpu_of_id[socinfo->legacy.id]; + if (socinfo->v1.id < ARRAY_SIZE(cpu_of_id)) + cur_cpu = cpu_of_id[socinfo->v1.id]; socinfo_init_sysdev(); + + switch (socinfo->v1.format) { + case 1: + pr_info("%s: v%u, id=%u, ver=%u.%u\n", + __func__, socinfo->v1.format, socinfo->v1.id, + SOCINFO_VERSION_MAJOR(socinfo->v1.version), + SOCINFO_VERSION_MINOR(socinfo->v1.version)); + break; + case 2: + pr_info("%s: v%u, id=%u, ver=%u.%u, " + "raw_id=%u, raw_ver=%u\n", + __func__, socinfo->v1.format, socinfo->v1.id, + SOCINFO_VERSION_MAJOR(socinfo->v1.version), + SOCINFO_VERSION_MINOR(socinfo->v1.version), + socinfo->v2.raw_id, socinfo->v2.raw_version); + break; + case 3: + pr_info("%s: v%u, id=%u, ver=%u.%u, " + "raw_id=%u, raw_ver=%u, hw_plat=%u\n", + __func__, socinfo->v1.format, socinfo->v1.id, + SOCINFO_VERSION_MAJOR(socinfo->v1.version), + SOCINFO_VERSION_MINOR(socinfo->v1.version), + socinfo->v2.raw_id, socinfo->v2.raw_version, + socinfo->v3.hw_platform); + break; + default: + pr_err("%s: Unknown format found\n", __func__); + break; + } + return 0; } diff --git a/arch/arm/mach-msm/socinfo.h b/arch/arm/mach-msm/socinfo.h index 66b36e8243a4..a3c04b19f4ba 100644 --- a/arch/arm/mach-msm/socinfo.h +++ b/arch/arm/mach-msm/socinfo.h @@ -51,6 +51,7 @@ enum msm_cpu socinfo_get_msm_cpu(void); uint32_t socinfo_get_id(void); uint32_t socinfo_get_version(void); char *socinfo_get_build_id(void); +uint32_t socinfo_get_platform_type(void); int __init socinfo_init(void) __must_check; static inline int cpu_is_msm7x01(void) -- cgit v1.2.3 From d4b0734edebd32885064ccfa6646088e22b9de03 Mon Sep 17 00:00:00 2001 From: Willie Ruan Date: Mon, 12 Oct 2009 22:37:25 -0700 Subject: msm: proc_comm: fix typo of POCM for PCOM Signed-off-by: Willie Ruan --- arch/arm/mach-msm/proc_comm.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/proc_comm.h b/arch/arm/mach-msm/proc_comm.h index ca773797dc58..5e08f050d07a 100644 --- a/arch/arm/mach-msm/proc_comm.h +++ b/arch/arm/mach-msm/proc_comm.h @@ -112,14 +112,14 @@ enum { PCOM_CUSTOMER_CMD3, PCOM_CLK_REGIME_ENTER_APPSBL_CHG_MODE, PCOM_CLK_REGIME_EXIT_APPSBL_CHG_MODE, - POCM_CLK_REGIME_SEC_RAIL_DISABLE, - POCM_CLK_REGIME_SEC_RAIL_ENABLE, - POCM_CLK_REGIME_SEC_RAIL_CONTROL, - POCM_SET_SW_WATCHDOG_STATE, - POCM_PM_MPP_CONFIG_DIGITAL_INPUT, - POCM_PM_MPP_CONFIG_I_SINK, - POCM_RESERVED_101, - POCM_MSM_HSUSB_PHY_RESET, + PCOM_CLK_REGIME_SEC_RAIL_DISABLE, + PCOM_CLK_REGIME_SEC_RAIL_ENABLE, + PCOM_CLK_REGIME_SEC_RAIL_CONTROL, + PCOM_SET_SW_WATCHDOG_STATE, + PCOM_PM_MPP_CONFIG_DIGITAL_INPUT, + PCOM_PM_MPP_CONFIG_I_SINK, + PCOM_RESERVED_101, + PCOM_MSM_HSUSB_PHY_RESET, PCOM_GET_BATT_MV_LEVEL, PCOM_CHG_USB_IS_PC_CONNECTED, PCOM_CHG_USB_IS_CHARGER_CONNECTED, -- cgit v1.2.3 From 2838e16056509934737d7d7750c771eab13c58f6 Mon Sep 17 00:00:00 2001 From: Willie Ruan Date: Mon, 12 Oct 2009 22:40:44 -0700 Subject: msm: mpp: add MPP as digital input configuration API New hardware design, like 7x30 FLUID, needs to use MPP as digital input on application processor. FLUID uses one MPP for flip detection. Signed-off-by: Willie Ruan --- arch/arm/mach-msm/include/mach/mpp.h | 12 ++++++++ arch/arm/mach-msm/mpp.c | 59 ++++++++++++++++++++++-------------- 2 files changed, 48 insertions(+), 23 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/include/mach/mpp.h b/arch/arm/mach-msm/include/mach/mpp.h index b2f5c671babd..7af853bdca49 100644 --- a/arch/arm/mach-msm/include/mach/mpp.h +++ b/arch/arm/mach-msm/include/mach/mpp.h @@ -32,6 +32,7 @@ struct mpp { const char *name; unsigned id; + int is_input; int status; }; @@ -52,10 +53,21 @@ enum { MPP_DLOGIC_OUT_CTRL_NOT_MPP, /* MPP Output = Inverted MPP Input */ }; +/* Digital Logical Input Value */ +enum { + MPP_DLOGIC_IN_DBUS_NONE, + MPP_DLOGIC_IN_DBUS_1, + MPP_DLOGIC_IN_DBUS_2, + MPP_DLOGIC_IN_DBUS_3, +}; + #define MPP_CFG(level, control) ((((level) & 0x0FFFF) << 16) | \ ((control) & 0x0FFFFF)) +#define MPP_CFG_INPUT(level, dbus) ((((level) & 0x0FFFF) << 16) | \ + ((control) & 0x0FFFFF)) struct mpp *mpp_get(struct device *dev, const char *id); int mpp_config_digital_out(struct mpp *mpp, unsigned config); +int mpp_config_digital_in(struct mpp *mpp, unsigned config); #endif diff --git a/arch/arm/mach-msm/mpp.c b/arch/arm/mach-msm/mpp.c index 1b992d2ab1d5..eb6f533d61d0 100644 --- a/arch/arm/mach-msm/mpp.c +++ b/arch/arm/mach-msm/mpp.c @@ -66,31 +66,32 @@ #include "proc_comm.h" -#define MPP(_name, _id, _status) { .name = _name, .id = _id, .status = _status} +#define MPP(_name, _id, _is_input, _status) \ + { .name = _name, .id = _id, .is_input = _is_input, .status = _status} static struct mpp mpps[] = { - MPP("mpp1", 0, 0), - MPP("mpp2", 1, 0), - MPP("mpp3", 2, 0), - MPP("mpp4", 3, 0), - MPP("mpp5", 4, 0), - MPP("mpp6", 5, 0), - MPP("mpp7", 6, 0), - MPP("mpp8", 7, 0), - MPP("mpp9", 8, 0), - MPP("mpp10", 9, 0), - MPP("mpp11", 10, 0), - MPP("mpp12", 11, 0), - MPP("mpp13", 12, 0), - MPP("mpp14", 13, 0), - MPP("mpp15", 14, 0), - MPP("mpp16", 15, 0), - MPP("mpp17", 16, 0), - MPP("mpp18", 17, 0), - MPP("mpp19", 18, 0), - MPP("mpp20", 19, 0), - MPP("mpp21", 20, 0), - MPP("mpp22", 21, 0), + MPP("mpp1", 0, 0, 0), + MPP("mpp2", 1, 0, 0), + MPP("mpp3", 2, 0, 0), + MPP("mpp4", 3, 0, 0), + MPP("mpp5", 4, 0, 0), + MPP("mpp6", 5, 0, 0), + MPP("mpp7", 6, 0, 0), + MPP("mpp8", 7, 0, 0), + MPP("mpp9", 8, 0, 0), + MPP("mpp10", 9, 0, 0), + MPP("mpp11", 10, 0, 0), + MPP("mpp12", 11, 0, 0), + MPP("mpp13", 12, 0, 0), + MPP("mpp14", 13, 0, 0), + MPP("mpp15", 14, 0, 0), + MPP("mpp16", 15, 0, 0), + MPP("mpp17", 16, 0, 0), + MPP("mpp18", 17, 0, 0), + MPP("mpp19", 18, 0, 0), + MPP("mpp20", 19, 0, 0), + MPP("mpp21", 20, 0, 0), + MPP("mpp22", 21, 0, 0), }; struct mpp *mpp_get(struct device *dev, const char *id) @@ -110,10 +111,22 @@ int mpp_config_digital_out(struct mpp *mpp, unsigned config) int err; err = msm_proc_comm(PCOM_PM_MPP_CONFIG, &id, &config); mpp->status = err; + mpp->is_input = 0; return err; } EXPORT_SYMBOL(mpp_config_digital_out); +int mpp_config_digital_in(struct mpp *mpp, unsigned config) +{ + unsigned id = mpp->id; + int err; + err = msm_proc_comm(PCOM_PM_MPP_CONFIG_DIGITAL_INPUT, &id, &config); + mpp->status = err; + mpp->is_input = 1; + return err; +} +EXPORT_SYMBOL(mpp_config_digital_in); + #if defined(CONFIG_DEBUG_FS) static int mpp_debug_set(void *data, u64 val) { -- cgit v1.2.3 From bb5c5dd385ec860914607fe696c744f563d835b4 Mon Sep 17 00:00:00 2001 From: Matt Wagantall Date: Fri, 16 Oct 2009 10:04:08 -0700 Subject: msm: acpuclock-8x50: Clean-up PLL0 fix-up The PLL0 fix-up should not assume there is only one PLL0 row in the frequency table. The fix-up now checks the row's frequency before changing it. Change-Id: I1a459cfb916cf8bf8a84dc7aac9ba7745dff6978 Signed-off-by: Matt Wagantall --- arch/arm/mach-msm/acpuclock-8x50.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/acpuclock-8x50.c b/arch/arm/mach-msm/acpuclock-8x50.c index 9283a2d5e490..8fb7c46254d1 100644 --- a/arch/arm/mach-msm/acpuclock-8x50.c +++ b/arch/arm/mach-msm/acpuclock-8x50.c @@ -105,8 +105,7 @@ struct clkctl_acpu_speed acpu_freq_tbl[] = { { 0, 96000, ACPU_PLL_1, 1, 7, 0, 0, 14000, 0, 0, 1000}, { 0, 128000, ACPU_PLL_1, 1, 5, 0, 0, 14000, 2, 0, 1000}, { 0, 192000, ACPU_PLL_1, 1, 3, 0, 0, 14000, 0, 0, 1000}, - /* 235.93 on CDMA only. */ - { 1, 245000, ACPU_PLL_0, 4, 0, 0, 0, 29000, 0, 0, 1000}, + { 1, 245760, ACPU_PLL_0, 4, 0, 0, 0, 29000, 0, 0, 1000}, { 0, 256000, ACPU_PLL_1, 1, 2, 0, 0, 29000, 0, 0, 1000}, { 1, 384000, ACPU_PLL_3, 0, 0, 0, 0, 58000, 1, 0xA, 1000}, { 0, 422400, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0xB, 1000}, @@ -604,11 +603,6 @@ static void __init acpu_freq_tbl_fixup(void) unsigned int max_acpu_khz, pll0_fixup; unsigned int i; - /* pll0_m_val will be 36 for CDMA-only and 4 otherwise, - * indicating PLL0 is running at 235MHz, not 245MHz */ - pll0_m_val = readl(PLL0_M_VAL_ADDR) & 0x7FFFF; - pll0_fixup = (pll0_m_val == 36); - ct_csr_base = ioremap(CT_CSR_PHYS, PAGE_SIZE); BUG_ON(ct_csr_base == NULL); @@ -649,9 +643,16 @@ static void __init acpu_freq_tbl_fixup(void) skip_efuse_fixup: iounmap(ct_csr_base); BUG_ON(drv_state.max_vdd == 0); + + /* pll0_m_val will be 36 when PLL0 is run at 235MHz + * instead of the usual 245MHz. */ + pll0_m_val = readl(PLL0_M_VAL_ADDR) & 0x7FFFF; + pll0_fixup = (pll0_m_val == 36); + for (i = 0; acpu_freq_tbl[i].a11clk_khz != 0; i++) { - if (pll0_fixup && acpu_freq_tbl[i].pll == ACPU_PLL_0) { - /* PLL0 is 235.93MHz for CDMA-only */ + if (acpu_freq_tbl[i].pll == ACPU_PLL_0 + && acpu_freq_tbl[i].a11clk_khz == 245760 + && pll0_fixup) { acpu_freq_tbl[i].a11clk_khz = 235930; } if (acpu_freq_tbl[i].vdd > drv_state.max_vdd) { -- cgit v1.2.3 From b79c0ad4427f4adacfacb211b4b834208d9b13d0 Mon Sep 17 00:00:00 2001 From: Matt Wagantall Date: Fri, 16 Oct 2009 10:22:56 -0700 Subject: msm: acpuclock-8x50: Change "a11" naming convention to "acpu" 8K application processors are Scorpion-based, not ARM11-based. Replace the ARM11 naming convention with something more generic. Change-Id: Ie77b9cdc354f988ffe4446fda8c430b8f5f61142 Signed-off-by: Matt Wagantall --- arch/arm/mach-msm/acpuclock-8x50.c | 68 +++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 34 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/acpuclock-8x50.c b/arch/arm/mach-msm/acpuclock-8x50.c index 8fb7c46254d1..3f64516d4a4d 100644 --- a/arch/arm/mach-msm/acpuclock-8x50.c +++ b/arch/arm/mach-msm/acpuclock-8x50.c @@ -85,10 +85,10 @@ struct clkctl_acpu_speed { unsigned int use_for_scaling; - unsigned int a11clk_khz; + unsigned int acpuclk_khz; int pll; - unsigned int a11clk_src_sel; - unsigned int a11clk_src_div; + unsigned int acpuclk_src_sel; + unsigned int acpuclk_src_div; unsigned int ahbclk_khz; unsigned int ahbclk_div; unsigned int axiclk_khz; @@ -139,18 +139,18 @@ static void __init cpufreq_table_init(void) * freq_table values need to match frequencies specified in * acpu_freq_tbl and acpu_freq_tbl needs to be fixed up during init. */ - for (i = 0; acpu_freq_tbl[i].a11clk_khz != 0 + for (i = 0; acpu_freq_tbl[i].acpuclk_khz != 0 && freq_cnt < ARRAY_SIZE(freq_table)-1; i++) { if (acpu_freq_tbl[i].use_for_scaling) { freq_table[freq_cnt].index = freq_cnt; freq_table[freq_cnt].frequency - = acpu_freq_tbl[i].a11clk_khz; + = acpu_freq_tbl[i].acpuclk_khz; freq_cnt++; } } /* freq_table not big enough to store all usable freqs. */ - BUG_ON(acpu_freq_tbl[i].a11clk_khz != 0); + BUG_ON(acpu_freq_tbl[i].acpuclk_khz != 0); freq_table[freq_cnt].index = freq_cnt; freq_table[freq_cnt].frequency = CPUFREQ_TABLE_END; @@ -342,8 +342,8 @@ static void config_pll(struct clkctl_acpu_speed *s) case 0x0: regval = readl(SPSS_CLK_CNTL_ADDR); regval &= ~(0x7 << 4 | 0xf); - regval |= (s->a11clk_src_sel << 4); - regval |= (s->a11clk_src_div << 0); + regval |= (s->acpuclk_src_sel << 4); + regval |= (s->acpuclk_src_div << 0); writel(regval, SPSS_CLK_CNTL_ADDR); regval = readl(SPSS_CLK_SEL_ADDR); @@ -354,8 +354,8 @@ static void config_pll(struct clkctl_acpu_speed *s) case 0x1: regval = readl(SPSS_CLK_CNTL_ADDR); regval &= ~(0x7 << 12 | 0xf << 8); - regval |= (s->a11clk_src_sel << 12); - regval |= (s->a11clk_src_div << 8); + regval |= (s->acpuclk_src_sel << 12); + regval |= (s->acpuclk_src_div << 8); writel(regval, SPSS_CLK_CNTL_ADDR); regval = readl(SPSS_CLK_SEL_ADDR); @@ -411,16 +411,16 @@ int acpuclk_set_rate(unsigned long rate, enum setrate_reason reason) strt_s = drv_state.current_speed; - if (rate == (strt_s->a11clk_khz * 1000)) + if (rate == (strt_s->acpuclk_khz * 1000)) goto out; - for (tgt_s = acpu_freq_tbl; tgt_s->a11clk_khz != 0; tgt_s++) { - if (tgt_s->a11clk_khz == (rate / 1000)) + for (tgt_s = acpu_freq_tbl; tgt_s->acpuclk_khz != 0; tgt_s++) { + if (tgt_s->acpuclk_khz == (rate / 1000)) break; freq_index++; } - if (tgt_s->a11clk_khz == 0) { + if (tgt_s->acpuclk_khz == 0) { rc = -EINVAL; goto out; } @@ -523,9 +523,9 @@ static void __init acpuclk_init(void) } /* Find the matching clock rate. */ - for (speed = acpu_freq_tbl; speed->a11clk_khz != 0; speed++) { - if (speed->a11clk_src_sel == sel && - speed->a11clk_src_div == div) + for (speed = acpu_freq_tbl; speed->acpuclk_khz != 0; speed++) { + if (speed->acpuclk_src_sel == sel && + speed->acpuclk_src_div == div) break; } break; @@ -534,7 +534,7 @@ static void __init acpuclk_init(void) sel = ((readl(SCPLL_FSM_CTL_EXT_ADDR) >> 3) & 0x3f); /* Find the matching clock rate. */ - for (speed = acpu_freq_tbl; speed->a11clk_khz != 0; speed++) { + for (speed = acpu_freq_tbl; speed->acpuclk_khz != 0; speed++) { if (speed->sc_l_value == sel && speed->sc_core_src_sel_mask == 1) break; @@ -552,7 +552,7 @@ static void __init acpuclk_init(void) if (speed->pll != ACPU_PLL_3) scpll_init(); - if (speed->a11clk_khz == 0) { + if (speed->acpuclk_khz == 0) { printk(KERN_WARNING "Warning - ACPU clock reports invalid " "speed\n"); return; @@ -563,12 +563,12 @@ static void __init acpuclk_init(void) if (rc < 0) pr_err("Setting AXI min rate failed!\n"); - printk(KERN_INFO "ACPU running at %d KHz\n", speed->a11clk_khz); + printk(KERN_INFO "ACPU running at %d KHz\n", speed->acpuclk_khz); } unsigned long acpuclk_get_rate(void) { - return drv_state.current_speed->a11clk_khz; + return drv_state.current_speed->acpuclk_khz; } uint32_t acpuclk_get_switch_time(void) @@ -633,9 +633,9 @@ static void __init acpu_freq_tbl_fixup(void) pr_info("Max ACPU freq from efuse data is %d KHz\n", max_acpu_khz); - for (i = 0; acpu_freq_tbl[i].a11clk_khz != 0; i++) { - if (acpu_freq_tbl[i].a11clk_khz > max_acpu_khz) { - acpu_freq_tbl[i].a11clk_khz = 0; + for (i = 0; acpu_freq_tbl[i].acpuclk_khz != 0; i++) { + if (acpu_freq_tbl[i].acpuclk_khz > max_acpu_khz) { + acpu_freq_tbl[i].acpuclk_khz = 0; break; } } @@ -649,14 +649,14 @@ skip_efuse_fixup: pll0_m_val = readl(PLL0_M_VAL_ADDR) & 0x7FFFF; pll0_fixup = (pll0_m_val == 36); - for (i = 0; acpu_freq_tbl[i].a11clk_khz != 0; i++) { + for (i = 0; acpu_freq_tbl[i].acpuclk_khz != 0; i++) { if (acpu_freq_tbl[i].pll == ACPU_PLL_0 - && acpu_freq_tbl[i].a11clk_khz == 245760 + && acpu_freq_tbl[i].acpuclk_khz == 245760 && pll0_fixup) { - acpu_freq_tbl[i].a11clk_khz = 235930; + acpu_freq_tbl[i].acpuclk_khz = 235930; } if (acpu_freq_tbl[i].vdd > drv_state.max_vdd) { - acpu_freq_tbl[i].a11clk_khz = 0; + acpu_freq_tbl[i].acpuclk_khz = 0; break; } } @@ -667,10 +667,10 @@ static void __init lpj_init(void) { int i; const struct clkctl_acpu_speed *base_clk = drv_state.current_speed; - for (i = 0; acpu_freq_tbl[i].a11clk_khz; i++) { + for (i = 0; acpu_freq_tbl[i].acpuclk_khz; i++) { acpu_freq_tbl[i].lpj = cpufreq_scale(loops_per_jiffy, - base_clk->a11clk_khz, - acpu_freq_tbl[i].a11clk_khz); + base_clk->acpuclk_khz, + acpu_freq_tbl[i].acpuclk_khz); } } @@ -681,9 +681,9 @@ static int __init acpu_avs_init(int (*set_vdd) (int), int khz) int freq_count = 0; int freq_index = -1; - for (i = 0; acpu_freq_tbl[i].a11clk_khz; i++) { + for (i = 0; acpu_freq_tbl[i].acpuclk_khz; i++) { freq_count++; - if (acpu_freq_tbl[i].a11clk_khz == khz) + if (acpu_freq_tbl[i].acpuclk_khz == khz) freq_index = i; } @@ -711,7 +711,7 @@ void __init msm_acpu_clock_init(struct msm_acpu_clock_platform_data *clkdata) #endif #ifdef CONFIG_MSM_CPU_AVS if (!acpu_avs_init(drv_state.acpu_set_vdd, - drv_state.current_speed->a11clk_khz)) { + drv_state.current_speed->acpuclk_khz)) { /* avs init successful. avs will handle voltage changes */ drv_state.acpu_set_vdd = NULL; } -- cgit v1.2.3 From e76d0345ae3f30628e982fff53c87bba3243b50e Mon Sep 17 00:00:00 2001 From: Matt Wagantall Date: Fri, 16 Oct 2009 14:11:16 -0700 Subject: msm: clock: Fix proc_comm 'OFF' flags for several 7x30 clocks Add 'OFF' flags to several clocks. Missing 'OFF' flags for clocks that are not enabled at boot can cause crashes when attemping to read clock enable/disabled status (from debugfs, for example) if the clock is not enabled first. Unnecessary 'OFF' flags are also removed from several clocks that are known to be on at boot. Change-Id: I7c952414d4cac68d51d0c9f6827928f8fc20c3ad Signed-off-by: Matt Wagantall --- arch/arm/mach-msm/devices.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/devices.c b/arch/arm/mach-msm/devices.c index 0fcea3aa4368..f852c2ef5ffd 100644 --- a/arch/arm/mach-msm/devices.c +++ b/arch/arm/mach-msm/devices.c @@ -544,7 +544,7 @@ unsigned msm_num_clocks_7x27 = ARRAY_SIZE(msm_clocks_7x27); struct clk msm_clocks_7x30[] = { CLK_PCOM("adm_clk", ADM_CLK, NULL, 0), CLK_PCOM("adsp_clk", ADSP_CLK, NULL, 0), - CLK_PCOM("cam_mclk_clk", CAM_MCLK_CLK, NULL, OFF), + CLK_PCOM("cam_mclk_clk", CAM_MCLK_CLK, NULL, 0), CLK_PCOM("camif_pad_pclk", CAMIF_PAD_PCLK, NULL, OFF), CLK_PCOM("ebi1_clk", EBI1_CLK, NULL, CLK_MIN), CLK_PCOM("ebi2_clk", EBI2_CLK, NULL, 0), @@ -563,8 +563,8 @@ struct clk msm_clocks_7x30[] = { CLK_PCOM("pcm_clk", PCM_CLK, NULL, 0), CLK_PCOM("mddi_clk", PMDH_CLK, NULL, OFF | CLK_MINMAX), CLK_PCOM("mddi_pclk", PMDH_PCLK, NULL, 0), - CLK_PCOM("rotator_imem_clk", ROTATOR_IMEM_CLK, NULL, 0), - CLK_PCOM("rotator_pclk", ROTATOR_PCLK, NULL, 0), + CLK_PCOM("rotator_imem_clk", ROTATOR_IMEM_CLK, NULL, OFF), + CLK_PCOM("rotator_pclk", ROTATOR_PCLK, NULL, OFF), CLK_PCOM("sdac_clk", SDAC_CLK, NULL, OFF), CLK_PCOM("sdc_clk", SDC1_CLK, &msm_device_sdc1.dev, OFF), CLK_PCOM("sdc_pclk", SDC1_PCLK, &msm_device_sdc1.dev, OFF), @@ -592,10 +592,10 @@ struct clk msm_clocks_7x30[] = { CLK_PCOM("usb_hs3_core_clk", USB_HS3_CORE_CLK, NULL, OFF), CLK_PCOM("usb_otg_clk", USB_OTG_CLK, NULL, 0), CLK_PCOM("vdc_clk", VDC_CLK, NULL, OFF | CLK_MIN), - CLK_PCOM("vfe_camif_clk", VFE_CAMIF_CLK, NULL, OFF), - CLK_PCOM("vfe_clk", VFE_CLK, NULL, OFF), - CLK_PCOM("vfe_mdc_clk", VFE_MDC_CLK, NULL, OFF), - CLK_PCOM("vfe_pclk", VFE_PCLK, NULL, 0), + CLK_PCOM("vfe_camif_clk", VFE_CAMIF_CLK, NULL, 0), + CLK_PCOM("vfe_clk", VFE_CLK, NULL, 0), + CLK_PCOM("vfe_mdc_clk", VFE_MDC_CLK, NULL, 0), + CLK_PCOM("vfe_pclk", VFE_PCLK, NULL, OFF), CLK_PCOM("grp_pclk", GRP_PCLK, NULL, 0), CLK_PCOM("lpa_codec_clk", LPA_CODEC_CLK, NULL, 0), CLK_PCOM("lpa_core_clk", LPA_CORE_CLK, NULL, 0), -- cgit v1.2.3 From 1828009246bf9c9bc86e9e0e5032fadf25c53ae0 Mon Sep 17 00:00:00 2001 From: Matt Wagantall Date: Fri, 16 Oct 2009 14:43:43 -0700 Subject: msm: clock: Put clock lists in alphabetical order Also, rename the 7x30 'cam_mclk_clk' clock to 'cam_m_clk', to comply with the naming convention. Change-Id: If703b93cbcff26e4baf48970b1d5fa2b25b0b0f5 Signed-off-by: Matt Wagantall --- arch/arm/mach-msm/devices.c | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/devices.c b/arch/arm/mach-msm/devices.c index f852c2ef5ffd..74ac321f662a 100644 --- a/arch/arm/mach-msm/devices.c +++ b/arch/arm/mach-msm/devices.c @@ -420,10 +420,10 @@ struct clk msm_clocks_7x01a[] = { CLK_PCOM("icodec_tx_clk", ICODEC_TX_CLK, NULL, 0), CLK_PCOM("imem_clk", IMEM_CLK, NULL, OFF), CLK_PCOM("mdc_clk", MDC_CLK, NULL, 0), + CLK_PCOM("mddi_clk", PMDH_CLK, NULL, OFF | CLK_MINMAX), CLK_PCOM("mdp_clk", MDP_CLK, NULL, OFF), CLK_PCOM("pbus_clk", PBUS_CLK, NULL, CLK_MIN), CLK_PCOM("pcm_clk", PCM_CLK, NULL, 0), - CLK_PCOM("mddi_clk", PMDH_CLK, NULL, OFF | CLK_MINMAX), CLK_PCOM("sdac_clk", SDAC_CLK, NULL, OFF), CLK_PCOM("sdc_clk", SDC1_CLK, &msm_device_sdc1.dev, OFF), CLK_PCOM("sdc_pclk", SDC1_PCLK, &msm_device_sdc1.dev, OFF), @@ -465,13 +465,13 @@ struct clk msm_clocks_7x25[] = { CLK_PCOM("icodec_tx_clk", ICODEC_TX_CLK, NULL, 0), CLK_PCOM("imem_clk", IMEM_CLK, NULL, OFF), CLK_PCOM("mdc_clk", MDC_CLK, NULL, 0), + CLK_PCOM("mddi_clk", PMDH_CLK, NULL, OFF | CLK_MINMAX), CLK_PCOM("mdp_clk", MDP_CLK, NULL, OFF), CLK_PCOM("mdp_lcdc_pclk_clk", MDP_LCDC_PCLK_CLK, NULL, 0), CLK_PCOM("mdp_lcdc_pad_pclk_clk", MDP_LCDC_PAD_PCLK_CLK, NULL, 0), CLK_PCOM("mdp_vsync_clk", MDP_VSYNC_CLK, NULL, 0), CLK_PCOM("pbus_clk", PBUS_CLK, NULL, CLK_MIN), CLK_PCOM("pcm_clk", PCM_CLK, NULL, 0), - CLK_PCOM("mddi_clk", PMDH_CLK, NULL, OFF | CLK_MINMAX), CLK_PCOM("sdac_clk", SDAC_CLK, NULL, OFF), CLK_PCOM("sdc_clk", SDC1_CLK, &msm_device_sdc1.dev, OFF), CLK_PCOM("sdc_pclk", SDC1_PCLK, &msm_device_sdc1.dev, OFF), @@ -505,18 +505,19 @@ struct clk msm_clocks_7x27[] = { CLK_PCOM("ecodec_clk", ECODEC_CLK, NULL, 0), CLK_PCOM("gp_clk", GP_CLK, NULL, 0), CLK_PCOM("grp_clk", GRP_CLK, NULL, 0), + CLK_PCOM("grp_pclk", GRP_PCLK, NULL, 0), CLK_PCOM("i2c_clk", I2C_CLK, &msm_device_i2c.dev, 0), CLK_PCOM("icodec_rx_clk", ICODEC_RX_CLK, NULL, 0), CLK_PCOM("icodec_tx_clk", ICODEC_TX_CLK, NULL, 0), CLK_PCOM("imem_clk", IMEM_CLK, NULL, OFF), CLK_PCOM("mdc_clk", MDC_CLK, NULL, 0), + CLK_PCOM("mddi_clk", PMDH_CLK, NULL, OFF | CLK_MINMAX), CLK_PCOM("mdp_clk", MDP_CLK, NULL, OFF), CLK_PCOM("mdp_lcdc_pclk_clk", MDP_LCDC_PCLK_CLK, NULL, 0), CLK_PCOM("mdp_lcdc_pad_pclk_clk", MDP_LCDC_PAD_PCLK_CLK, NULL, 0), CLK_PCOM("mdp_vsync_clk", MDP_VSYNC_CLK, NULL, 0), CLK_PCOM("pbus_clk", PBUS_CLK, NULL, CLK_MIN), CLK_PCOM("pcm_clk", PCM_CLK, NULL, 0), - CLK_PCOM("mddi_clk", PMDH_CLK, NULL, OFF | CLK_MINMAX), CLK_PCOM("sdac_clk", SDAC_CLK, NULL, OFF), CLK_PCOM("sdc_clk", SDC1_CLK, &msm_device_sdc1.dev, OFF), CLK_PCOM("sdc_pclk", SDC1_PCLK, &msm_device_sdc1.dev, OFF), @@ -534,6 +535,7 @@ struct clk msm_clocks_7x27[] = { CLK_PCOM("usb_hs_clk", USB_HS_CLK, NULL, OFF), CLK_PCOM("usb_hs_pclk", USB_HS_PCLK, NULL, OFF), CLK_PCOM("usb_otg_clk", USB_OTG_CLK, NULL, 0), + CLK_PCOM("usb_phy_clk", USB_PHY_CLK, NULL, 0), CLK_PCOM("vdc_clk", VDC_CLK, NULL, OFF | CLK_MIN), CLK_PCOM("vfe_clk", VFE_CLK, NULL, OFF), CLK_PCOM("vfe_mdc_clk", VFE_MDC_CLK, NULL, OFF), @@ -544,25 +546,39 @@ unsigned msm_num_clocks_7x27 = ARRAY_SIZE(msm_clocks_7x27); struct clk msm_clocks_7x30[] = { CLK_PCOM("adm_clk", ADM_CLK, NULL, 0), CLK_PCOM("adsp_clk", ADSP_CLK, NULL, 0), - CLK_PCOM("cam_mclk_clk", CAM_MCLK_CLK, NULL, 0), + CLK_PCOM("cam_m_clk", CAM_MCLK_CLK, NULL, 0), CLK_PCOM("camif_pad_pclk", CAMIF_PAD_PCLK, NULL, OFF), CLK_PCOM("ebi1_clk", EBI1_CLK, NULL, CLK_MIN), CLK_PCOM("ebi2_clk", EBI2_CLK, NULL, 0), CLK_PCOM("ecodec_clk", ECODEC_CLK, NULL, 0), CLK_PCOM("gp_clk", GP_CLK, NULL, 0), + CLK_PCOM("grp_2d_clk", GRP_2D_CLK, NULL, 0), + CLK_PCOM("grp_2d_pclk", GRP_2D_PCLK, NULL, 0), CLK_PCOM("grp_clk", GRP_CLK, NULL, 0), + CLK_PCOM("grp_pclk", GRP_PCLK, NULL, 0), CLK_PCOM("i2c_clk", I2C_CLK, &msm_device_i2c.dev, 0), CLK_PCOM("imem_clk", IMEM_CLK, NULL, OFF), + CLK_PCOM("lpa_codec_clk", LPA_CODEC_CLK, NULL, 0), + CLK_PCOM("lpa_core_clk", LPA_CORE_CLK, NULL, 0), + CLK_PCOM("lpa_pclk", LPA_PCLK, NULL, 0), CLK_PCOM("mdc_clk", MDC_CLK, NULL, 0), + CLK_PCOM("mddi_clk", PMDH_CLK, NULL, OFF | CLK_MINMAX), + CLK_PCOM("mddi_pclk", PMDH_PCLK, NULL, 0), CLK_PCOM("mdp_clk", MDP_CLK, NULL, OFF), CLK_PCOM("mdp_pclk", MDP_PCLK, NULL, 0), CLK_PCOM("mdp_lcdc_pclk_clk", MDP_LCDC_PCLK_CLK, NULL, 0), CLK_PCOM("mdp_lcdc_pad_pclk_clk", MDP_LCDC_PAD_PCLK_CLK, NULL, 0), CLK_PCOM("mdp_vsync_clk", MDP_VSYNC_CLK, NULL, 0), + CLK_PCOM("mfc_clk", MFC_CLK, NULL, 0), + CLK_PCOM("mfc_div2_clk", MFC_DIV2_CLK, NULL, 0), + CLK_PCOM("mfc_pclk", MFC_PCLK, NULL, 0), + CLK_PCOM("mi2s_codec_rx_m_clk", MI2S_CODEC_RX_MCLK, NULL, 0), + CLK_PCOM("mi2s_codec_rx_s_clk", MI2S_CODEC_RX_SCLK, NULL, 0), + CLK_PCOM("mi2s_codec_tx_m_clk", MI2S_CODEC_TX_MCLK, NULL, 0), + CLK_PCOM("mi2s_codec_tx_s_clk", MI2S_CODEC_TX_SCLK, NULL, 0), CLK_PCOM("pbus_clk", PBUS_CLK, NULL, CLK_MIN), CLK_PCOM("pcm_clk", PCM_CLK, NULL, 0), - CLK_PCOM("mddi_clk", PMDH_CLK, NULL, OFF | CLK_MINMAX), - CLK_PCOM("mddi_pclk", PMDH_PCLK, NULL, 0), + CLK_PCOM("qup_clk", QUP_I2C_CLK, &qup_device_i2c.dev, 0), CLK_PCOM("rotator_imem_clk", ROTATOR_IMEM_CLK, NULL, OFF), CLK_PCOM("rotator_pclk", ROTATOR_PCLK, NULL, OFF), CLK_PCOM("sdac_clk", SDAC_CLK, NULL, OFF), @@ -596,19 +612,6 @@ struct clk msm_clocks_7x30[] = { CLK_PCOM("vfe_clk", VFE_CLK, NULL, 0), CLK_PCOM("vfe_mdc_clk", VFE_MDC_CLK, NULL, 0), CLK_PCOM("vfe_pclk", VFE_PCLK, NULL, OFF), - CLK_PCOM("grp_pclk", GRP_PCLK, NULL, 0), - CLK_PCOM("lpa_codec_clk", LPA_CODEC_CLK, NULL, 0), - CLK_PCOM("lpa_core_clk", LPA_CORE_CLK, NULL, 0), - CLK_PCOM("lpa_pclk", LPA_PCLK, NULL, 0), - CLK_PCOM("mfc_clk", MFC_CLK, NULL, 0), - CLK_PCOM("mfc_div2_clk", MFC_DIV2_CLK, NULL, 0), - CLK_PCOM("mfc_pclk", MFC_PCLK, NULL, 0), - CLK_PCOM("grp_2d_clk", GRP_2D_CLK, NULL, 0), - CLK_PCOM("grp_2d_pclk", GRP_2D_PCLK, NULL, 0), - CLK_PCOM("mi2s_codec_rx_m_clk", MI2S_CODEC_RX_MCLK, NULL, 0), - CLK_PCOM("mi2s_codec_rx_s_clk", MI2S_CODEC_RX_SCLK, NULL, 0), - CLK_PCOM("mi2s_codec_tx_m_clk", MI2S_CODEC_TX_MCLK, NULL, 0), - CLK_PCOM("mi2s_codec_tx_s_clk", MI2S_CODEC_TX_SCLK, NULL, 0), }; unsigned msm_num_clocks_7x30 = ARRAY_SIZE(msm_clocks_7x30); -- cgit v1.2.3 From f1fdeba529894032aac3efbf1517801329030de5 Mon Sep 17 00:00:00 2001 From: Matt Wagantall Date: Wed, 7 Oct 2009 12:46:11 -0700 Subject: msm: iomap: Add 7x30 ACC register region The ACC register region contains Scorpion CPU clock control/distribution registers. It is required for Scorpion clock source selection. Change-Id: I1bcb412043f7cea403387fe249cf9be3fa5c7459 Signed-off-by: Matt Wagantall --- arch/arm/mach-msm/include/mach/msm_iomap.h | 4 ++++ arch/arm/mach-msm/io.c | 1 + 2 files changed, 5 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/include/mach/msm_iomap.h b/arch/arm/mach-msm/include/mach/msm_iomap.h index 6ea60e0872d2..0c2caab9aa99 100644 --- a/arch/arm/mach-msm/include/mach/msm_iomap.h +++ b/arch/arm/mach-msm/include/mach/msm_iomap.h @@ -115,6 +115,10 @@ #define MSM_SCPLL_PHYS 0xA8800000 #define MSM_SCPLL_SIZE SZ_4K +#define MSM_ACC_BASE IOMEM(0xE0007000) +#define MSM_ACC_PHYS 0xC0101000 +#define MSM_ACC_SIZE SZ_4K + #define MSM_GCC_BASE IOMEM(0xE0008000) #define MSM_GCC_PHYS 0xC0182000 #define MSM_GCC_SIZE SZ_4K diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c index e0375c7ea0a2..2712cdc938b6 100644 --- a/arch/arm/mach-msm/io.c +++ b/arch/arm/mach-msm/io.c @@ -133,6 +133,7 @@ static struct map_desc msm7x30_io_desc[] __initdata = { MSM_DEVICE(SCPLL), MSM_DEVICE(AD5), MSM_DEVICE(MDC), + MSM_DEVICE(ACC), MSM_DEVICE(GCC), #ifdef CONFIG_MSM_DEBUG_UART MSM_DEVICE(DEBUG_UART), -- cgit v1.2.3 From 79d8df1fc521d37daac5fa7323a5658d910448f6 Mon Sep 17 00:00:00 2001 From: Michael Bohan Date: Tue, 13 Oct 2009 15:10:25 -0700 Subject: msm: Add MSM7x30 FFA and MSM7x30 FLUID board types Signed-off-by: Michael Bohan --- arch/arm/mach-msm/Kconfig | 8 ++++++++ arch/arm/mach-msm/board-msm7x30.c | 24 ++++++++++++++++++++++++ 2 files changed, 32 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index d32ceb386d0b..660986cee7fb 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -101,6 +101,14 @@ config MACH_MSM7X30_FFA help Support for the Qualcomm MSM7x30 FFA eval board. +config MACH_MSM7X30_FLUID + depends on ARCH_MSM7X30 + depends on !MSM_STACKED_MEMORY + default y + bool "MSM7x30 FLUID" + help + Support for the Qualcomm MSM7x30 FLUID eval board. + config MACH_SAPPHIRE depends on ARCH_MSM7X01A default n diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c index f0a2b7691d33..3dc0fc54322a 100644 --- a/arch/arm/mach-msm/board-msm7x30.c +++ b/arch/arm/mach-msm/board-msm7x30.c @@ -183,3 +183,27 @@ MACHINE_START(MSM7X30_SURF, "QCT MSM7X30 SURF") .init_machine = msm7x30_init, .timer = &msm_timer, MACHINE_END + +MACHINE_START(MSM7X30_FFA, "QCT MSM7X30 FFA") +#ifdef CONFIG_MSM_DEBUG_UART + .phys_io = MSM_DEBUG_UART_PHYS, + .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc, +#endif + .boot_params = 0x00200100, + .map_io = msm7x30_map_io, + .init_irq = msm7x30_init_irq, + .init_machine = msm7x30_init, + .timer = &msm_timer, +MACHINE_END + +MACHINE_START(MSM7X30_FLUID, "QCT MSM7X30 FLUID") +#ifdef CONFIG_MSM_DEBUG_UART + .phys_io = MSM_DEBUG_UART_PHYS, + .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc, +#endif + .boot_params = 0x00200100, + .map_io = msm7x30_map_io, + .init_irq = msm7x30_init_irq, + .init_machine = msm7x30_init, + .timer = &msm_timer, +MACHINE_END -- cgit v1.2.3 From 01ba2d9ee3bd5b9bccc28952b00b4f3636dd4b7b Mon Sep 17 00:00:00 2001 From: Matt Wagantall Date: Tue, 20 Oct 2009 17:49:10 -0700 Subject: msm: internal_power_rail: Add MFC power rail control support Change-Id: I040d655baf470a0cb276dab1b5f06872614a1c3b Signed-off-by: Matt Wagantall --- arch/arm/mach-msm/include/mach/internal_power_rail.h | 1 + 1 file changed, 1 insertion(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/include/mach/internal_power_rail.h b/arch/arm/mach-msm/include/mach/internal_power_rail.h index 1170771ac3bd..cd7ca765bde6 100644 --- a/arch/arm/mach-msm/include/mach/internal_power_rail.h +++ b/arch/arm/mach-msm/include/mach/internal_power_rail.h @@ -32,6 +32,7 @@ #define PWR_RAIL_GRP_CLK 8 #define PWR_RAIL_VDC_CLK 39 #define PWR_RAIL_VFE_CLK 41 +#define PWR_RAIL_MFC_CLK 68 enum rail_ctl_mode { PWR_RAIL_CTL_AUTO = 0, -- cgit v1.2.3 From c6930a0c9904f1588962105cdead0af328d09901 Mon Sep 17 00:00:00 2001 From: Matt Wagantall Date: Wed, 7 Oct 2009 12:17:37 -0700 Subject: msm: acpuclock: Move CPU-specific defines to correct driver files CPU-specific defines are moved from the common acpuclock.h header file into the CPU-specific drivers. Doing so keeps acpuclock.h generic, allowing it to be used for all acpuclock drivers. Change-Id: I4cf9633271a077d31dc793e96f0b721bab286e04 Signed-off-by: Matt Wagantall --- arch/arm/mach-msm/acpuclock-8x50.c | 9 +++++++++ arch/arm/mach-msm/acpuclock.c | 15 +++++++++++++++ arch/arm/mach-msm/acpuclock.h | 21 --------------------- 3 files changed, 24 insertions(+), 21 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/acpuclock-8x50.c b/arch/arm/mach-msm/acpuclock-8x50.c index 3f64516d4a4d..d02d1b56821e 100644 --- a/arch/arm/mach-msm/acpuclock-8x50.c +++ b/arch/arm/mach-msm/acpuclock-8x50.c @@ -83,6 +83,15 @@ #define SCPLL_STATUS_ADDR (MSM_SCPLL_BASE + 0x18) #define SCPLL_FSM_CTL_EXT_ADDR (MSM_SCPLL_BASE + 0x10) +enum { + ACPU_PLL_TCXO = -1, + ACPU_PLL_0 = 0, + ACPU_PLL_1, + ACPU_PLL_2, + ACPU_PLL_3, + ACPU_PLL_END, +}; + struct clkctl_acpu_speed { unsigned int use_for_scaling; unsigned int acpuclk_khz; diff --git a/arch/arm/mach-msm/acpuclock.c b/arch/arm/mach-msm/acpuclock.c index c594b96ad9f2..bcc8491ab342 100644 --- a/arch/arm/mach-msm/acpuclock.c +++ b/arch/arm/mach-msm/acpuclock.c @@ -42,6 +42,21 @@ #define PERF_SWITCH_DEBUG 0 #define PERF_SWITCH_STEP_DEBUG 0 +#define A11S_CLK_CNTL_ADDR (MSM_CSR_BASE + 0x100) +#define A11S_CLK_SEL_ADDR (MSM_CSR_BASE + 0x104) +#define A11S_VDD_SVS_PLEVEL_ADDR (MSM_CSR_BASE + 0x124) +#define PLLn_MODE(n) (MSM_CLK_CTL_BASE + 0x300 + 28 * (n)) +#define PLLn_L_VAL(n) (MSM_CLK_CTL_BASE + 0x304 + 28 * (n)) + +enum { + ACPU_PLL_TCXO = -1, + ACPU_PLL_0 = 0, + ACPU_PLL_1, + ACPU_PLL_2, + ACPU_PLL_3, + ACPU_PLL_END, +}; + struct clock_state { struct clkctl_acpu_speed *current_speed; diff --git a/arch/arm/mach-msm/acpuclock.h b/arch/arm/mach-msm/acpuclock.h index 7d419ab46e7d..ad7b4cd2399d 100644 --- a/arch/arm/mach-msm/acpuclock.h +++ b/arch/arm/mach-msm/acpuclock.h @@ -22,27 +22,6 @@ #include - -#define A11S_CLK_CNTL_ADDR (MSM_CSR_BASE + 0x100) -#define A11S_CLK_SEL_ADDR (MSM_CSR_BASE + 0x104) -#define A11S_VDD_SVS_PLEVEL_ADDR (MSM_CSR_BASE + 0x124) - -#define PLLn_MODE(n) (MSM_CLK_CTL_BASE + 0x300 + 28 * (n)) -#define PLLn_L_VAL(n) (MSM_CLK_CTL_BASE + 0x304 + 28 * (n)) - -/* - * ARM11 clock configuration for specific ACPU speeds - */ - -enum { - ACPU_PLL_TCXO = -1, - ACPU_PLL_0 = 0, - ACPU_PLL_1, - ACPU_PLL_2, - ACPU_PLL_3, - ACPU_PLL_END, -}; - enum setrate_reason { SETRATE_CPUFREQ = 0, SETRATE_SWFI, -- cgit v1.2.3 From 5ca21b8fc6e8ecdc5d910cbdfc379984316aeca5 Mon Sep 17 00:00:00 2001 From: Matt Wagantall Date: Mon, 12 Oct 2009 13:24:13 -0700 Subject: msm: clock: Implement clock reset API. Some drivers require the ability to assert and deassert reset signals to hardware blocks associated with clocks. An API is added to do this using proc_comm. Change-Id: Ib29fa5b5fae6e4892ada2015b831583d5b8d87f4 Signed-off-by: Matt Wagantall --- arch/arm/mach-msm/clock-7x30.c | 7 +++++++ arch/arm/mach-msm/clock-pcom.c | 17 +++++++++++++++++ arch/arm/mach-msm/clock.c | 6 ++++++ arch/arm/mach-msm/clock.h | 2 ++ arch/arm/mach-msm/include/mach/clk.h | 8 ++++++++ 5 files changed, 40 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/clock-7x30.c b/arch/arm/mach-msm/clock-7x30.c index e420b4a913ee..2d52a53db1de 100644 --- a/arch/arm/mach-msm/clock-7x30.c +++ b/arch/arm/mach-msm/clock-7x30.c @@ -63,6 +63,7 @@ #include #include #include +#include #include "clock.h" #include "clock-7x30.h" @@ -695,6 +696,11 @@ static void soc_clk_disable(unsigned id) return; } +static int soc_clk_reset(unsigned id, enum clk_reset_action action) +{ + return -EPERM; +} + static int soc_clk_set_rate(unsigned id, unsigned rate) { struct clk_local *t = &clk_local_tbl[id]; @@ -857,6 +863,7 @@ static long soc_clk_round_rate(unsigned id, unsigned rate) struct clk_ops clk_ops_7x30 = { .enable = soc_clk_enable, .disable = soc_clk_disable, + .reset = soc_clk_reset, .set_rate = soc_clk_set_rate, .set_min_rate = soc_clk_set_min_rate, .set_max_rate = soc_clk_set_max_rate, diff --git a/arch/arm/mach-msm/clock-pcom.c b/arch/arm/mach-msm/clock-pcom.c index a0969072e826..e4997254a279 100644 --- a/arch/arm/mach-msm/clock-pcom.c +++ b/arch/arm/mach-msm/clock-pcom.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "proc_comm.h" #include "clock.h" @@ -37,6 +38,21 @@ void pc_clk_disable(unsigned id) msm_proc_comm(PCOM_CLKCTL_RPC_DISABLE, &id, NULL); } +int pc_clk_reset(unsigned id, enum clk_reset_action action) +{ + int rc; + + if (action == CLK_RESET_ASSERT) + rc = msm_proc_comm(PCOM_CLKCTL_RPC_RESET_ASSERT, &id, NULL); + else + rc = msm_proc_comm(PCOM_CLKCTL_RPC_RESET_DEASSERT, &id, NULL); + + if (rc < 0) + return rc; + else + return (int)id < 0 ? -EINVAL : 0; +} + int pc_clk_set_rate(unsigned id, unsigned rate) { /* The rate _might_ be rounded off to the nearest KHz value by the @@ -103,6 +119,7 @@ long pc_clk_round_rate(unsigned id, unsigned rate) struct clk_ops clk_ops_pcom = { .enable = pc_clk_enable, .disable = pc_clk_disable, + .reset = pc_clk_reset, .set_rate = pc_clk_set_rate, .set_min_rate = pc_clk_set_min_rate, .set_max_rate = pc_clk_set_max_rate, diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c index 45e78d74ddb6..c7622f9c2169 100644 --- a/arch/arm/mach-msm/clock.c +++ b/arch/arm/mach-msm/clock.c @@ -106,6 +106,12 @@ void clk_disable(struct clk *clk) } EXPORT_SYMBOL(clk_disable); +int clk_reset(struct clk *clk, enum clk_reset_action action) +{ + return clk->ops->reset(clk->id, action); +} +EXPORT_SYMBOL(clk_reset); + unsigned long clk_get_rate(struct clk *clk) { return clk->ops->get_rate(clk->id); diff --git a/arch/arm/mach-msm/clock.h b/arch/arm/mach-msm/clock.h index 99e1bac7bfc8..66cd44f8b720 100644 --- a/arch/arm/mach-msm/clock.h +++ b/arch/arm/mach-msm/clock.h @@ -18,6 +18,7 @@ #define __ARCH_ARM_MACH_MSM_CLOCK_H #include +#include #include "clock-pcom.h" #include "clock-7x30.h" @@ -35,6 +36,7 @@ struct clk_ops { int (*enable)(unsigned id); void (*disable)(unsigned id); + int (*reset)(unsigned id, enum clk_reset_action action); int (*set_rate)(unsigned id, unsigned rate); int (*set_min_rate)(unsigned id, unsigned rate); int (*set_max_rate)(unsigned id, unsigned rate); diff --git a/arch/arm/mach-msm/include/mach/clk.h b/arch/arm/mach-msm/include/mach/clk.h index 53ec86e6bc58..ac70550cb41c 100644 --- a/arch/arm/mach-msm/include/mach/clk.h +++ b/arch/arm/mach-msm/include/mach/clk.h @@ -34,6 +34,11 @@ */ #define MSM_AXI_MAX_FREQ LONG_MAX +enum clk_reset_action { + CLK_RESET_DEASSERT = 0, + CLK_RESET_ASSERT = 1 +}; + struct clk; /* Rate is minimum clock rate in Hz */ @@ -42,4 +47,7 @@ int clk_set_min_rate(struct clk *clk, unsigned long rate); /* Rate is maximum clock rate in Hz */ int clk_set_max_rate(struct clk *clk, unsigned long rate); +/* Assert/Deassert reset to a hardware block associated with a clock */ +int clk_reset(struct clk *clk, enum clk_reset_action action); + #endif -- cgit v1.2.3 From 4c9a33db889bcc8f7c513fc6df088e4a9b5027d4 Mon Sep 17 00:00:00 2001 From: Willie Ruan Date: Sat, 17 Oct 2009 23:15:14 -0700 Subject: msm: gpio: move two msm_gpio structs from gpio.c to gpio_chip.h There is a requirement to add PM8058 GPIOs and MPP(Multi Purpose Pin)s on 7x30 SoC to kernel gpio framework. To allow another file to really use register_gpio_chip() these structs must be moved to gpio_chip.h. Signed-off-by: Willie Ruan --- arch/arm/mach-msm/gpio.c | 24 ------------------------ arch/arm/mach-msm/gpio_chip.h | 23 +++++++++++++++++++++++ 2 files changed, 23 insertions(+), 24 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/gpio.c b/arch/arm/mach-msm/gpio.c index d9b4fcbebff7..6c80d76b184b 100644 --- a/arch/arm/mach-msm/gpio.c +++ b/arch/arm/mach-msm/gpio.c @@ -31,8 +31,6 @@ enum { static int msm_gpio_debug_mask = 0; module_param_named(debug_mask, msm_gpio_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP); -#define MSM_GPIO_BROKEN_INT_CLEAR 1 - /* private gpio_configure flags */ #define MSM_GPIOF_ENABLE_INTERRUPT 0x10000000 #define MSM_GPIOF_DISABLE_INTERRUPT 0x20000000 @@ -46,28 +44,6 @@ static int msm_gpio_write(struct gpio_chip *chip, unsigned n, unsigned on); static int msm_gpio_read_detect_status(struct gpio_chip *chip, unsigned int gpio); static int msm_gpio_clear_detect_status(struct gpio_chip *chip, unsigned int gpio); -struct msm_gpio_regs -{ - void __iomem *out; - void __iomem *in; - void __iomem *int_status; - void __iomem *int_clear; - void __iomem *int_en; - void __iomem *int_edge; - void __iomem *int_pos; - void __iomem *oe; -}; - -struct msm_gpio_chip { - struct gpio_chip chip; - struct msm_gpio_regs regs; -#if MSM_GPIO_BROKEN_INT_CLEAR - unsigned int_status_copy; -#endif - unsigned int both_edge_detect; - unsigned int int_enable[2]; /* 0: awake, 1: sleep */ -}; - struct msm_gpio_chip msm_gpio_chips[] = { { .regs = { diff --git a/arch/arm/mach-msm/gpio_chip.h b/arch/arm/mach-msm/gpio_chip.h index eab9f0946921..39ccc0f0ed8e 100644 --- a/arch/arm/mach-msm/gpio_chip.h +++ b/arch/arm/mach-msm/gpio_chip.h @@ -33,6 +33,29 @@ struct gpio_chip { int (*clear_detect_status)(struct gpio_chip *chip, unsigned int gpio); }; +struct msm_gpio_regs { + void __iomem *out; + void __iomem *in; + void __iomem *int_status; + void __iomem *int_clear; + void __iomem *int_en; + void __iomem *int_edge; + void __iomem *int_pos; + void __iomem *oe; +}; + +#define MSM_GPIO_BROKEN_INT_CLEAR 1 + +struct msm_gpio_chip { + struct gpio_chip chip; + struct msm_gpio_regs regs; +#if MSM_GPIO_BROKEN_INT_CLEAR + unsigned int_status_copy; +#endif + unsigned int both_edge_detect; + unsigned int int_enable[2]; /* 0: awake, 1: sleep */ +}; + int register_gpio_chip(struct gpio_chip *gpio_chip); #endif -- cgit v1.2.3 From 4a4646a8202a63348d25b4e787a8132d2c69c52a Mon Sep 17 00:00:00 2001 From: Matt Wagantall Date: Fri, 16 Oct 2009 17:08:27 -0700 Subject: msm: clock-7x30: Add image rotator clock support. Change-Id: I4e07e0da136889f2741a2e74463c04e146fcad75 Signed-off-by: Matt Wagantall --- arch/arm/mach-msm/clock-7x30.c | 3 +++ arch/arm/mach-msm/clock-7x30.h | 3 +++ 2 files changed, 6 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/clock-7x30.c b/arch/arm/mach-msm/clock-7x30.c index 2d52a53db1de..90a29fbf73d7 100644 --- a/arch/arm/mach-msm/clock-7x30.c +++ b/arch/arm/mach-msm/clock-7x30.c @@ -512,6 +512,8 @@ static struct clk_local clk_local_tbl[] = { CLK_GLBL(MDP_P, GLBL_CLK_ENA_2_SC, B(6)), CLK_GLBL(MFC_P, GLBL_CLK_ENA_2_SC, B(26)), CLK_GLBL(PMDH_P, GLBL_CLK_ENA_2_SC, B(4)), + CLK_GLBL(ROTATOR_IMEM, GLBL_CLK_ENA_2_SC, B(23)), + CLK_GLBL(ROTATOR_P, GLBL_CLK_ENA_2_SC, B(25)), CLK_GLBL(SDC1_H, GLBL_CLK_ENA_SC, B(7)), CLK_GLBL(SDC2_H, GLBL_CLK_ENA_SC, B(8)), CLK_GLBL(SDC3_H, GLBL_CLK_ENA_SC, B(27)), @@ -538,6 +540,7 @@ static struct clk_local clk_local_tbl[] = { CLK_BRIDGE(AXI_GRP_2D, GLBL_CLK_ENA_SC, B(21), AXI_LI_VG), CLK_BRIDGE(AXI_LI_GRP, GLBL_CLK_ENA_SC, B(22), AXI_LI_VG), CLK_BRIDGE(AXI_MFC, GLBL_CLK_ENA_2_SC, B(20), AXI_LI_VG), + CLK_BRIDGE(AXI_ROTATOR, GLBL_CLK_ENA_2_SC, B(22), AXI_LI_VG), CLK_BRIDGE(AXI_VPE, GLBL_CLK_ENA_2_SC, B(21), AXI_LI_VG), }; diff --git a/arch/arm/mach-msm/clock-7x30.h b/arch/arm/mach-msm/clock-7x30.h index 8aa92f2e0d1a..362035d0dceb 100644 --- a/arch/arm/mach-msm/clock-7x30.h +++ b/arch/arm/mach-msm/clock-7x30.h @@ -73,6 +73,8 @@ enum { L_7X30_LPA_P_CLK, L_7X30_MIDI_CLK, L_7X30_MDC_CLK, + L_7X30_ROTATOR_IMEM_CLK, + L_7X30_ROTATOR_P_CLK, L_7X30_SDAC_M_CLK, L_7X30_SDAC_S_CLK, L_7X30_UART1_CLK, @@ -117,6 +119,7 @@ enum { L_7X30_AXI_MDP_CLK, L_7X30_AXI_IMEM_CLK, L_7X30_AXI_LI_ADSP_A_CLK, + L_7X30_AXI_ROTATOR_CLK, L_7X30_NR_CLKS }; -- cgit v1.2.3 From f5d43b2cb9fb004a8597a003ec14bb69792b6525 Mon Sep 17 00:00:00 2001 From: "Vishwanathapura, Niranjana" Date: Wed, 7 Oct 2009 15:35:23 -0600 Subject: msm: Add module to test proc comm system Add moulde to test the proc comm system. Module sends a predefined proc comm command to modem and expect a known return. Signed-off-by: Niranjana Vishwanathapura --- arch/arm/mach-msm/Kconfig | 7 ++ arch/arm/mach-msm/Makefile | 1 + arch/arm/mach-msm/proc_comm_test.c | 169 +++++++++++++++++++++++++++++++++++++ 3 files changed, 177 insertions(+) create mode 100644 arch/arm/mach-msm/proc_comm_test.c (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index 660986cee7fb..d9909d13aaad 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -497,6 +497,13 @@ config MSM_RPC_PING help Implements MSM rpc ping test module. +config MSM_RPC_PROC_COMM_TEST + depends on DEBUG_FS + default m + bool "MSM rpc proc comm test" + help + Implements MSM rpc proc comm test module. + config MSM_RPC_OEM_RAPI depends on MSM_ONCRPCROUTER default m diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 4d5d8ea03041..79275c422d0c 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -37,6 +37,7 @@ obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_device.o obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_servers.o obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_clients.o obj-$(CONFIG_MSM_RPC_PING) += ping_mdm_rpc_client.o +obj-$(CONFIG_MSM_RPC_PROC_COMM_TEST) += proc_comm_test.o obj-$(CONFIG_MSM_RPC_OEM_RAPI) += oem_rapi_client.o obj-$(CONFIG_MSM_RPCSERVERS) += rpc_server_dog_keepalive.o obj-$(CONFIG_MSM_RPCSERVERS) += rpc_server_time_remote.o diff --git a/arch/arm/mach-msm/proc_comm_test.c b/arch/arm/mach-msm/proc_comm_test.c new file mode 100644 index 000000000000..e38b8d651d27 --- /dev/null +++ b/arch/arm/mach-msm/proc_comm_test.c @@ -0,0 +1,169 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* + * PROC COMM TEST Driver source file + */ + +#include +#include +#include +#include +#include "proc_comm.h" + +static struct dentry *dent; +static int proc_comm_test_res; + +static int proc_comm_reverse_test(void) +{ + uint32_t data1, data2; + int rc; + + data1 = 10; + data2 = 20; + + rc = msm_proc_comm(PCOM_OEM_TEST_CMD, &data1, &data2); + if (rc) + return rc; + + if ((data1 != 20) || (data2 != 10)) + return -1; + + return 0; +} + +static ssize_t debug_read(struct file *fp, char __user *buf, + size_t count, loff_t *pos) +{ + char _buf[16]; + + snprintf(_buf, sizeof(_buf), "%i\n", proc_comm_test_res); + + return simple_read_from_buffer(buf, count, pos, _buf, strlen(_buf)); +} + +static ssize_t debug_write(struct file *fp, const char __user *buf, + size_t count, loff_t *pos) +{ + + unsigned char cmd[64]; + int len; + + if (count < 1) + return 0; + + len = count > 63 ? 63 : count; + + if (copy_from_user(cmd, buf, len)) + return -EFAULT; + + cmd[len] = 0; + + if (cmd[len-1] == '\n') { + cmd[len-1] = 0; + len--; + } + + if (!strncmp(cmd, "reverse_test", 64)) + proc_comm_test_res = proc_comm_reverse_test(); + else + proc_comm_test_res = -EINVAL; + + if (proc_comm_test_res) + pr_err("proc comm test fail %d\n", + proc_comm_test_res); + else + pr_info("proc comm test passed\n"); + + return count; +} + +static int debug_release(struct inode *ip, struct file *fp) +{ + return 0; +} + +static int debug_open(struct inode *ip, struct file *fp) +{ + return 0; +} + +static const struct file_operations debug_ops = { + .owner = THIS_MODULE, + .open = debug_open, + .release = debug_release, + .read = debug_read, + .write = debug_write, +}; + +static void __exit proc_comm_test_mod_exit(void) +{ + debugfs_remove(dent); +} + +static int __init proc_comm_test_mod_init(void) +{ + dent = debugfs_create_file("proc_comm", 0444, 0, NULL, &debug_ops); + proc_comm_test_res = -1; + return 0; +} + +module_init(proc_comm_test_mod_init); +module_exit(proc_comm_test_mod_exit); + +MODULE_DESCRIPTION("PROC COMM TEST Driver"); +MODULE_LICENSE("Dual BSD/GPL"); -- cgit v1.2.3 From dfe851084705e0295945c2a324371db9c41b0615 Mon Sep 17 00:00:00 2001 From: Chandan Uddaraju Date: Thu, 22 Oct 2009 11:44:15 -0700 Subject: msm: socinfo: add SoC ID of 61 of ESM7x27 to 7x27 list. ESM7x27 is a EDGE target of 7x27 family. It is using a new SoC id. Signed-off-by: Chandan Uddaraju --- arch/arm/mach-msm/socinfo.c | 1 + 1 file changed, 1 insertion(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c index 3944347ae506..0c65e25c9c66 100644 --- a/arch/arm/mach-msm/socinfo.c +++ b/arch/arm/mach-msm/socinfo.c @@ -137,6 +137,7 @@ static enum msm_cpu cpu_of_id[] = { /* 7x27 IDs */ [43] = MSM_CPU_7X27, [44] = MSM_CPU_7X27, + [61] = MSM_CPU_7X27, /* 8x50 IDs */ [30] = MSM_CPU_8X50, -- cgit v1.2.3 From d0a45188b34bb240f3d164c954fc9ffc2229fac0 Mon Sep 17 00:00:00 2001 From: Matt Wagantall Date: Wed, 7 Oct 2009 12:37:28 -0700 Subject: msm: clock-7x30: Add support for local PLL enable/disable. The 7x30 SoC includes h/w that allows each processor to vote on enabling/disabling a PLL. Use the voting h/w to enable/disable PLLs instead of making proc-comm calls to the modem processor. Also, create an API that can be called from the acpuclock code. Change-Id: I825d11787c3310adcd20aa4db65a077c906fcc7d Signed-off-by: Matt Wagantall --- arch/arm/mach-msm/clock-7x30.c | 85 +++++++++++++++++++++++------------------- arch/arm/mach-msm/clock-7x30.h | 3 ++ arch/arm/mach-msm/clock.h | 11 ++++++ 3 files changed, 61 insertions(+), 38 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/clock-7x30.c b/arch/arm/mach-msm/clock-7x30.c index 90a29fbf73d7..d1bab48c85fa 100644 --- a/arch/arm/mach-msm/clock-7x30.c +++ b/arch/arm/mach-msm/clock-7x30.c @@ -100,17 +100,11 @@ enum { SRC_MAX /* Used for sources that can't be turned on/off. */ }; -struct pll_data { - int count; - uint32_t bit_mask; -}; - -static struct pll_data pll_tbl[SRC_MAX] = { - /* FIXME: Put in proper values for bit_mask. */ - [SRC_PLL0] = { 0, 0 }, - [SRC_PLL1] = { 0, 0 }, - [SRC_PLL3] = { 0, 0 }, - [SRC_PLL4] = { 0, 0 }, +static uint32_t src_pll_tbl[] = { + [SRC_PLL0] = PLL_0, + [SRC_PLL1] = PLL_1, + [SRC_PLL3] = PLL_3, + [SRC_PLL4] = PLL_4, }; #define B(x) BIT(x) @@ -406,6 +400,8 @@ static struct clk_freq_tbl dummy_freq = F_END; #define MDP_VSYNC_REG 0x0460 #define PLL_ENA_REG 0x0260 +static uint32_t pll_count[NUM_PLL]; + static uint32_t chld_grp_3d_src[] = {C(IMEM), C(GRP_3D), C(NONE)}; static uint32_t chld_mdp_lcdc_p[] = {C(MDP_LCDC_PAD_P), C(NONE)}; static uint32_t chld_mi2s_codec_rx[] = {C(MI2S_CODEC_RX_S), C(NONE)}; @@ -545,48 +541,61 @@ static struct clk_local clk_local_tbl[] = { }; static DEFINE_SPINLOCK(clock_reg_lock); +static DEFINE_SPINLOCK(pll_vote_lock); void pll_enable(uint32_t pll) { - struct pll_data *p; uint32_t reg_val; + unsigned long flags; - /* SRC_MAX is used as a placeholder for some freqencies that don't - * have any direct PLL dependency. */ - if (pll == SRC_MAX || pll == SRC_LPXO) - return; - - p = &pll_tbl[pll]; - if (!p->count) { + spin_lock_irqsave(&pll_vote_lock, flags); + if (!pll_count[pll]) { reg_val = readl(REG(PLL_ENA_REG)); - reg_val |= p->bit_mask; + reg_val |= (1 << pll); writel(reg_val, REG(PLL_ENA_REG)); } - p->count++; + pll_count[pll]++; + spin_unlock_irqrestore(&pll_vote_lock, flags); } -void pll_disable(uint32_t pll) +static void src_enable(uint32_t src) { - struct pll_data *p; - uint32_t reg_val; - /* SRC_MAX is used as a placeholder for some freqencies that don't * have any direct PLL dependency. */ - if (pll == SRC_MAX || pll == SRC_LPXO) + if (src == SRC_MAX || src == SRC_LPXO) return; - p = &pll_tbl[pll]; - if (!p->count) { + pll_enable(src_pll_tbl[src]); +} + +void pll_disable(uint32_t pll) +{ + uint32_t reg_val; + unsigned long flags; + + spin_lock_irqsave(&pll_vote_lock, flags); + if (pll_count[pll]) + pll_count[pll]--; + else pr_warning("Reference count mismatch in PLL disable!\n"); - return; - } - if (p->count) - p->count--; - if (p->count == 0) { + + if (pll_count[pll] == 0) { reg_val = readl(REG(PLL_ENA_REG)); - reg_val &= ~(p->bit_mask); + reg_val &= ~(1 << pll); writel(reg_val, REG(PLL_ENA_REG)); } + spin_unlock_irqrestore(&pll_vote_lock, flags); +} + +static void src_disable(uint32_t src) +{ + /* SRC_MAX is used as a placeholder for some freqencies that don't + * have any direct PLL dependency. */ + if (src == SRC_MAX || src == SRC_LPXO) + return; + + pll_disable(src_pll_tbl[src]); + } /* @@ -648,7 +657,7 @@ static int soc_clk_enable_nolock(unsigned id) if (!t->count) { if (t->parent != C(NONE)) soc_clk_enable_nolock(t->parent); - pll_enable(t->current_freq->src); + src_enable(t->current_freq->src); ret = _soc_clk_enable(id); } t->count++; @@ -668,7 +677,7 @@ static void soc_clk_disable_nolock(unsigned id) t->count--; if (t->count == 0) { _soc_clk_disable(id); - pll_disable(t->current_freq->src); + src_disable(t->current_freq->src); if (t->parent != C(NONE)) soc_clk_disable_nolock(t->parent); } @@ -754,7 +763,7 @@ static int soc_clk_set_rate(unsigned id, unsigned rate) _soc_clk_disable(id); /* Turn on PLL of the new freq. */ - pll_enable(nf->src); + src_enable(nf->src); /* Some clocks share the same register, so must be careful when * assuming a register doesn't need to be re-read. */ @@ -779,7 +788,7 @@ static int soc_clk_set_rate(unsigned id, unsigned rate) } /* Turn off PLL of the old freq. */ - pll_disable(cf->src); + src_disable(cf->src); /* Current freq must be updated before _soc_clk_enable() is called to * make sure the MNCNTR_E bit is set correctly. */ diff --git a/arch/arm/mach-msm/clock-7x30.h b/arch/arm/mach-msm/clock-7x30.h index 362035d0dceb..7480ace1a986 100644 --- a/arch/arm/mach-msm/clock-7x30.h +++ b/arch/arm/mach-msm/clock-7x30.h @@ -127,6 +127,9 @@ enum { struct clk_ops; extern struct clk_ops clk_ops_7x30; +void pll_enable(uint32_t pll); +void pll_disable(uint32_t pll); + #define CLK_7X30(clk_name, clk_id, clk_dev, clk_flags) { \ .name = clk_name, \ .id = L_7X30_##clk_id, \ diff --git a/arch/arm/mach-msm/clock.h b/arch/arm/mach-msm/clock.h index 66cd44f8b720..9608a6c6bbcb 100644 --- a/arch/arm/mach-msm/clock.h +++ b/arch/arm/mach-msm/clock.h @@ -81,6 +81,17 @@ struct clk { #define CLK_MINMAX (CLK_MIN | CLK_MAX) #define NR_CLKS P_NR_CLKS +enum { + PLL_0 = 0, + PLL_1, + PLL_2, + PLL_3, + PLL_4, + PLL_5, + PLL_6, + NUM_PLL +}; + enum clkvote_client { CLKVOTE_ACPUCLK = 0, CLKVOTE_PMQOS, -- cgit v1.2.3 From 6acb8ae5b2daa86c21ef9a84ddf1c284bd10c9fe Mon Sep 17 00:00:00 2001 From: Karthik Parsha Date: Wed, 14 Oct 2009 17:36:27 -0700 Subject: msm: acpuclock-8x50: Remove support for frequencies based on PLL1. PLL1 might not always be on. Also, it doesn't offer any frequencies that are useful when compared to the rest of the available frequencies. Hence removing frequencies based on PLL1. Change-Id: I823906bdbd137b883cfd116f425735eaae555a09 Signed-off-by: Karthik Parsha --- arch/arm/mach-msm/acpuclock-8x50.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/acpuclock-8x50.c b/arch/arm/mach-msm/acpuclock-8x50.c index d02d1b56821e..dde6900b0f0a 100644 --- a/arch/arm/mach-msm/acpuclock-8x50.c +++ b/arch/arm/mach-msm/acpuclock-8x50.c @@ -109,13 +109,8 @@ struct clkctl_acpu_speed { struct clkctl_acpu_speed acpu_freq_tbl[] = { { 0, 19200, ACPU_PLL_TCXO, 0, 0, 0, 0, 14000, 0, 0, 1000}, - { 0, 48000, ACPU_PLL_1, 1, 0xF, 0, 0, 14000, 0, 0, 1000}, - { 0, 64000, ACPU_PLL_1, 1, 0xB, 0, 0, 14000, 0, 0, 1000}, - { 0, 96000, ACPU_PLL_1, 1, 7, 0, 0, 14000, 0, 0, 1000}, { 0, 128000, ACPU_PLL_1, 1, 5, 0, 0, 14000, 2, 0, 1000}, - { 0, 192000, ACPU_PLL_1, 1, 3, 0, 0, 14000, 0, 0, 1000}, { 1, 245760, ACPU_PLL_0, 4, 0, 0, 0, 29000, 0, 0, 1000}, - { 0, 256000, ACPU_PLL_1, 1, 2, 0, 0, 29000, 0, 0, 1000}, { 1, 384000, ACPU_PLL_3, 0, 0, 0, 0, 58000, 1, 0xA, 1000}, { 0, 422400, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0xB, 1000}, { 0, 460800, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0xC, 1000}, -- cgit v1.2.3 From 84260e7e24e3ec6f5d562b96ed9d7df27a99b21b Mon Sep 17 00:00:00 2001 From: Ai Li Date: Thu, 15 Oct 2009 19:12:33 -0600 Subject: msm: timer: use tiered method to sync DGT after power collapse The time-sync protocol is not intended to support DGT. When sclk wraps, it can cause DGT to jump. In the tiered method, GPT syncs to sclk via the time-sync protocol, and DGT syncs to GPT. Because both DGT and GPT are local, syncing DGT to GPT is fast and can occur more often to detect GPT wrapping around. Signed-off-by: Ai Li --- arch/arm/mach-msm/pm.c | 4 +- arch/arm/mach-msm/pm2.c | 4 +- arch/arm/mach-msm/timer.c | 278 ++++++++++++++++++++++++++++------------------ arch/arm/mach-msm/timer.h | 2 +- 4 files changed, 174 insertions(+), 114 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/pm.c b/arch/arm/mach-msm/pm.c index 47be607e235c..78ca91ff42e0 100644 --- a/arch/arm/mach-msm/pm.c +++ b/arch/arm/mach-msm/pm.c @@ -624,7 +624,7 @@ static int msm_pm_enter(suspend_state_t state) int64_t period = 0; int64_t time = 0; - time = msm_timer_get_smem_clock_time(&period); + time = msm_timer_get_sclk_time(&period); ret = msm_clock_require_tcxo(clk_ids, NR_CLKS); #elif defined(CONFIG_CLOCK_BASED_SLEEP_LIMIT) ret = msm_clock_require_tcxo(NULL, 0); @@ -663,7 +663,7 @@ static int msm_pm_enter(suspend_state_t state) } if (time != 0) { - end_time = msm_timer_get_smem_clock_time(NULL); + end_time = msm_timer_get_sclk_time(NULL); if (end_time != 0) { time = end_time - time; if (time < 0) diff --git a/arch/arm/mach-msm/pm2.c b/arch/arm/mach-msm/pm2.c index 6ce1b6d883fc..b601a528f91a 100644 --- a/arch/arm/mach-msm/pm2.c +++ b/arch/arm/mach-msm/pm2.c @@ -1431,7 +1431,7 @@ static int msm_pm_enter(suspend_state_t state) int64_t period = 0; int64_t time = 0; - time = msm_timer_get_smem_clock_time(&period); + time = msm_timer_get_sclk_time(&period); ret = msm_clock_require_tcxo(clk_ids, NR_CLKS); #elif defined(CONFIG_CLOCK_BASED_SLEEP_LIMIT) ret = msm_clock_require_tcxo(NULL, 0); @@ -1509,7 +1509,7 @@ static int msm_pm_enter(suspend_state_t state) } if (time != 0) { - end_time = msm_timer_get_smem_clock_time(NULL); + end_time = msm_timer_get_sclk_time(NULL); if (end_time != 0) { time = end_time - time; if (time < 0) diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c index 20a21441c024..db3aeb909cf2 100644 --- a/arch/arm/mach-msm/timer.c +++ b/arch/arm/mach-msm/timer.c @@ -93,12 +93,15 @@ struct msm_clock { uint32_t flags; uint32_t write_delay; uint32_t last_set; - uint32_t offset; + uint32_t sleep_offset; uint32_t alarm_vtime; - uint32_t smem_offset; - uint32_t smem_in_sync; + uint32_t non_sleep_offset; + uint32_t in_sync; cycle_t stopped_tick; int stopped; + uint32_t rollover_offset; + uint32_t last_sync_gpt; + u64 last_sync_jiffies; }; enum { MSM_CLOCK_GPT, @@ -148,7 +151,7 @@ static cycle_t msm_gpt_read(struct clocksource *cs) if (clock->stopped) return clock->stopped_tick; else - return msm_read_timer_count(clock) + clock->offset; + return msm_read_timer_count(clock) + clock->sleep_offset; } static cycle_t msm_dgt_read(struct clocksource *cs) @@ -156,7 +159,8 @@ static cycle_t msm_dgt_read(struct clocksource *cs) struct msm_clock *clock = &msm_clocks[MSM_CLOCK_DGT]; if (clock->stopped) return clock->stopped_tick >> MSM_DGT_SHIFT; - return (msm_read_timer_count(clock) + clock->offset) >> MSM_DGT_SHIFT; + return (msm_read_timer_count(clock) + clock->sleep_offset) + >> MSM_DGT_SHIFT; } static int msm_timer_set_next_event(unsigned long cycles, @@ -183,7 +187,7 @@ static int msm_timer_set_next_event(unsigned long cycles, } now = msm_read_timer_count(clock); clock->last_set = now; - clock->alarm_vtime = alarm + clock->offset; + clock->alarm_vtime = alarm + clock->sleep_offset; late = now - alarm; if (late >= (int)(-clock->write_delay << clock->shift) && late < DGT_HZ*5) { static int print_limit = 10; @@ -203,6 +207,7 @@ static int msm_timer_set_next_event(unsigned long cycles, static void msm_timer_set_mode(enum clock_event_mode mode, struct clock_event_device *evt) { + struct msm_clock *gpt_clk = &msm_clocks[MSM_CLOCK_GPT]; struct msm_clock *clock; unsigned long irq_flags; @@ -215,32 +220,38 @@ static void msm_timer_set_mode(enum clock_event_mode mode, break; case CLOCK_EVT_MODE_ONESHOT: clock->stopped = 0; - clock->offset = -msm_read_timer_count(clock) + + clock->sleep_offset = -msm_read_timer_count(clock) + clock->stopped_tick; msm_active_clock = clock; writel(TIMER_ENABLE_EN, clock->regbase + TIMER_ENABLE); + if (clock != gpt_clk) + writel(TIMER_ENABLE_EN, + gpt_clk->regbase + TIMER_ENABLE); break; case CLOCK_EVT_MODE_UNUSED: case CLOCK_EVT_MODE_SHUTDOWN: msm_active_clock = NULL; - clock->smem_in_sync = 0; + clock->in_sync = 0; clock->stopped = 1; clock->stopped_tick = msm_read_timer_count(clock) + - clock->offset; + clock->sleep_offset; writel(0, clock->regbase + TIMER_ENABLE); + if (clock != gpt_clk) { + gpt_clk->in_sync = 0; + writel(0, gpt_clk->regbase + TIMER_ENABLE); + } break; } local_irq_restore(irq_flags); } /* - * Retrieve the cycle count from the slow clock through SMEM and optionally - * synchronize local clock(s) with the slow clock. The function implements - * the inter-processor time-sync protocol. + * Retrieve the cycle count from sclk and optionally synchronize local clock + * with the sclk value. * * time_start and time_expired are callbacks that must be specified. The * protocol uses them to detect timeout. The update callback is optional. - * If not NULL, update will be called so that it can update local clock(s). + * If not NULL, update will be called so that it can update local clock. * * The function does not use the argument data directly; it passes data to * the callbacks. @@ -250,10 +261,10 @@ static void msm_timer_set_mode(enum clock_event_mode mode, * >0: the slow clock value after time-sync */ #if defined(CONFIG_MSM_N_WAY_SMSM) -static uint32_t msm_timer_sync_sclk( +static uint32_t msm_timer_do_sync_to_sclk( void (*time_start)(struct msm_timer_sync_data_t *data), bool (*time_expired)(struct msm_timer_sync_data_t *data), - void (*update)(struct msm_timer_sync_data_t *data, uint32_t clk_val), + void (*update)(struct msm_timer_sync_data_t *, uint32_t, uint32_t), struct msm_timer_sync_data_t *data) { uint32_t *smem_clock; @@ -307,7 +318,7 @@ static uint32_t msm_timer_sync_sclk( if (smem_clock_val) { if (update != NULL) - update(data, smem_clock_val); + update(data, smem_clock_val, SCLK_HZ); if (msm_timer_debug_mask & MSM_TIMER_DEBUG_SYNC) printk(KERN_INFO @@ -324,10 +335,10 @@ sync_sclk_exit: return smem_clock_val; } #else /* CONFIG_MSM_N_WAY_SMSM */ -static uint32_t msm_timer_sync_sclk( +static uint32_t msm_timer_do_sync_to_sclk( void (*time_start)(struct msm_timer_sync_data_t *data), bool (*time_expired)(struct msm_timer_sync_data_t *data), - void (*update)(struct msm_timer_sync_data_t *data, uint32_t clk_val), + void (*update)(struct msm_timer_sync_data_t *, uint32_t, uint32_t), struct msm_timer_sync_data_t *data) { uint32_t *smem_clock; @@ -380,7 +391,7 @@ static uint32_t msm_timer_sync_sclk( if (smem_clock_val) { if (update != NULL) - update(data, smem_clock_val); + update(data, smem_clock_val, SCLK_HZ); } else { printk(KERN_INFO "get_smem_clock: timeout state %x clock %u\n", state, smem_clock_val); @@ -401,7 +412,7 @@ static uint32_t msm_timer_sync_sclk( /* * Callback function that initializes the timeout value. */ -static void msm_timer_sync_smem_clock_time_start( +static void msm_timer_sync_to_sclk_time_start( struct msm_timer_sync_data_t *data) { /* approx 1/128th of a second */ @@ -412,7 +423,7 @@ static void msm_timer_sync_smem_clock_time_start( /* * Callback function that checks the timeout. */ -static bool msm_timer_sync_smem_clock_time_expired( +static bool msm_timer_sync_to_sclk_time_expired( struct msm_timer_sync_data_t *data) { uint32_t delta = msm_read_timer_count(data->clock) - data->timeout; @@ -420,93 +431,110 @@ static bool msm_timer_sync_smem_clock_time_expired( } /* - * Callback function that updates clock(s) with the specified slow clock - * value. The GPT clock is always updated. + * Callback function that updates local clock from the specified source clock + * value and frequency. */ -static void msm_timer_sync_smem_clock_update( - struct msm_timer_sync_data_t *data, uint32_t clock_value) +static void msm_timer_sync_update(struct msm_timer_sync_data_t *data, + uint32_t src_clk_val, uint32_t src_clk_freq) { - struct msm_clock *clocks[2]; - uint32_t timer_counts[2]; - int i; + struct msm_clock *dst_clk = data->clock; + uint32_t dst_clk_val = msm_read_timer_count(dst_clk); + uint32_t new_offset; - clocks[0] = data->clock; - - if (data->clock != &msm_clocks[MSM_CLOCK_GPT]) - clocks[1] = &msm_clocks[MSM_CLOCK_GPT]; - else - clocks[1] = NULL; + if ((dst_clk->freq << dst_clk->shift) == src_clk_freq) { + new_offset = src_clk_val - dst_clk_val; + } else { + uint64_t temp; - for (i = 0; i < ARRAY_SIZE(clocks); i++) { - if (clocks[i] == NULL) - continue; + /* separate multiplication and division steps to reduce + rounding error */ + temp = src_clk_val; + temp *= dst_clk->freq << dst_clk->shift; + do_div(temp, src_clk_freq); - timer_counts[i] = msm_read_timer_count(clocks[i]); + new_offset = (uint32_t)(temp) - dst_clk_val; } - for (i = 0; i < ARRAY_SIZE(clocks); i++) { - uint32_t new_offset; - uint64_t temp; + if (dst_clk->sleep_offset + dst_clk->non_sleep_offset != new_offset) { + if (data->exit_sleep) + dst_clk->sleep_offset = + new_offset - dst_clk->non_sleep_offset; + else + dst_clk->non_sleep_offset = + new_offset - dst_clk->sleep_offset; - if (clocks[i] == NULL) - continue; + if (msm_timer_debug_mask & MSM_TIMER_DEBUG_SYNC) + printk(KERN_INFO "sync clock %s: " + "src %u, new offset %u + %u\n", + dst_clk->clocksource.name, src_clk_val, + dst_clk->sleep_offset, + dst_clk->non_sleep_offset); + } +} - /* separate multiplication and division steps to reduce - rounding error */ - temp = clock_value; - temp *= clocks[i]->freq << clocks[i]->shift; - temp /= SCLK_HZ; - new_offset = (uint32_t)(temp) - timer_counts[i]; +/* + * Synchronize GPT clock with sclk. + */ +static void msm_timer_sync_gpt_to_sclk(int exit_sleep) +{ + struct msm_clock *gpt_clk = &msm_clocks[MSM_CLOCK_GPT]; + struct msm_timer_sync_data_t data; + uint32_t ret; - if (clocks[i]->offset + clocks[i]->smem_offset != new_offset) { - if (data->exit_sleep) - clocks[i]->offset - = new_offset - clocks[i]->smem_offset; - else - clocks[i]->smem_offset - = new_offset - clocks[i]->offset; + if (gpt_clk->in_sync) + return; - clocks[i]->smem_in_sync = 1; + data.clock = gpt_clk; + data.timeout = 0; + data.exit_sleep = exit_sleep; - if (msm_timer_debug_mask & MSM_TIMER_DEBUG_SYNC) - printk(KERN_INFO "get_smem_clock: " - "clock %u new offset %u+%u\n", - clock_value, clocks[i]->offset, - clocks[i]->smem_offset); - } - } + ret = msm_timer_do_sync_to_sclk( + msm_timer_sync_to_sclk_time_start, + msm_timer_sync_to_sclk_time_expired, + msm_timer_sync_update, + &data); + + if (ret) + gpt_clk->in_sync = 1; } /* - * Synchronize clock(s) with the slow clock through SMEM. - * - * Return value: - * 0: the operation failed - * >0: the slow clock value after time-sync + * Synchronize clock with GPT clock. */ -static uint32_t msm_timer_sync_smem_clock(struct msm_clock *clock, - int exit_sleep) +static void msm_timer_sync_to_gpt(struct msm_clock *clock, int exit_sleep) { + struct msm_clock *gpt_clk = &msm_clocks[MSM_CLOCK_GPT]; struct msm_timer_sync_data_t data; + uint32_t gpt_clk_val; + u64 gpt_period = (1ULL << 32) * HZ / GPT_HZ; + u64 now = get_jiffies_64(); - if (!exit_sleep && clock->smem_in_sync && - msm_clocks[MSM_CLOCK_GPT].smem_in_sync) - return 0; + BUG_ON(clock == gpt_clk); + + if (clock->in_sync && + (now - clock->last_sync_jiffies < (gpt_period >> 1))) + return; + + gpt_clk_val = msm_read_timer_count(gpt_clk) + + gpt_clk->sleep_offset + gpt_clk->non_sleep_offset; + + if (exit_sleep && gpt_clk_val < clock->last_sync_gpt) + clock->non_sleep_offset -= clock->rollover_offset; data.clock = clock; data.timeout = 0; data.exit_sleep = exit_sleep; - return msm_timer_sync_sclk( - msm_timer_sync_smem_clock_time_start, - msm_timer_sync_smem_clock_time_expired, - msm_timer_sync_smem_clock_update, - &data); + msm_timer_sync_update(&data, gpt_clk_val, GPT_HZ); + + clock->in_sync = 1; + clock->last_sync_gpt = gpt_clk_val; + clock->last_sync_jiffies = now; } static void msm_timer_reactivate_alarm(struct msm_clock *clock) { - long alarm_delta = clock->alarm_vtime - clock->offset - + long alarm_delta = clock->alarm_vtime - clock->sleep_offset - msm_read_timer_count(clock); alarm_delta >>= clock->shift; if (alarm_delta < (long)clock->write_delay + 4) @@ -517,6 +545,7 @@ static void msm_timer_reactivate_alarm(struct msm_clock *clock) int64_t msm_timer_enter_idle(void) { + struct msm_clock *gpt_clk = &msm_clocks[MSM_CLOCK_GPT]; struct msm_clock *clock = msm_active_clock; uint32_t alarm; uint32_t count; @@ -525,11 +554,13 @@ int64_t msm_timer_enter_idle(void) BUG_ON(clock != &msm_clocks[MSM_CLOCK_GPT] && clock != &msm_clocks[MSM_CLOCK_DGT]); - msm_timer_sync_smem_clock(clock, 0); + msm_timer_sync_gpt_to_sclk(0); + if (clock != gpt_clk) + msm_timer_sync_to_gpt(clock, 0); count = msm_read_timer_count(clock); if (clock->stopped++ == 0) - clock->stopped_tick = count + clock->offset; + clock->stopped_tick = count + clock->sleep_offset; alarm = readl(clock->regbase + TIMER_MATCH_VAL); delta = alarm - count; if (delta <= -(int32_t)((clock->freq << clock->shift) >> 10)) { @@ -545,35 +576,52 @@ int64_t msm_timer_enter_idle(void) void msm_timer_exit_idle(int low_power) { + struct msm_clock *gpt_clk = &msm_clocks[MSM_CLOCK_GPT]; struct msm_clock *clock = msm_active_clock; - uint32_t smem_clock; + uint32_t enabled; BUG_ON(clock != &msm_clocks[MSM_CLOCK_GPT] && clock != &msm_clocks[MSM_CLOCK_DGT]); - if (low_power) { -#if !defined(CONFIG_ARCH_MSM_SCORPION) - if (!(readl(clock->regbase+TIMER_ENABLE) & TIMER_ENABLE_EN)) + if (!low_power) + goto exit_idle_exit; + + enabled = readl(gpt_clk->regbase + TIMER_ENABLE) & TIMER_ENABLE_EN; + if (!enabled) + writel(TIMER_ENABLE_EN, gpt_clk->regbase + TIMER_ENABLE); + +#if defined(CONFIG_ARCH_MSM_SCORPION) + gpt_clk->in_sync = 0; +#else + gpt_clk->in_sync = gpt_clk->in_sync && enabled; #endif - { - writel(TIMER_ENABLE_EN, clock->regbase + TIMER_ENABLE); - if (clock != &msm_clocks[MSM_CLOCK_GPT]) { - struct msm_clock *gpt = - &msm_clocks[MSM_CLOCK_GPT]; - writel(TIMER_ENABLE_EN, - gpt->regbase + TIMER_ENABLE); - } - smem_clock = msm_timer_sync_smem_clock(clock, 1); - } - msm_timer_reactivate_alarm(clock); - } + msm_timer_sync_gpt_to_sclk(1); + + if (clock == gpt_clk) + goto exit_idle_alarm; + + enabled = readl(clock->regbase + TIMER_ENABLE) & TIMER_ENABLE_EN; + if (!enabled) + writel(TIMER_ENABLE_EN, clock->regbase + TIMER_ENABLE); + +#if defined(CONFIG_ARCH_MSM_SCORPION) + clock->in_sync = 0; +#else + clock->in_sync = clock->in_sync && enabled; +#endif + msm_timer_sync_to_gpt(clock, 1); + +exit_idle_alarm: + msm_timer_reactivate_alarm(clock); + +exit_idle_exit: clock->stopped--; } /* * Callback function that initializes the timeout value. */ -static void msm_timer_get_smem_clock_time_start( +static void msm_timer_get_sclk_time_start( struct msm_timer_sync_data_t *data) { data->timeout = 10000; @@ -582,34 +630,34 @@ static void msm_timer_get_smem_clock_time_start( /* * Callback function that checks the timeout. */ -static bool msm_timer_get_smem_clock_time_expired( +static bool msm_timer_get_sclk_time_expired( struct msm_timer_sync_data_t *data) { return --data->timeout <= 0; } /* - * Retrieve the cycle count from the slow clock through SMEM and - * convert it into nanoseconds. + * Retrieve the cycle count from the sclk and convert it into + * nanoseconds. * * On exit, if period is not NULL, it contains the period of the - * slow clock in nanoseconds, i.e. how long the cycle count wraps - * around. + * sclk in nanoseconds, i.e. how long the cycle count wraps around. * * Return value: * 0: the operation failed; period is not set either * >0: time in nanoseconds */ -int64_t msm_timer_get_smem_clock_time(int64_t *period) +int64_t msm_timer_get_sclk_time(int64_t *period) { struct msm_timer_sync_data_t data; uint32_t clock_value; int64_t tmp; memset(&data, 0, sizeof(data)); - clock_value = msm_timer_sync_sclk( - msm_timer_get_smem_clock_time_start, - msm_timer_get_smem_clock_time_expired, + + clock_value = msm_timer_do_sync_to_sclk( + msm_timer_get_sclk_time_start, + msm_timer_get_sclk_time_expired, NULL, &data); @@ -617,7 +665,7 @@ int64_t msm_timer_get_smem_clock_time(int64_t *period) return 0; if (period) { - tmp = (int64_t)UINT_MAX; + tmp = 1LL << 32; tmp = tmp * NSEC_PER_SEC / SCLK_HZ; *period = tmp; } @@ -767,6 +815,18 @@ static void __init msm_timer_init(void) writel(0, clock->regbase + TIMER_ENABLE); writel(~0, clock->regbase + TIMER_MATCH_VAL); + if ((clock->freq << clock->shift) == GPT_HZ) { + clock->rollover_offset = 0; + } else { + uint64_t temp; + + temp = clock->freq << clock->shift; + temp <<= 32; + temp /= GPT_HZ; + + clock->rollover_offset = (uint32_t) temp; + } + ce->mult = div_sc(clock->freq, NSEC_PER_SEC, ce->shift); /* allow at least 10 seconds to notice that the timer wrapped */ ce->max_delta_ns = diff --git a/arch/arm/mach-msm/timer.h b/arch/arm/mach-msm/timer.h index 26d20a776160..161751e99c36 100644 --- a/arch/arm/mach-msm/timer.h +++ b/arch/arm/mach-msm/timer.h @@ -33,6 +33,6 @@ extern struct sys_timer msm_timer; int64_t msm_timer_enter_idle(void); void msm_timer_exit_idle(int low_power); -int64_t msm_timer_get_smem_clock_time(int64_t *period); +int64_t msm_timer_get_sclk_time(int64_t *period); int msm_timer_init_time_sync(void); #endif -- cgit v1.2.3 From 5f2780b375c6c91364968328af21475fd5b83639 Mon Sep 17 00:00:00 2001 From: Willie Ruan Date: Sun, 18 Oct 2009 15:03:04 -0700 Subject: msm: add pmic8058-gpio.c to support PM8058 GPIO in gpiolib framework PM8058 has GPIOs which can be used by Linux drivers. The goal is to use the kernel's gpiolib but right now we have to use Google's gpiolib because there can't be two gpiolib implementations. Porting to kernel gpiolib will occur after Google's generic_gpio is ported. Drivers should have configured PM8058 GPIOs using pm8058_gpio_config with full parameters before calling gpiolib APIs. Signed-off-by: Willie Ruan --- arch/arm/mach-msm/Makefile | 1 + arch/arm/mach-msm/pmic8058-gpio.c | 150 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 151 insertions(+) create mode 100644 arch/arm/mach-msm/pmic8058-gpio.c (limited to 'arch') diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 79275c422d0c..8f5be8b176da 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -78,3 +78,4 @@ obj-$(CONFIG_TROUT_BATTCHG) += htc_battery.o obj-$(CONFIG_HTC_PWRSINK) += htc_pwrsink.o obj-$(CONFIG_HTC_HEADSET) += htc_headset.o +obj-$(CONFIG_PMIC8058) += pmic8058-gpio.o diff --git a/arch/arm/mach-msm/pmic8058-gpio.c b/arch/arm/mach-msm/pmic8058-gpio.c new file mode 100644 index 000000000000..09a465d028d9 --- /dev/null +++ b/arch/arm/mach-msm/pmic8058-gpio.c @@ -0,0 +1,150 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +/* + * Qualcomm PMIC8058 GPIO driver + * + */ + +#include +#include +#include "gpio_chip.h" + +#define PM8058_GPIO_TO_INT(n) (PMIC8058_IRQ_BASE + (n)) + +static int pm8058_gpio_configure(struct gpio_chip *chip, + unsigned int gpio, + unsigned long flags) +{ + int rc = 0, direction; + + gpio -= chip->start; + + if (flags & (GPIOF_INPUT | GPIOF_DRIVE_OUTPUT)) { + direction = 0; + if (flags & GPIOF_INPUT) + direction |= PM_GPIO_DIR_IN; + if (flags & GPIOF_DRIVE_OUTPUT) + direction |= PM_GPIO_DIR_OUT; + + if (flags & (GPIOF_OUTPUT_LOW | GPIOF_OUTPUT_HIGH)) { + if (flags & GPIOF_OUTPUT_HIGH) + rc = pm8058_gpio_set(gpio, 1); + else + rc = pm8058_gpio_set(gpio, 0); + + if (rc) { + pr_err("%s: FAIL pm8058_gpio_set(): rc=%d.\n", + __func__, rc); + goto bail_out; + } + } + + rc = pm8058_gpio_set_direction(gpio, direction); + if (rc) + pr_err("%s: FAIL pm8058_gpio_config(): rc=%d.\n", + __func__, rc); + } + +bail_out: + return rc; +} + +static int pm8058_gpio_get_irq_num(struct gpio_chip *chip, + unsigned int gpio, + unsigned int *irqp, + unsigned long *irqnumflagsp) +{ + gpio -= chip->start; + *irqp = PM8058_GPIO_TO_INT(gpio); + if (irqnumflagsp) + *irqnumflagsp = 0; + return 0; +} + +static int pm8058_gpio_read(struct gpio_chip *chip, unsigned n) +{ + n -= chip->start; + return pm8058_gpio_get(n); +} + +static int pm8058_gpio_write(struct gpio_chip *chip, unsigned n, unsigned on) +{ + n -= chip->start; + return pm8058_gpio_set(n, on); +} + +struct msm_gpio_chip pm8058_gpio_chip = { + .chip = { + .start = NR_GPIO_IRQS, + .end = NR_GPIO_IRQS + NR_PMIC8058_GPIO_IRQS - 1, + .configure = pm8058_gpio_configure, + .get_irq_num = pm8058_gpio_get_irq_num, + .read = pm8058_gpio_read, + .write = pm8058_gpio_write, + } +}; + +static int __init pm8058_gpio_init(void) +{ + int rc; + + rc = register_gpio_chip(&pm8058_gpio_chip.chip); + pr_info("%s: register_gpio_chip(): rc=%d\n", __func__, rc); + + return rc; +} +device_initcall(pm8058_gpio_init); -- cgit v1.2.3 From b7a7c417da886776add2ea8de9fd70660544f1f4 Mon Sep 17 00:00:00 2001 From: Willie Ruan Date: Sun, 18 Oct 2009 16:12:42 -0700 Subject: msm: add pmic8058-mpp.c to support PM8058 MPP in gpiolib framework PM8058 has MPPs which can be used by Linux drivers. The goal is to use the kernel's gpiolib but right now we have to use Google's gpiolib because there can't be two gpiolib implementations. Porting to kernel gpiolib will occur after Google's generic_gpio is ported. Only digital input function of a MPP is supported. Drivers should have configured PM8058 MPPs using mpp_config_digital_in before calling gpiolib APIs. Signed-off-by: Willie Ruan --- arch/arm/mach-msm/Makefile | 2 +- arch/arm/mach-msm/pmic8058-mpp.c | 105 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-msm/pmic8058-mpp.c (limited to 'arch') diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 8f5be8b176da..632ea78c3e5d 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -78,4 +78,4 @@ obj-$(CONFIG_TROUT_BATTCHG) += htc_battery.o obj-$(CONFIG_HTC_PWRSINK) += htc_pwrsink.o obj-$(CONFIG_HTC_HEADSET) += htc_headset.o -obj-$(CONFIG_PMIC8058) += pmic8058-gpio.o +obj-$(CONFIG_PMIC8058) += pmic8058-gpio.o pmic8058-mpp.o diff --git a/arch/arm/mach-msm/pmic8058-mpp.c b/arch/arm/mach-msm/pmic8058-mpp.c new file mode 100644 index 000000000000..5c4f396c544b --- /dev/null +++ b/arch/arm/mach-msm/pmic8058-mpp.c @@ -0,0 +1,105 @@ +/* Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Code Aurora Forum nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * Alternatively, provided that this notice is retained in full, this software + * may be relicensed by the recipient under the terms of the GNU General Public + * License version 2 ("GPL") and only version 2, in which case the provisions of + * the GPL apply INSTEAD OF those given above. If the recipient relicenses the + * software under the GPL, then the identification text in the MODULE_LICENSE + * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a + * recipient changes the license terms to the GPL, subsequent recipients shall + * not relicense under alternate licensing terms, including the BSD or dual + * BSD/GPL terms. In addition, the following license statement immediately + * below and between the words START and END shall also then apply when this + * software is relicensed under the GPL: + * + * START + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * END + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +/* + * Qualcomm PMIC8058 MPP driver + * + */ + +#include +#include +#include "gpio_chip.h" + +#define PM8058_MPP_TO_INT(n) (PMIC8058_IRQ_BASE + NR_PMIC8058_GPIO_IRQS + (n)) + +static int pm8058_mpp_get_irq_num(struct gpio_chip *chip, + unsigned int gpio, + unsigned int *irqp, + unsigned long *irqnumflagsp) +{ + gpio -= chip->start; + *irqp = PM8058_MPP_TO_INT(gpio); + if (irqnumflagsp) + *irqnumflagsp = 0; + return 0; +} + +static int pm8058_mpp_read(struct gpio_chip *chip, unsigned n) +{ + n -= chip->start; + return pm8058_mpp_get(n); +} + +struct msm_gpio_chip pm8058_mpp_chip = { + .chip = { + .start = NR_GPIO_IRQS + NR_PMIC8058_GPIO_IRQS, + .end = NR_GPIO_IRQS + NR_PMIC8058_GPIO_IRQS + + NR_PMIC8058_MPP_IRQS - 1, + .get_irq_num = pm8058_mpp_get_irq_num, + .read = pm8058_mpp_read, + } +}; + +static int __init pm8058_mpp_init(void) +{ + int rc; + + rc = register_gpio_chip(&pm8058_mpp_chip.chip); + pr_info("%s: register_gpio_chip(): rc=%d\n", __func__, rc); + + return rc; +} +device_initcall(pm8058_mpp_init); -- cgit v1.2.3 From df28cdd843da69bff7a5d82458e2625784a4a129 Mon Sep 17 00:00:00 2001 From: Saravana Kannan Date: Thu, 29 Oct 2009 16:06:37 -0700 Subject: msm: clock: Add support for AXI_ROTATOR and HDMI clocks. Signed-off-by: Saravana Kannan --- arch/arm/mach-msm/clock-pcom.h | 4 +++- arch/arm/mach-msm/devices.c | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/clock-pcom.h b/arch/arm/mach-msm/clock-pcom.h index 8d8f5a95b78a..39a2976ae56b 100644 --- a/arch/arm/mach-msm/clock-pcom.h +++ b/arch/arm/mach-msm/clock-pcom.h @@ -127,8 +127,10 @@ #define P_SDAC_MCLK 87 #define P_MI2S_HDMI_CLK 88 #define P_MI2S_HDMI_MCLK 89 +#define P_AXI_ROTATOR_CLK 90 +#define P_HDMI_CLK 91 -#define P_NR_CLKS 90 +#define P_NR_CLKS 92 struct clk_ops; extern struct clk_ops clk_ops_pcom; diff --git a/arch/arm/mach-msm/devices.c b/arch/arm/mach-msm/devices.c index 74ac321f662a..e525c62dc87f 100644 --- a/arch/arm/mach-msm/devices.c +++ b/arch/arm/mach-msm/devices.c @@ -556,6 +556,7 @@ struct clk msm_clocks_7x30[] = { CLK_PCOM("grp_2d_pclk", GRP_2D_PCLK, NULL, 0), CLK_PCOM("grp_clk", GRP_CLK, NULL, 0), CLK_PCOM("grp_pclk", GRP_PCLK, NULL, 0), + CLK_PCOM("hdmi_clk", HDMI_CLK, NULL, 0), CLK_PCOM("i2c_clk", I2C_CLK, &msm_device_i2c.dev, 0), CLK_PCOM("imem_clk", IMEM_CLK, NULL, OFF), CLK_PCOM("lpa_codec_clk", LPA_CODEC_CLK, NULL, 0), @@ -579,6 +580,7 @@ struct clk msm_clocks_7x30[] = { CLK_PCOM("pbus_clk", PBUS_CLK, NULL, CLK_MIN), CLK_PCOM("pcm_clk", PCM_CLK, NULL, 0), CLK_PCOM("qup_clk", QUP_I2C_CLK, &qup_device_i2c.dev, 0), + CLK_PCOM("rotator_clk", AXI_ROTATOR_CLK, NULL, 0), CLK_PCOM("rotator_imem_clk", ROTATOR_IMEM_CLK, NULL, OFF), CLK_PCOM("rotator_pclk", ROTATOR_PCLK, NULL, OFF), CLK_PCOM("sdac_clk", SDAC_CLK, NULL, OFF), -- cgit v1.2.3 From 93fe1971f973f4a60c4db244b8ad9194b5db41eb Mon Sep 17 00:00:00 2001 From: David Brown Date: Mon, 24 Aug 2009 15:54:16 -0700 Subject: mach_msm: Conditionalize SMD support in GPIO code. Remove dependency on SMD from GPIO code. Modem CPU will not be notified of GPIO states for proper sleep without this feature. Signed-off-by: David Brown --- arch/arm/mach-msm/gpio.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/gpio.c b/arch/arm/mach-msm/gpio.c index 6c80d76b184b..00dc85b03da5 100644 --- a/arch/arm/mach-msm/gpio.c +++ b/arch/arm/mach-msm/gpio.c @@ -473,7 +473,11 @@ static void msm_gpio_sleep_int(unsigned long arg) BUILD_BUG_ON(NR_GPIO_IRQS > NUM_GPIO_SMEM_BANKS * 32); +#ifdef CONFIG_MACH_SMD smem_gpio = smem_alloc(SMEM_GPIO_INT, sizeof(*smem_gpio)); +#else + smem_gpio = NULL; +#endif if (smem_gpio == NULL) return; @@ -495,7 +499,11 @@ void msm_gpio_enter_sleep(int from_idle) int i; struct tramp_gpio_smem *smem_gpio; +#ifdef CONFIG_MACH_SMD smem_gpio = smem_alloc(SMEM_GPIO_INT, sizeof(*smem_gpio)); +#else + smem_gpio = NULL; +#endif if (smem_gpio) { for (i = 0; i < ARRAY_SIZE(smem_gpio->enabled); i++) { @@ -544,7 +552,11 @@ void msm_gpio_exit_sleep(void) int i; struct tramp_gpio_smem *smem_gpio; +#ifdef CONFIG_MACH_SMD smem_gpio = smem_alloc(SMEM_GPIO_INT, sizeof(*smem_gpio)); +#else + smem_gpio = NULL; +#endif for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) { writel(msm_gpio_chips[i].int_enable[0], msm_gpio_chips[i].regs.int_en); -- cgit v1.2.3 From b206e4ea6523c2c1bc634b6857775bb5c54e4eef Mon Sep 17 00:00:00 2001 From: "Pfeffer, Zach" Date: Mon, 31 Aug 2009 15:39:27 -0700 Subject: mach_msm: dma: Use an ISR safe disable IRQ call Kernel 2.6.31 brought out a latent bug in the dma ISR, disable_irq was being used instead of disable_irq_nosync. This caused the kernel to lock up at boot. Signed-off-by: Zach Pfeffer --- arch/arm/mach-msm/dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/dma.c b/arch/arm/mach-msm/dma.c index c4c8502ec04d..fae9dc88b8e4 100644 --- a/arch/arm/mach-msm/dma.c +++ b/arch/arm/mach-msm/dma.c @@ -259,7 +259,7 @@ static irqreturn_t msm_datamover_irq_handler(int irq, void *dev_id) } if (!channel_active) { - disable_irq(INT_ADM_AARM); + disable_irq_nosync(INT_ADM_AARM); clk_ctl = CLK_TO_BE_DIS; mod_timer(&timer, jiffies + HZ); } -- cgit v1.2.3 From e9ca0021e5ab9563bac25bc6eca7e1ca26b45f4d Mon Sep 17 00:00:00 2001 From: David Brown Date: Tue, 15 Sep 2009 15:02:36 -0700 Subject: msm: add grapefruit qsd8x50 support. Add machine-type support for the qsd8x50 "grapefruit" internal development platform. Signed-off-by: David Brown --- arch/arm/mach-msm/board-qsd8x50.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/board-qsd8x50.c b/arch/arm/mach-msm/board-qsd8x50.c index 85395db1fc2f..76eb4e9182a3 100644 --- a/arch/arm/mach-msm/board-qsd8x50.c +++ b/arch/arm/mach-msm/board-qsd8x50.c @@ -1463,6 +1463,18 @@ MACHINE_START(QSD8X50_SURF, "QCT QSD8X50 SURF") .timer = &msm_timer, MACHINE_END +MACHINE_START(QSD8X50_GRAPEFRUIT, "QCT QSD8X50 GRAPEFRUIT") +#ifdef CONFIG_MSM_DEBUG_UART + .phys_io = MSM_DEBUG_UART_PHYS, + .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc, +#endif + .boot_params = 0x20000100, + .map_io = qsd8x50_map_io, + .init_irq = qsd8x50_init_irq, + .init_machine = qsd8x50_init, + .timer = &msm_timer, +MACHINE_END + MACHINE_START(QSD8X50_FFA, "QCT QSD8X50 FFA") #ifdef CONFIG_MSM_DEBUG_UART .phys_io = MSM_DEBUG_UART_PHYS, -- cgit v1.2.3 From c9239f537a1e4f4cfe4553755377a03e4a442de8 Mon Sep 17 00:00:00 2001 From: Neil Leeder Date: Wed, 16 Sep 2009 16:41:47 -0700 Subject: msm: add config option for grapefruit platform Signed-off-by: Neil Leeder --- arch/arm/mach-msm/Kconfig | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index d9909d13aaad..03be35b0d9c4 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -138,6 +138,14 @@ config MACH_QSD8X50_COMET help Support for the Qualcomm Comet eval board. +config MACH_QSD8X50_GRAPEFRUIT + depends on ARCH_QSD8X50 + depends on MSM_STACKED_MEMORY + default n + bool "QSD8x50 Grapefruit" + help + Support for the Qualcomm Grapefruit eval board. + endmenu config MSM_STACKED_MEMORY -- cgit v1.2.3 From 193c5a64e0f017262c4d485f9e0217129735c473 Mon Sep 17 00:00:00 2001 From: David Brown Date: Thu, 5 Nov 2009 13:56:10 -0800 Subject: msm: Add QSD8x50 ST1 machine type. Change-Id: Iaa42379f24716be07f27b797605d2309683b1c4d Signed-off-by: David Brown --- arch/arm/mach-msm/Kconfig | 8 ++++++++ arch/arm/mach-msm/board-qsd8x50.c | 12 ++++++++++++ 2 files changed, 20 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index 03be35b0d9c4..57012e82e3cd 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -146,6 +146,14 @@ config MACH_QSD8X50_GRAPEFRUIT help Support for the Qualcomm Grapefruit eval board. +config MACH_QSD8X50_ST1 + depends on ARCH_QSD8X50 + depends on MSM_STACKED_MEMORY + default n + bool "QSD8x50 ST1" + help + Support for the Qualcomm ST1. + endmenu config MSM_STACKED_MEMORY diff --git a/arch/arm/mach-msm/board-qsd8x50.c b/arch/arm/mach-msm/board-qsd8x50.c index 76eb4e9182a3..a75b2375a78c 100644 --- a/arch/arm/mach-msm/board-qsd8x50.c +++ b/arch/arm/mach-msm/board-qsd8x50.c @@ -1486,3 +1486,15 @@ MACHINE_START(QSD8X50_FFA, "QCT QSD8X50 FFA") .init_machine = qsd8x50_init, .timer = &msm_timer, MACHINE_END + +MACHINE_START(QSD8X50_ST1, "QCT QSD8X50 ST1") +#ifdef CONFIG_MSM_DEBUG_UART + .phys_io = MSM_DEBUG_UART_PHYS, + .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc, +#endif + .boot_params = 0x20000100, + .map_io = qsd8x50_map_io, + .init_irq = qsd8x50_init_irq, + .init_machine = qsd8x50_init, + .timer = &msm_timer, +MACHINE_END -- cgit v1.2.3 From 878f36a89f144d1401da94c1b9535d51fa13beb3 Mon Sep 17 00:00:00 2001 From: Jeff Ohlstein Date: Wed, 18 Nov 2009 14:22:08 -0800 Subject: msm: gpio: Fix misnamed ifdefs CONFIG_MACH_SMD appears several time in our gpio driver. This symbol is incorrect, and the right feature name is CONFIG_MSM_SMD. Signed-off-by: Jeff Ohlstein --- arch/arm/mach-msm/gpio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/gpio.c b/arch/arm/mach-msm/gpio.c index 00dc85b03da5..598022906be6 100644 --- a/arch/arm/mach-msm/gpio.c +++ b/arch/arm/mach-msm/gpio.c @@ -499,7 +499,7 @@ void msm_gpio_enter_sleep(int from_idle) int i; struct tramp_gpio_smem *smem_gpio; -#ifdef CONFIG_MACH_SMD +#ifdef CONFIG_MSM_SMD smem_gpio = smem_alloc(SMEM_GPIO_INT, sizeof(*smem_gpio)); #else smem_gpio = NULL; @@ -552,7 +552,7 @@ void msm_gpio_exit_sleep(void) int i; struct tramp_gpio_smem *smem_gpio; -#ifdef CONFIG_MACH_SMD +#ifdef CONFIG_MSM_SMD smem_gpio = smem_alloc(SMEM_GPIO_INT, sizeof(*smem_gpio)); #else smem_gpio = NULL; -- cgit v1.2.3 From b6f35ee4ecea59c231504c23d62aa1fb016cf8d7 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Mon, 28 Dec 2009 15:54:30 -0800 Subject: Add the clocksource structure to the read function. --- arch/arm/mach-msm/timer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c index db3aeb909cf2..0f668dcd098a 100644 --- a/arch/arm/mach-msm/timer.c +++ b/arch/arm/mach-msm/timer.c @@ -712,7 +712,7 @@ unsigned long long sched_clock(void) cs = &clock->clocksource; last_ticks = saved_ticks; - saved_ticks = ticks = cs->read(); + saved_ticks = ticks = cs->read(cs); if (!saved_ticks_valid) { saved_ticks_valid = 1; last_ticks = ticks; -- cgit v1.2.3 From 09961e57f24a5ba31780e557808bd610c1286411 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Mon, 28 Dec 2009 15:55:35 -0800 Subject: Drop the usage of non-existant switch.h --- arch/arm/mach-msm/include/mach/msm_handset.h | 2 -- arch/arm/mach-msm/rpc_server_handset.c | 1 - 2 files changed, 3 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/include/mach/msm_handset.h b/arch/arm/mach-msm/include/mach/msm_handset.h index 4d6ccd21d4da..6947e03b8986 100644 --- a/arch/arm/mach-msm/include/mach/msm_handset.h +++ b/arch/arm/mach-msm/include/mach/msm_handset.h @@ -17,7 +17,6 @@ #define _MSM_HANDSET_H #include -#include #if defined(CONFIG_INPUT_MSM_HANDSET) struct input_dev *msm_get_handset_input_dev(void); @@ -30,7 +29,6 @@ struct input_dev *msm_get_handset_input_dev(void) struct msm_handset { struct input_dev *ip_dev; - struct switch_dev sdev; }; #endif diff --git a/arch/arm/mach-msm/rpc_server_handset.c b/arch/arm/mach-msm/rpc_server_handset.c index 38cc38cabaea..f2df4aca231b 100644 --- a/arch/arm/mach-msm/rpc_server_handset.c +++ b/arch/arm/mach-msm/rpc_server_handset.c @@ -135,7 +135,6 @@ report_headset_switch(struct input_dev *dev, int key, int value) struct msm_handset *hs = input_get_drvdata(dev); input_report_switch(dev, key, value); - switch_set_state(&hs->sdev, value); input_sync(dev); } -- cgit v1.2.3 From 7a63ec9cebccfd4a3ff5c451da4c2f5068eab2a1 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Mon, 28 Dec 2009 15:57:54 -0800 Subject: add clk.h to msm_iomap.h --- arch/arm/mach-msm/include/mach/board.h | 1 + 1 file changed, 1 insertion(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h index 5045edd36131..163dffe87923 100644 --- a/arch/arm/mach-msm/include/mach/board.h +++ b/arch/arm/mach-msm/include/mach/board.h @@ -20,6 +20,7 @@ #include #include +#include /* platform device data structures */ -- cgit v1.2.3 From 9417118f5a7724564b7afe32faa4130f7ca8c694 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Mon, 28 Dec 2009 15:59:14 -0800 Subject: Drop early suspend header. --- arch/arm/mach-msm/cpufreq.c | 1 - 1 file changed, 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/cpufreq.c b/arch/arm/mach-msm/cpufreq.c index 0dffaa2fa4cb..8c20add08267 100644 --- a/arch/arm/mach-msm/cpufreq.c +++ b/arch/arm/mach-msm/cpufreq.c @@ -17,7 +17,6 @@ * */ -#include #include #include #include "acpuclock.h" -- cgit v1.2.3 From d480430e0c9fc587bd1dfc301e741b360282ae76 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Mon, 28 Dec 2009 16:00:26 -0800 Subject: Remove platform devices and code for devices that aren't in mainline. --- arch/arm/mach-msm/devices.c | 141 -------------------------------------------- 1 file changed, 141 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/devices.c b/arch/arm/mach-msm/devices.c index e525c62dc87f..d25191acdaec 100644 --- a/arch/arm/mach-msm/devices.c +++ b/arch/arm/mach-msm/devices.c @@ -99,77 +99,6 @@ struct platform_device msm_device_uart3 = { #define MSM_UART2DM_PHYS 0xA0300000 #endif -static struct resource resources_i2c[] = { - { - .start = MSM_I2C_PHYS, - .end = MSM_I2C_PHYS + MSM_I2C_SIZE - 1, - .flags = IORESOURCE_MEM, - }, - { - .start = INT_PWB_I2C, - .end = INT_PWB_I2C, - .flags = IORESOURCE_IRQ, - }, -}; - -struct platform_device msm_device_i2c = { - .name = "msm_i2c", - .id = 0, - .num_resources = ARRAY_SIZE(resources_i2c), - .resource = resources_i2c, -}; - -static struct resource resources_hsusb[] = { - { - .start = MSM_HSUSB_PHYS, - .end = MSM_HSUSB_PHYS + MSM_HSUSB_SIZE, - .flags = IORESOURCE_MEM, - }, - { - .start = INT_USB_HS, - .end = INT_USB_HS, - .flags = IORESOURCE_IRQ, - }, -}; - -struct platform_device msm_device_hsusb_peripheral = { -#ifdef CONFIG_USB_ANDROID - .name = "msm_hsusb", -#else - .name = "msm_hsusb_peripheral", -#endif - .id = -1, - .num_resources = ARRAY_SIZE(resources_hsusb_peripheral), - .resource = resources_hsusb_peripheral, - .dev = { - .dma_mask = &dma_mask, - .coherent_dma_mask = 0xffffffffULL, - }, -}; - -static struct resource resources_hsusb_host[] = { - { - .start = MSM_HSUSB_PHYS, - .end = MSM_HSUSB_PHYS + MSM_HSUSB_SIZE, - .flags = IORESOURCE_MEM, - }, - { - .start = INT_USB_HS, - .end = INT_USB_HS, - .flags = IORESOURCE_IRQ, - }, -}; - -struct platform_device msm_device_hsusb_host = { - .name = "msm_hsusb_host", - .id = -1, - .num_resources = ARRAY_SIZE(resources_hsusb_host), - .resource = resources_hsusb_host, - .dev = { - .dma_mask = &dma_mask, - .coherent_dma_mask = 0xffffffffULL, - }, -}; struct flash_platform_data msm_nand_data = { .parts = NULL, @@ -347,65 +276,6 @@ int __init msm_add_sdcc(unsigned int controller, struct mmc_platform_data *plat) return platform_device_register(pdev); } -#define CLOCK(clk_name, clk_id, clk_dev, clk_flags, clk_arch) { \ - .name = clk_name, \ - .id = clk_id, \ - .flags = (clk_flags) | ((clk_arch) & CLKFLAG_ARCH_ALL), \ - .dev = clk_dev, \ - } - -static struct platform_device msm_tvenc_device = { - .name = "tvenc", - .id = 0, - .num_resources = ARRAY_SIZE(msm_tvenc_resources), - .resource = msm_tvenc_resources, -}; - -static void __init msm_register_device(struct platform_device *pdev, void *data) -{ - int ret; - - pdev->dev.platform_data = data; - - ret = platform_device_register(pdev); - if (ret) - dev_err(&pdev->dev, - "%s: platform_device_register() failed = %d\n", - __func__, ret); -} - -void __init msm_fb_register_device(char *name, void *data) -{ - if (!strncmp(name, "mdp", 3)) - msm_register_device(&msm_mdp_device, data); - else if (!strncmp(name, "pmdh", 4)) - msm_register_device(&msm_mddi_device, data); - else if (!strncmp(name, "emdh", 4)) - msm_register_device(&msm_mddi_ext_device, data); - else if (!strncmp(name, "ebi2", 4)) - msm_register_device(&msm_ebi2_lcd_device, data); - else if (!strncmp(name, "tvenc", 5)) - msm_register_device(&msm_tvenc_device, data); - else if (!strncmp(name, "lcdc", 4)) - msm_register_device(&msm_lcdc_device, data); - else - printk(KERN_ERR "%s: unknown device! %s\n", __func__, name); -} - -static struct platform_device msm_camera_device = { - .name = "msm_camera", - .id = 0, -}; - -void __init msm_camera_register_device(void *res, uint32_t num, - void *data) -{ - msm_camera_device.num_resources = num; - msm_camera_device.resource = res; - - msm_register_device(&msm_camera_device, data); -} - struct clk msm_clocks_7x01a[] = { CLK_PCOM("adm_clk", ADM_CLK, NULL, 0), CLK_PCOM("adsp_clk", ADSP_CLK, NULL, 0), @@ -440,8 +310,6 @@ struct clk msm_clocks_7x01a[] = { CLK_PCOM("uart_clk", UART1_CLK, &msm_device_uart1.dev, OFF), CLK_PCOM("uart_clk", UART2_CLK, &msm_device_uart2.dev, 0), CLK_PCOM("uart_clk", UART3_CLK, &msm_device_uart3.dev, OFF), - CLK_PCOM("uartdm_clk", UART1DM_CLK, &msm_device_uart_dm1.dev, OFF), - CLK_PCOM("uartdm_clk", UART2DM_CLK, &msm_device_uart_dm2.dev, 0), CLK_PCOM("usb_hs_clk", USB_HS_CLK, NULL, OFF), CLK_PCOM("usb_hs_pclk", USB_HS_PCLK, NULL, OFF), CLK_PCOM("usb_otg_clk", USB_OTG_CLK, NULL, 0), @@ -484,8 +352,6 @@ struct clk msm_clocks_7x25[] = { CLK_PCOM("uart_clk", UART1_CLK, &msm_device_uart1.dev, OFF), CLK_PCOM("uart_clk", UART2_CLK, &msm_device_uart2.dev, 0), CLK_PCOM("uart_clk", UART3_CLK, &msm_device_uart3.dev, OFF), - CLK_PCOM("uartdm_clk", UART1DM_CLK, &msm_device_uart_dm1.dev, OFF), - CLK_PCOM("uartdm_clk", UART2DM_CLK, &msm_device_uart_dm2.dev, 0), CLK_PCOM("usb_hs_clk", USB_HS_CLK, NULL, OFF), CLK_PCOM("usb_hs_pclk", USB_HS_PCLK, NULL, OFF), CLK_PCOM("usb_otg_clk", USB_OTG_CLK, NULL, 0), @@ -530,8 +396,6 @@ struct clk msm_clocks_7x27[] = { CLK_PCOM("uart_clk", UART1_CLK, &msm_device_uart1.dev, OFF), CLK_PCOM("uart_clk", UART2_CLK, &msm_device_uart2.dev, 0), CLK_PCOM("uart_clk", UART3_CLK, &msm_device_uart3.dev, OFF), - CLK_PCOM("uartdm_clk", UART1DM_CLK, &msm_device_uart_dm1.dev, OFF), - CLK_PCOM("uartdm_clk", UART2DM_CLK, &msm_device_uart_dm2.dev, 0), CLK_PCOM("usb_hs_clk", USB_HS_CLK, NULL, OFF), CLK_PCOM("usb_hs_pclk", USB_HS_PCLK, NULL, OFF), CLK_PCOM("usb_otg_clk", USB_OTG_CLK, NULL, 0), @@ -579,7 +443,6 @@ struct clk msm_clocks_7x30[] = { CLK_PCOM("mi2s_codec_tx_s_clk", MI2S_CODEC_TX_SCLK, NULL, 0), CLK_PCOM("pbus_clk", PBUS_CLK, NULL, CLK_MIN), CLK_PCOM("pcm_clk", PCM_CLK, NULL, 0), - CLK_PCOM("qup_clk", QUP_I2C_CLK, &qup_device_i2c.dev, 0), CLK_PCOM("rotator_clk", AXI_ROTATOR_CLK, NULL, 0), CLK_PCOM("rotator_imem_clk", ROTATOR_IMEM_CLK, NULL, OFF), CLK_PCOM("rotator_pclk", ROTATOR_PCLK, NULL, OFF), @@ -597,8 +460,6 @@ struct clk msm_clocks_7x30[] = { CLK_PCOM("uart_clk", UART1_CLK, &msm_device_uart1.dev, OFF), CLK_PCOM("uart_clk", UART2_CLK, &msm_device_uart2.dev, 0), CLK_PCOM("uart_clk", UART3_CLK, &msm_device_uart3.dev, OFF), - CLK_PCOM("uartdm_clk", UART1DM_CLK, &msm_device_uart_dm1.dev, OFF), - CLK_PCOM("uartdm_clk", UART2DM_CLK, &msm_device_uart_dm2.dev, 0), CLK_PCOM("usb_hs_clk", USB_HS_CLK, NULL, OFF), CLK_PCOM("usb_hs_pclk", USB_HS_PCLK, NULL, OFF), CLK_PCOM("usb_hs_core_clk", USB_HS_CORE_CLK, NULL, OFF), @@ -655,8 +516,6 @@ struct clk msm_clocks_8x50[] = { CLK_PCOM("uart_clk", UART1_CLK, &msm_device_uart1.dev, OFF), CLK_PCOM("uart_clk", UART2_CLK, &msm_device_uart2.dev, 0), CLK_PCOM("uart_clk", UART3_CLK, &msm_device_uart3.dev, OFF), - CLK_PCOM("uartdm_clk", UART1DM_CLK, &msm_device_uart_dm1.dev, OFF), - CLK_PCOM("uartdm_clk", UART2DM_CLK, &msm_device_uart_dm2.dev, 0), CLK_PCOM("usb_hs_clk", USB_HS_CLK, NULL, OFF), CLK_PCOM("usb_hs_pclk", USB_HS_PCLK, NULL, OFF), CLK_PCOM("usb_otg_clk", USB_OTG_CLK, NULL, 0), -- cgit v1.2.3 From b2329b169460d959a066512c628a61ffb906228b Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Mon, 28 Dec 2009 16:01:04 -0800 Subject: Add missing MSM_AD5_BASE header. --- arch/arm/mach-msm/include/mach/msm_iomap.h | 1 + 1 file changed, 1 insertion(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/include/mach/msm_iomap.h b/arch/arm/mach-msm/include/mach/msm_iomap.h index 0c2caab9aa99..2f54547e1890 100644 --- a/arch/arm/mach-msm/include/mach/msm_iomap.h +++ b/arch/arm/mach-msm/include/mach/msm_iomap.h @@ -162,6 +162,7 @@ #define MSM_MDC_PHYS 0xAA500000 #define MSM_MDC_SIZE SZ_1M +#define MSM_AD5_BASE IOMEM(0xE0300000) #define MSM_AD5_PHYS 0xAC000000 #define MSM_AD5_SIZE (SZ_1M*13) -- cgit v1.2.3 From bfb6e8a4076056d4dc76aa799f9ec0bcd765089d Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Mon, 28 Dec 2009 16:01:47 -0800 Subject: Add missing rpc macros. --- arch/arm/mach-msm/include/mach/msm_rpcrouter.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/include/mach/msm_rpcrouter.h b/arch/arm/mach-msm/include/mach/msm_rpcrouter.h index a1f357f574f6..d0c01fb53047 100644 --- a/arch/arm/mach-msm/include/mach/msm_rpcrouter.h +++ b/arch/arm/mach-msm/include/mach/msm_rpcrouter.h @@ -28,6 +28,25 @@ struct rpcrouter_ioctl_server_args { uint32_t vers; }; +#define RPC_ROUTER_VERSION_V1 0x00010000 + +#define RPC_ROUTER_IOCTL_MAGIC (0xC1) + +#define RPC_ROUTER_IOCTL_GET_VERSION \ + _IOR(RPC_ROUTER_IOCTL_MAGIC, 0, unsigned int) + +#define RPC_ROUTER_IOCTL_GET_MTU \ + _IOR(RPC_ROUTER_IOCTL_MAGIC, 1, unsigned int) + +#define RPC_ROUTER_IOCTL_REGISTER_SERVER \ + _IOWR(RPC_ROUTER_IOCTL_MAGIC, 2, unsigned int) + +#define RPC_ROUTER_IOCTL_UNREGISTER_SERVER \ + _IOWR(RPC_ROUTER_IOCTL_MAGIC, 3, unsigned int) + +#define RPC_ROUTER_IOCTL_CLEAR_NETRESET \ + _IOWR(RPC_ROUTER_IOCTL_MAGIC, 4, unsigned int) + /* RPC API version structure * Version bit 31 : 1->hashkey versioning, * 0->major-minor (backward compatible) versioning -- cgit v1.2.3 From 9b3ec8cdc8c270f6b73db3e4d44fafae8bb6d4e1 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Mon, 28 Dec 2009 16:04:41 -0800 Subject: Drop two unused Makefile entries for audio, and rpc. --- arch/arm/mach-msm/Makefile | 3 --- 1 file changed, 3 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 632ea78c3e5d..6d7937fa50ce 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -40,7 +40,6 @@ obj-$(CONFIG_MSM_RPC_PING) += ping_mdm_rpc_client.o obj-$(CONFIG_MSM_RPC_PROC_COMM_TEST) += proc_comm_test.o obj-$(CONFIG_MSM_RPC_OEM_RAPI) += oem_rapi_client.o obj-$(CONFIG_MSM_RPCSERVERS) += rpc_server_dog_keepalive.o -obj-$(CONFIG_MSM_RPCSERVERS) += rpc_server_time_remote.o obj-$(CONFIG_MSM_DALRPC) += dal.o obj-$(CONFIG_MSM_DALRPC_TEST) += dal_remotetest.o obj-$(CONFIG_MSM_RPCSERVER_HANDSET) += rpc_server_handset.o @@ -67,8 +66,6 @@ obj-$(CONFIG_TROUT_PWRSINK) += htc_pwrsink.o obj-$(CONFIG_ARCH_MSM7X27) += board-msm7x27.o obj-$(CONFIG_ARCH_MSM7X30) += board-msm7x30.o clock-7x30.o -obj-$(CONFIG_QSD_AUDIO) += qdsp6/ - obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire.o board-sapphire-gpio.o obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire-keypad.o board-sapphire-panel.o obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire-mmc.o board-sapphire-wifi.o -- cgit v1.2.3 From 1275a78f6bf3875096931f8a37237d804a5c6fee Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Mon, 28 Dec 2009 16:06:46 -0800 Subject: Drop unused code from board-comet.c --- arch/arm/mach-msm/board-comet.c | 624 ---------------------------------------- 1 file changed, 624 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/board-comet.c b/arch/arm/mach-msm/board-comet.c index c83e699b1c43..9d8e290e8930 100644 --- a/arch/arm/mach-msm/board-comet.c +++ b/arch/arm/mach-msm/board-comet.c @@ -59,12 +59,9 @@ #include #include #include -#include #include -#include #include #include -#include #include #include @@ -73,10 +70,6 @@ #include #include #include -#include -#include -#include -#include #include #include "devices.h" @@ -172,294 +165,6 @@ static struct platform_device smc911x_device = { .resource = smc911x_resources, }; -static struct usb_mass_storage_platform_data usb_mass_storage_pdata = { - .nluns = 0x02, - .buf_size = 16384, - .vendor = "GOOGLE", - .product = "Mass storage", - .release = 0xffff, -}; - -static struct platform_device mass_storage_device = { - .name = "usb_mass_storage", - .id = -1, - .dev = { - .platform_data = &usb_mass_storage_pdata, - }, -}; - -static struct usb_function_map usb_functions_map[] = { - {"diag", 0}, - {"adb", 1}, - {"modem", 2}, - {"nmea", 3}, - {"mass_storage", 4}, - {"ethernet", 5}, -}; - -/* dynamic composition */ -static struct usb_composition usb_func_composition[] = { - { - .product_id = 0x9012, - .functions = 0x5, /* 0101 */ - }, - - { - .product_id = 0x9013, - .functions = 0x15, /* 10101 */ - }, - - { - .product_id = 0x9014, - .functions = 0x30, /* 110000 */ - }, - - { - .product_id = 0x9016, - .functions = 0xD, /* 01101 */ - }, - - { - .product_id = 0x9017, - .functions = 0x1D, /* 11101 */ - }, - - { - .product_id = 0xF000, - .functions = 0x10, /* 10000 */ - }, - - { - .product_id = 0xF009, - .functions = 0x20, /* 100000 */ - }, - - { - .product_id = 0x9018, - .functions = 0x1F, /* 011111 */ - }, - -}; -static struct msm_hsusb_platform_data msm_hsusb_pdata = { - .version = 0x0100, - .phy_info = (USB_PHY_INTEGRATED | USB_PHY_MODEL_180NM), - .vendor_id = 0x5c6, - .product_name = "Qualcomm HSUSB Device", - .serial_number = "1234567890ABCDEF", - .manufacturer_name = "Qualcomm Incorporated", - .compositions = usb_func_composition, - .num_compositions = ARRAY_SIZE(usb_func_composition), - .function_map = usb_functions_map, - .num_functions = ARRAY_SIZE(usb_functions_map), - .config_gpio = NULL, -}; - -static struct android_pmem_platform_data android_pmem_pdata = { - .name = "pmem", - .size = MSM_PMEM_MDP_SIZE, - .no_allocator = 0, - .cached = 1, -}; - -static struct android_pmem_platform_data android_pmem_gpu0_pdata = { - .name = "pmem_gpu0", - .start = MSM_PMEM_GPU0_BASE, - .size = MSM_PMEM_GPU0_SIZE, - .no_allocator = 1, - .cached = 0, -}; - -static struct platform_device android_pmem_device = { - .name = "android_pmem", - .id = 0, - .dev = { .platform_data = &android_pmem_pdata }, -}; - -static struct platform_device android_pmem_gpu0_device = { - .name = "android_pmem", - .id = 2, - .dev = { .platform_data = &android_pmem_gpu0_pdata }, -}; - -static struct resource qsd_spi_resources[] = { - { - .name = "spi_irq_in", - .start = INT_SPI_INPUT, - .end = INT_SPI_INPUT, - .flags = IORESOURCE_IRQ, - }, - { - .name = "spi_irq_out", - .start = INT_SPI_OUTPUT, - .end = INT_SPI_OUTPUT, - .flags = IORESOURCE_IRQ, - }, - { - .name = "spi_irq_err", - .start = INT_SPI_ERROR, - .end = INT_SPI_ERROR, - .flags = IORESOURCE_IRQ, - }, - { - .name = "spi_base", - .start = 0xA1200000, - .end = 0xA1200000 + SZ_4K - 1, - .flags = IORESOURCE_MEM, - }, - { - .name = "spi_clk", - .start = 17, - .end = 1, - .flags = IORESOURCE_IRQ, - }, - { - .name = "spi_mosi", - .start = 18, - .end = 1, - .flags = IORESOURCE_IRQ, - }, - { - .name = "spi_miso", - .start = 19, - .end = 1, - .flags = IORESOURCE_IRQ, - }, - { - .name = "spi_cs0", - .start = 20, - .end = 1, - .flags = IORESOURCE_IRQ, - }, - { - .name = "spi_irq_cs0", - .start = 106, - .end = 0, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct platform_device qsd_device_spi = { - .name = "spi_qsd", - .id = 0, - .num_resources = ARRAY_SIZE(qsd_spi_resources), - .resource = qsd_spi_resources, -}; - -static struct spi_board_info msm_spi_board_info[] __initdata = { - { - .modalias = "bma150", - .mode = SPI_MODE_3, - .irq = MSM_GPIO_TO_INT(106), - .bus_num = 0, - .chip_select = 0, - .max_speed_hz = 10000000, - } -}; - -static struct resource msm_fb_resources[] = { - { - .flags = IORESOURCE_DMA, - } -}; - -static int msm_fb_detect_panel(const char *name) -{ - int ret; - - if ((!strcmp(name, "mddi_toshiba_wvga") && wvga_present) || - (!strcmp(name, "lcdc_external") && wvga_present) || - (!strcmp(name, "lcdc_wxga") && wxga_present)) - ret = 0; - else - ret = -ENODEV; - - return ret; -} - -static struct msm_fb_platform_data msm_fb_pdata = { - .detect_client = msm_fb_detect_panel, -}; - -static struct platform_device msm_fb_device = { - .name = "msm_fb", - .id = 0, - .num_resources = ARRAY_SIZE(msm_fb_resources), - .resource = msm_fb_resources, - .dev = { - .platform_data = &msm_fb_pdata, - } -}; - -static int msm_fb_mddi_sel_clk(u32 *clk_rate) -{ - *clk_rate *= 2; - return 0; -} - -static struct mddi_platform_data mddi_pdata = { - .mddi_sel_clk = msm_fb_mddi_sel_clk, -}; - -static void __init msm_fb_add_devices(void) -{ - int rc; - - if (wvga_present) { - vreg_mmc = vreg_get(NULL, "gp6"); - rc = vreg_set_level(vreg_mmc, 2850); - if (!rc) - rc = vreg_enable(vreg_mmc); - if (rc) - printk(KERN_ERR "%s: gp6 vreg error: %d\n", - __func__, rc); - else - gp6_enabled = 1; - } - - msm_fb_register_device("mdp", 0); - msm_fb_register_device("pmdh", &mddi_pdata); - msm_fb_register_device("emdh", &mddi_pdata); - msm_fb_register_device("tvenc", 0); - msm_fb_register_device("lcdc", 0); -} - -static struct resource msm_audio_resources[] = { - { - .flags = IORESOURCE_DMA, - }, - { - .name = "aux_pcm_dout", - .start = 68, - .end = 68, - .flags = IORESOURCE_IO, - }, - { - .name = "aux_pcm_din", - .start = 69, - .end = 69, - .flags = IORESOURCE_IO, - }, - { - .name = "aux_pcm_syncout", - .start = 70, - .end = 70, - .flags = IORESOURCE_IO, - }, - { - .name = "aux_pcm_clkin_a", - .start = 71, - .end = 71, - .flags = IORESOURCE_IO, - }, -}; - -static struct platform_device msm_audio_device = { - .name = "msm_audio", - .id = 0, - .num_resources = ARRAY_SIZE(msm_audio_resources), - .resource = msm_audio_resources, -}; - static void __iomem *comet_cpld_base(void) { static void __iomem *comet_cpld_base_addr; @@ -485,255 +190,11 @@ cpld_base_exit: return comet_cpld_base_addr; } -static struct msm_serial_hs_platform_data msm_uart_dm1_pdata = { - .wakeup_irq = MSM_GPIO_TO_INT(45), - .inject_rx_on_wakeup = 1, - .rx_to_inject = 0x32, -}; - -static struct resource bluesleep_resources[] = { - { - .name = "gpio_host_wake", - .start = 40, - .end = 40, - .flags = IORESOURCE_IO, - }, - { - .name = "gpio_ext_wake", - .start = 29, - .end = 29, - .flags = IORESOURCE_IO, - }, - { - .name = "host_wake", - .start = MSM_GPIO_TO_INT(40), - .end = MSM_GPIO_TO_INT(40), - .flags = IORESOURCE_IRQ, - }, -}; - -static struct platform_device msm_bluesleep_device = { - .name = "bluesleep", - .id = -1, - .num_resources = ARRAY_SIZE(bluesleep_resources), - .resource = bluesleep_resources, -}; - -#ifdef CONFIG_BT -static struct platform_device msm_bt_power_device = { - .name = "bt_power", -}; - -enum { - BT_SYSRST, - BT_WAKE, - BT_HOST_WAKE, - BT_PWR_EN, - BT_RFR, - BT_CTS, - BT_RX, - BT_TX, - BT_PCM_DOUT, - BT_PCM_DIN, - BT_PCM_SYNC, - BT_PCM_CLK, -}; - -static unsigned bt_config_power_on[] = { - GPIO_CFG(29, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* WAKE */ - GPIO_CFG(40, 0, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), /* HOST_WAKE */ - GPIO_CFG(22, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* PWR_EN */ - GPIO_CFG(43, 2, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* RFR */ - GPIO_CFG(44, 2, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), /* CTS */ - GPIO_CFG(45, 2, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), /* Rx */ - GPIO_CFG(46, 2, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* Tx */ - GPIO_CFG(68, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* PCM_DOUT */ - GPIO_CFG(69, 1, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), /* PCM_DIN */ - GPIO_CFG(70, 2, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* PCM_SYNC */ - GPIO_CFG(71, 2, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* PCM_CLK */ -}; -static unsigned bt_config_power_off[] = { - GPIO_CFG(29, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* WAKE */ - GPIO_CFG(40, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* HOST_WAKE */ - GPIO_CFG(22, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* PWR_EN */ - GPIO_CFG(43, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* RFR */ - GPIO_CFG(44, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* CTS */ - GPIO_CFG(45, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* Rx */ - GPIO_CFG(46, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* Tx */ - GPIO_CFG(68, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* PCM_DOUT */ - GPIO_CFG(69, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* PCM_DIN */ - GPIO_CFG(70, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* PCM_SYNC */ - GPIO_CFG(71, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* PCM_CLK */ -}; - -static int bluetooth_power(int on) -{ - int pin, rc; - char __iomem *cpld_base; - - printk(KERN_DEBUG "%s\n", __func__); - - cpld_base = comet_cpld_base(); - if (!cpld_base) - return -ENOMEM; - - if (on) { - for (pin = 0; pin < ARRAY_SIZE(bt_config_power_on); pin++) { - rc = gpio_tlmm_config(bt_config_power_on[pin], - GPIO_ENABLE); - if (rc) { - printk(KERN_ERR - "%s: gpio_tlmm_config(%#x)=%d\n", - __func__, bt_config_power_on[pin], rc); - return -EIO; - } - } - - gpio_set_value(22, on); /* PWR_EN */ - writeb(cpld_info->bt_reset_mask, - cpld_base + cpld_info->bt_reset_reg); /* SYSRST */ - - } else { - writeb(cpld_info->bt_reset_mask, - cpld_base + cpld_info->bt_reset_reg); /* SYSRST */ - gpio_set_value(22, on); /* PWR_EN */ - - for (pin = 0; pin < ARRAY_SIZE(bt_config_power_off); pin++) { - rc = gpio_tlmm_config(bt_config_power_off[pin], - GPIO_ENABLE); - if (rc) { - printk(KERN_ERR - "%s: gpio_tlmm_config(%#x)=%d\n", - __func__, bt_config_power_off[pin], rc); - return -EIO; - } - } - - } - - return 0; -} - -static void __init bt_power_init(void) -{ - msm_bt_power_device.dev.platform_data = &bluetooth_power; -} -#else -#define bt_power_init(x) do {} while (0) -#endif - static struct platform_device *devices[] __initdata = { - &msm_fb_device, &msm_device_smd, &msm_device_dmov, &smc911x_device, - &android_pmem_device, - &android_pmem_gpu0_device, &msm_device_nand, - &msm_device_hsusb_otg, - &msm_device_hsusb_host, - &msm_device_hsusb_peripheral, - &mass_storage_device, - &msm_audio_device, - &msm_device_uart_dm1, - &msm_bluesleep_device, -#ifdef CONFIG_BT - &msm_bt_power_device, -#endif - &msm_device_i2c, - &qsd_device_spi, - &msm_device_tssc, -}; - -#ifdef CONFIG_QSD_SVS -#define TPS65023_MAX_DCDC1 1600 -#else -#define TPS65023_MAX_DCDC1 CONFIG_QSD_PMIC_DEFAULT_DCDC1 -#endif - -static int qsd8x50_tps65023_set_dcdc1(int mVolts) -{ - int rc = 0; -#ifdef CONFIG_QSD_SVS - rc = tps65023_set_dcdc1_level(mVolts); - /* By default the TPS65023 will be initialized to 1.225V. - * So we can safely switch to any frequency within this - * voltage even if the device is not probed/ready. - */ - if (rc == -ENODEV && mVolts <= CONFIG_QSD_PMIC_DEFAULT_DCDC1) - rc = 0; -#else - /* Disallow frequencies not supported in the default PMIC - * output voltage. - */ - if (mVolts > CONFIG_QSD_PMIC_DEFAULT_DCDC1) - rc = -EFAULT; -#endif - return rc; -} - -static struct msm_acpu_clock_platform_data comet_clock_data = { - .acpu_switch_time_us = 20, - .max_speed_delta_khz = 256000, - .vdd_switch_time_us = 62, - .power_collapse_khz = 128000000, - .wait_for_irq_khz = 128000000, - .max_vdd = TPS65023_MAX_DCDC1, - .acpu_set_vdd = qsd8x50_tps65023_set_dcdc1, -}; - -static void touchpad_gpio_release(void) -{ - gpio_free(TOUCHPAD_IRQ); - gpio_free(TOUCHPAD_SUSPEND); -} - -static int touchpad_gpio_setup(void) -{ - int rc; - int suspend_pin = TOUCHPAD_SUSPEND; - int irq_pin = TOUCHPAD_IRQ; - unsigned suspend_cfg = - GPIO_CFG(suspend_pin, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA); - unsigned irq_cfg = - GPIO_CFG(irq_pin, 1, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA); - - rc = gpio_request(irq_pin, "msm_touchpad_irq"); - if (rc) { - pr_err("gpio_request failed on pin %d (rc=%d)\n", - irq_pin, rc); - goto err_gpioconfig; - } - rc = gpio_request(suspend_pin, "msm_touchpad_suspend"); - if (rc) { - pr_err("gpio_request failed on pin %d (rc=%d)\n", - suspend_pin, rc); - goto err_gpioconfig; - } - rc = gpio_tlmm_config(suspend_cfg, GPIO_ENABLE); - if (rc) { - pr_err("gpio_tlmm_config failed on pin %d (rc=%d)\n", - suspend_pin, rc); - goto err_gpioconfig; - } - rc = gpio_tlmm_config(irq_cfg, GPIO_ENABLE); - if (rc) { - pr_err("gpio_tlmm_config failed on pin %d (rc=%d)\n", - irq_pin, rc); - goto err_gpioconfig; - } - return rc; - -err_gpioconfig: - touchpad_gpio_release(); - return rc; -} - -static struct msm_touchpad_platform_data msm_touchpad_data = { - .gpioirq = TOUCHPAD_IRQ, - .gpiosuspend = TOUCHPAD_SUSPEND, - .gpio_setup = touchpad_gpio_setup, - .gpio_shutdown = touchpad_gpio_release }; @@ -787,32 +248,6 @@ err_gpioconfig: return rc; } -static struct msm_i2ckbd_platform_data msm_kybd_data = { - .hwrepeat = 0, - .scanset1 = 1, - .gpioreset = KBD_RST, - .gpioirq = KBD_IRQ, - .gpio_setup = kbd_gpio_setup, - .gpio_shutdown = kbd_gpio_release, -}; - -static struct i2c_board_info msm_i2c_board_info[] __initdata = { - { - I2C_BOARD_INFO("glidesensor", 0x2A), - .irq = MSM_GPIO_TO_INT(TOUCHPAD_IRQ), - .platform_data = &msm_touchpad_data - }, - { - I2C_BOARD_INFO("msm-i2ckbd", 0x3A), - .type = "msm-i2ckbd", - .irq = MSM_GPIO_TO_INT(KBD_IRQ), - .platform_data = &msm_kybd_data - }, - { - I2C_BOARD_INFO("tps65023", 0x48), - }, -}; - static void __init comet_init_irq(void) { msm_init_irq(); @@ -956,28 +391,6 @@ static struct mmc_platform_data comet_sdcc_data = { .translate_vdd = msm_sdcc_setup_power, }; -static void __init comet_init_mmc(void) -{ - vreg_mmc = vreg_get(NULL, "gp6"); - if (IS_ERR(vreg_mmc)) { - printk(KERN_ERR "%s: vreg get failed (%ld)\n", - __func__, PTR_ERR(vreg_mmc)); - return; - } - sdcc_gpio_init(); - msm_add_sdcc(1, &comet_sdcc_data); - msm_add_sdcc(3, &comet_sdcc_data); -} - -static struct msm_i2c_platform_data msm_i2c_pdata = { - .clk_freq = 100000, -}; - -static void __init msm_device_i2c_init(void) -{ - msm_device_i2c.dev.platform_data = &msm_i2c_pdata; -} - static struct msm_pm_platform_data msm_pm_data[MSM_PM_SLEEP_MODE_NR] = { [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].supported = 1, [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].suspend_enabled = 1, @@ -1052,50 +465,13 @@ static void __init comet_init(void) writew(cpld_info->per_reset_all_reset, cpld_base + COMET_CPLD_PER_RESET); - msm_acpu_clock_init(&comet_clock_data); - - msm_device_hsusb_peripheral.dev.platform_data = &msm_hsusb_pdata; - msm_device_hsusb_host.dev.platform_data = &msm_hsusb_pdata; platform_add_devices(devices, ARRAY_SIZE(devices)); - msm_device_uart_dm1.dev.platform_data = &msm_uart_dm1_pdata; - bt_power_init(); - msm_fb_add_devices(); - comet_init_mmc(); - msm_device_i2c_init(); - i2c_register_board_info(0, msm_i2c_board_info, - ARRAY_SIZE(msm_i2c_board_info)); - spi_register_board_info(msm_spi_board_info, - ARRAY_SIZE(msm_spi_board_info)); msm_pm_set_platform_data(msm_pm_data); } -static void __init comet_allocate_memory_regions(void) -{ - void *addr; - unsigned long size; - - addr = alloc_bootmem(android_pmem_pdata.size); - android_pmem_pdata.start = __pa(addr); - - size = MSM_FB_SIZE; - addr = (void *)MSM_FB_BASE; - msm_fb_resources[0].start = (unsigned long)addr; - msm_fb_resources[0].end = msm_fb_resources[0].start + size - 1; - printk(KERN_INFO "using %lu bytes of SMI at %lx physical for fb\n", - size, (unsigned long)addr); - - size = MSM_AUDIO_SIZE; - addr = alloc_bootmem(size); - msm_audio_resources[0].start = __pa(addr); - msm_audio_resources[0].end = __pa(addr) + MSM_AUDIO_SIZE; - printk(KERN_INFO "allocating %lu bytes at %p (%lx physical)" - "for audio\n", size, addr, __pa(addr)); -} - static void __init comet_map_io(void) { msm_map_comet_io(); - comet_allocate_memory_regions(); msm_clock_init(msm_clocks_8x50, msm_num_clocks_8x50); } -- cgit v1.2.3 From 8ffd5688f8a244b101ed161a7bdcbedfeb15a9cf Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Mon, 28 Dec 2009 16:07:22 -0800 Subject: Drop unused code from board-qsd8x50.c --- arch/arm/mach-msm/board-qsd8x50.c | 962 -------------------------------------- 1 file changed, 962 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/board-qsd8x50.c b/arch/arm/mach-msm/board-qsd8x50.c index a75b2375a78c..75e59be7fd4b 100644 --- a/arch/arm/mach-msm/board-qsd8x50.c +++ b/arch/arm/mach-msm/board-qsd8x50.c @@ -59,13 +59,10 @@ #include #include #include -#include #include -#include #include #include #include -#include #include #include @@ -76,12 +73,9 @@ #include #include #include -#include -#include #include #include #include -#include #include #include "devices.h" @@ -118,719 +112,22 @@ static struct resource smc91x_resources[] = { }, }; -static struct usb_mass_storage_platform_data usb_mass_storage_pdata = { - .nluns = 0x02, - .buf_size = 16384, - .vendor = "GOOGLE", - .product = "Mass storage", - .release = 0xffff, -}; - -static struct platform_device mass_storage_device = { - .name = "usb_mass_storage", - .id = -1, - .dev = { - .platform_data = &usb_mass_storage_pdata, - }, -}; - static struct platform_device smc91x_device = { .name = "smc91x", .id = 0, .num_resources = ARRAY_SIZE(smc91x_resources), .resource = smc91x_resources, }; -static struct usb_function_map usb_functions_map[] = { - {"diag", 0}, - {"adb", 1}, - {"modem", 2}, - {"nmea", 3}, - {"mass_storage", 4}, - {"ethernet", 5}, -}; - -/* dynamic composition */ -static struct usb_composition usb_func_composition[] = { - { - .product_id = 0x9012, - .functions = 0x5, /* 0101 */ - }, - - { - .product_id = 0x9013, - .functions = 0x15, /* 10101 */ - }, - - { - .product_id = 0x9014, - .functions = 0x30, /* 110000 */ - }, - { - .product_id = 0x9015, - .functions = 0x12, /* 10010 */ - }, - - { - .product_id = 0x9016, - .functions = 0xD, /* 01101 */ - }, - - { - .product_id = 0x9017, - .functions = 0x1D, /* 11101 */ - }, - - { - .product_id = 0xF000, - .functions = 0x10, /* 10000 */ - }, - - { - .product_id = 0xF009, - .functions = 0x20, /* 100000 */ - }, - - { - .product_id = 0x9018, - .functions = 0x1F, /* 011111 */ - }, - - { - .product_id = 0x901A, - .functions = 0x0F, /* 01111 */ - }, -}; -static struct msm_hsusb_platform_data msm_hsusb_pdata = { - .version = 0x0100, - .phy_info = (USB_PHY_INTEGRATED | USB_PHY_MODEL_180NM), - .vendor_id = 0x5c6, - .product_name = "Qualcomm HSUSB Device", - .serial_number = "1234567890ABCDEF", - .manufacturer_name = "Qualcomm Incorporated", - .compositions = usb_func_composition, - .num_compositions = ARRAY_SIZE(usb_func_composition), - .function_map = usb_functions_map, - .num_functions = ARRAY_SIZE(usb_functions_map), - .config_gpio = NULL, -}; - -static struct android_pmem_platform_data android_pmem_pdata = { - .name = "pmem", - .size = MSM_PMEM_MDP_SIZE, - .no_allocator = 0, - .cached = 1, -}; - -static struct android_pmem_platform_data android_pmem_adsp_pdata = { - .name = "pmem_adsp", - .size = MSM_PMEM_ADSP_SIZE, - .no_allocator = 0, - .cached = 0, -}; - -static struct android_pmem_platform_data android_pmem_gpu0_pdata = { - .name = "pmem_gpu0", - .start = MSM_PMEM_GPU0_BASE, - .size = MSM_PMEM_GPU0_SIZE, - .no_allocator = 0, - .cached = 0, -}; - -static struct android_pmem_platform_data android_pmem_gpu1_pdata = { - .name = "pmem_gpu1", - .no_allocator = 0, - .cached = 0, -}; - -static struct android_pmem_platform_data android_pmem_camera_pdata = { - .name = "pmem_camera", - .size = MSM_PMEM_CAMERA_SIZE, - .no_allocator = 1, - .cached = 1, -}; - -static struct platform_device android_pmem_device = { - .name = "android_pmem", - .id = 0, - .dev = { .platform_data = &android_pmem_pdata }, -}; - -static struct platform_device android_pmem_adsp_device = { - .name = "android_pmem", - .id = 1, - .dev = { .platform_data = &android_pmem_adsp_pdata }, -}; - -static struct platform_device android_pmem_gpu0_device = { - .name = "android_pmem", - .id = 2, - .dev = { .platform_data = &android_pmem_gpu0_pdata }, -}; - -static struct platform_device android_pmem_gpu1_device = { - .name = "android_pmem", - .id = 3, - .dev = { .platform_data = &android_pmem_gpu1_pdata }, -}; -static struct platform_device android_pmem_camera_device = { - .name = "android_pmem", - .id = 4, - .dev = { .platform_data = &android_pmem_camera_pdata }, - }; - -static struct resource msm_fb_resources[] = { - { - .flags = IORESOURCE_DMA, - } -}; - -static int msm_fb_detect_panel(const char *name) -{ - int ret = -EPERM; - - if (machine_is_qsd8x50_ffa()) { - if (!strncmp(name, "mddi_toshiba_wvga_pt", 20)) - ret = 0; - else - ret = -ENODEV; - } else if (machine_is_qsd8x50_surf() && !strcmp(name, "lcdc_external")) - ret = 0; - - return ret; -} - -static struct msm_fb_platform_data msm_fb_pdata = { - .detect_client = msm_fb_detect_panel, -}; - -static struct platform_device msm_fb_device = { - .name = "msm_fb", - .id = 0, - .num_resources = ARRAY_SIZE(msm_fb_resources), - .resource = msm_fb_resources, - .dev = { - .platform_data = &msm_fb_pdata, - } -}; - -static struct resource qsd_spi_resources[] = { - { - .name = "spi_irq_in", - .start = INT_SPI_INPUT, - .end = INT_SPI_INPUT, - .flags = IORESOURCE_IRQ, - }, - { - .name = "spi_irq_out", - .start = INT_SPI_OUTPUT, - .end = INT_SPI_OUTPUT, - .flags = IORESOURCE_IRQ, - }, - { - .name = "spi_irq_err", - .start = INT_SPI_ERROR, - .end = INT_SPI_ERROR, - .flags = IORESOURCE_IRQ, - }, - { - .name = "spi_base", - .start = 0xA1200000, - .end = 0xA1200000 + SZ_4K - 1, - .flags = IORESOURCE_MEM, - }, - { - .name = "spi_clk", - .start = 17, - .end = 1, - .flags = IORESOURCE_IRQ, - }, - { - .name = "spi_mosi", - .start = 18, - .end = 1, - .flags = IORESOURCE_IRQ, - }, - { - .name = "spi_miso", - .start = 19, - .end = 1, - .flags = IORESOURCE_IRQ, - }, - { - .name = "spi_cs0", - .start = 20, - .end = 1, - .flags = IORESOURCE_IRQ, - }, - { - .name = "spi_pwr", - .start = 21, - .end = 0, - .flags = IORESOURCE_IRQ, - }, - { - .name = "spi_irq_cs0", - .start = 22, - .end = 0, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct platform_device qsd_device_spi = { - .name = "spi_qsd", - .id = 0, - .num_resources = ARRAY_SIZE(qsd_spi_resources), - .resource = qsd_spi_resources, -}; - -static struct spi_board_info msm_spi_board_info[] __initdata = { - { - .modalias = "bma150", - .mode = SPI_MODE_3, - .irq = MSM_GPIO_TO_INT(22), - .bus_num = 0, - .chip_select = 0, - .max_speed_hz = 10000000, - } -}; - -static int mddi_toshiba_pmic_bl(int level) -{ - int ret = -EPERM; - - if (machine_is_qsd8x50_ffa()) { - ret = pmic_set_led_intensity(LED_LCD, level); - - if (ret) - printk(KERN_WARNING "%s: can't set lcd backlight!\n", - __func__); - } - - return ret; -} - -static struct msm_panel_common_pdata mddi_toshiba_pdata = { - .pmic_backlight = mddi_toshiba_pmic_bl, -}; - -static struct platform_device mddi_toshiba_device = { - .name = "mddi_toshiba", - .id = 0, - .dev = { - .platform_data = &mddi_toshiba_pdata, - } -}; - -static void msm_fb_vreg_config(const char *name, int on) -{ - struct vreg *vreg; - int ret = 0; - - vreg = vreg_get(NULL, name); - if (IS_ERR(vreg)) { - printk(KERN_ERR "%s: vreg_get(%s) failed (%ld)\n", - __func__, name, PTR_ERR(vreg)); - return; - } - - ret = (on) ? vreg_enable(vreg) : vreg_disable(vreg); - if (ret) - printk(KERN_ERR "%s: %s(%s) failed!\n", - __func__, (on) ? "vreg_enable" : "vreg_disable", name); -} - -#define MDDI_RST_OUT_GPIO 100 - -static void msm_fb_mddi_power_save(int on) -{ - int flag_on = !!on; - - if (!flag_on && machine_is_qsd8x50_ffa()) { - gpio_set_value(MDDI_RST_OUT_GPIO, 0); - mdelay(1); - } - - msm_fb_vreg_config("gp5", flag_on); - msm_fb_vreg_config("boost", flag_on); - - if (flag_on && machine_is_qsd8x50_ffa()) { - gpio_set_value(MDDI_RST_OUT_GPIO, 0); - mdelay(1); - gpio_set_value(MDDI_RST_OUT_GPIO, 1); - gpio_set_value(MDDI_RST_OUT_GPIO, 1); - mdelay(1); - } -} - -static int msm_fb_mddi_sel_clk(u32 *clk_rate) -{ - *clk_rate *= 2; - return 0; -} - -static struct mddi_platform_data mddi_pdata = { - .mddi_power_save = msm_fb_mddi_power_save, - .mddi_sel_clk = msm_fb_mddi_sel_clk, -}; - -static struct msm_panel_common_pdata mdp_pdata = { - .gpio = 98, -}; - -static void __init msm_fb_add_devices(void) -{ - msm_fb_register_device("mdp", &mdp_pdata); - msm_fb_register_device("pmdh", &mddi_pdata); - msm_fb_register_device("emdh", &mddi_pdata); - msm_fb_register_device("tvenc", 0); - msm_fb_register_device("lcdc", 0); -} - -static struct resource msm_audio_resources[] = { - { - .flags = IORESOURCE_DMA, - }, - { - .name = "aux_pcm_dout", - .start = 68, - .end = 68, - .flags = IORESOURCE_IO, - }, - { - .name = "aux_pcm_din", - .start = 69, - .end = 69, - .flags = IORESOURCE_IO, - }, - { - .name = "aux_pcm_syncout", - .start = 70, - .end = 70, - .flags = IORESOURCE_IO, - }, - { - .name = "aux_pcm_clkin_a", - .start = 71, - .end = 71, - .flags = IORESOURCE_IO, - }, - { - .name = "sdac_din", - .start = 144, - .end = 144, - .flags = IORESOURCE_IO, - }, - { - .name = "sdac_dout", - .start = 145, - .end = 145, - .flags = IORESOURCE_IO, - }, - { - .name = "sdac_wsout", - .start = 143, - .end = 143, - .flags = IORESOURCE_IO, - }, - { - .name = "cc_i2s_clk", - .start = 142, - .end = 142, - .flags = IORESOURCE_IO, - }, - { - .name = "audio_master_clkout", - .start = 146, - .end = 146, - .flags = IORESOURCE_IO, - }, - -}; - -static unsigned audio_gpio_on[] = { - GPIO_CFG(68, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* PCM_DOUT */ - GPIO_CFG(69, 1, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), /* PCM_DIN */ - GPIO_CFG(70, 2, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* PCM_SYNC */ - GPIO_CFG(71, 2, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* PCM_CLK */ - GPIO_CFG(142, 2, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* CC_I2S_CLK */ - GPIO_CFG(143, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* SADC_WSOUT */ - GPIO_CFG(144, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* SADC_DIN */ - GPIO_CFG(145, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* SDAC_DOUT */ - GPIO_CFG(146, 2, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* MA_CLK_OUT */ -}; - -static void __init audio_gpio_init(void) -{ - int pin, rc; - - for (pin = 0; pin < ARRAY_SIZE(audio_gpio_on); pin++) { - rc = gpio_tlmm_config(audio_gpio_on[pin], - GPIO_ENABLE); - if (rc) { - printk(KERN_ERR - "%s: gpio_tlmm_config(%#x)=%d\n", - __func__, audio_gpio_on[pin], rc); - return; - } - } -} - -static struct platform_device msm_audio_device = { - .name = "msm_audio", - .id = 0, - .num_resources = ARRAY_SIZE(msm_audio_resources), - .resource = msm_audio_resources, -}; - -static struct resource bluesleep_resources[] = { - { - .name = "gpio_host_wake", - .start = 21, - .end = 21, - .flags = IORESOURCE_IO, - }, - { - .name = "gpio_ext_wake", - .start = 19, - .end = 19, - .flags = IORESOURCE_IO, - }, - { - .name = "host_wake", - .start = MSM_GPIO_TO_INT(21), - .end = MSM_GPIO_TO_INT(21), - .flags = IORESOURCE_IRQ, - }, -}; - -static struct platform_device msm_bluesleep_device = { - .name = "bluesleep", - .id = -1, - .num_resources = ARRAY_SIZE(bluesleep_resources), - .resource = bluesleep_resources, -}; - -#ifdef CONFIG_BT -static struct platform_device msm_bt_power_device = { - .name = "bt_power", -}; - -enum { - BT_SYSRST, - BT_WAKE, - BT_HOST_WAKE, - BT_PWR_EN, - BT_RFR, - BT_CTS, - BT_RX, - BT_TX, - BT_PCM_DOUT, - BT_PCM_DIN, - BT_PCM_SYNC, - BT_PCM_CLK, -}; - -static unsigned bt_config_power_on[] = { - GPIO_CFG(18, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* SYSRST */ - GPIO_CFG(19, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* WAKE */ - GPIO_CFG(21, 0, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), /* HOST_WAKE */ - GPIO_CFG(22, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* VDD_IO */ - GPIO_CFG(43, 2, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* RFR */ - GPIO_CFG(44, 2, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), /* CTS */ - GPIO_CFG(45, 2, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), /* Rx */ - GPIO_CFG(46, 2, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* Tx */ - GPIO_CFG(113, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* VDD_FREG */ -}; - -static int bluetooth_power(int on) -{ - printk(KERN_DEBUG "Bluetooth power switch: %d\n", on); - - gpio_set_value(18, on); /* SYSRST* */ - - return 0; -} - -static void __init bt_power_init(void) -{ - int pin, rc; - - for (pin = 0; pin < ARRAY_SIZE(bt_config_power_on); pin++) { - rc = gpio_tlmm_config(bt_config_power_on[pin], - GPIO_ENABLE); - if (rc) { - printk(KERN_ERR - "%s: gpio_tlmm_config(%#x)=%d\n", - __func__, bt_config_power_on[pin], rc); - return; - } - } - - gpio_set_value(18, 0); /* SYSRST* */ - gpio_set_value(22, 1); /* VDD_IO */ - gpio_set_value(113, 1); /* VDD_FREG */ - msm_bt_power_device.dev.platform_data = &bluetooth_power; - printk(KERN_DEBUG "Bluetooth power switch initialized\n"); -} -#else -#define bt_power_init(x) do {} while (0) -#endif - -static struct resource kgsl_resources[] = { - { - .name = "kgsl_reg_memory", - .start = 0xA0000000, - .end = 0xA001ffff, - .flags = IORESOURCE_MEM, - }, - { - .name = "kgsl_phys_memory", - .start = MSM_GPU_PHYS_BASE, - .end = MSM_GPU_PHYS_BASE + MSM_GPU_PHYS_SIZE - 1, - .flags = IORESOURCE_MEM, - }, - { - .start = INT_GRAPHICS, - .end = INT_GRAPHICS, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct platform_device msm_device_kgsl = { - .name = "kgsl", - .id = -1, - .num_resources = ARRAY_SIZE(kgsl_resources), - .resource = kgsl_resources, -}; - -static struct platform_device msm_device_pmic_leds = { - .name = "pmic-leds", - .id = -1, -}; static struct platform_device *devices[] __initdata = { - &msm_fb_device, - &mddi_toshiba_device, &smc91x_device, &msm_device_smd, &msm_device_dmov, - &android_pmem_device, - &android_pmem_adsp_device, - &android_pmem_gpu0_device, - &android_pmem_gpu1_device, &msm_device_nand, - &msm_device_i2c, - &qsd_device_spi, - &msm_device_hsusb_otg, - &msm_device_hsusb_host, - &msm_device_hsusb_peripheral, - &mass_storage_device, - &msm_device_tssc, - &android_pmem_camera_device, - &msm_audio_device, - &msm_device_uart_dm1, - &msm_bluesleep_device, -#ifdef CONFIG_BT - &msm_bt_power_device, -#endif #if !defined(CONFIG_MSM_SERIAL_DEBUGGER) &msm_device_uart3, #endif - &msm_device_pmic_leds, - &msm_device_kgsl, -}; - -#ifdef CONFIG_QSD_SVS -#define TPS65023_MAX_DCDC1 1600 -#else -#define TPS65023_MAX_DCDC1 CONFIG_QSD_PMIC_DEFAULT_DCDC1 -#endif - -static int qsd8x50_tps65023_set_dcdc1(int mVolts) -{ - int rc = 0; -#ifdef CONFIG_QSD_SVS - rc = tps65023_set_dcdc1_level(mVolts); - /* By default the TPS65023 will be initialized to 1.225V. - * So we can safely switch to any frequency within this - * voltage even if the device is not probed/ready. - */ - if (rc == -ENODEV && mVolts <= CONFIG_QSD_PMIC_DEFAULT_DCDC1) - rc = 0; -#else - /* Disallow frequencies not supported in the default PMIC - * output voltage. - */ - if (mVolts > CONFIG_QSD_PMIC_DEFAULT_DCDC1) - rc = -EFAULT; -#endif - return rc; -} - -static struct msm_acpu_clock_platform_data qsd8x50_clock_data = { - .acpu_switch_time_us = 20, - .max_speed_delta_khz = 256000, - .vdd_switch_time_us = 62, - .power_collapse_khz = 128000000, - .wait_for_irq_khz = 128000000, - .max_vdd = TPS65023_MAX_DCDC1, - .acpu_set_vdd = qsd8x50_tps65023_set_dcdc1, -}; - - -static void touchpad_gpio_release(void) -{ - gpio_free(TOUCHPAD_IRQ); - gpio_free(TOUCHPAD_SUSPEND); -} - -static int touchpad_gpio_setup(void) -{ - int rc; - int suspend_pin = TOUCHPAD_SUSPEND; - int irq_pin = TOUCHPAD_IRQ; - unsigned suspend_cfg = - GPIO_CFG(suspend_pin, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA); - unsigned irq_cfg = - GPIO_CFG(irq_pin, 1, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA); - - rc = gpio_request(irq_pin, "msm_touchpad_irq"); - if (rc) { - pr_err("gpio_request failed on pin %d (rc=%d)\n", - irq_pin, rc); - goto err_gpioconfig; - } - rc = gpio_request(suspend_pin, "msm_touchpad_suspend"); - if (rc) { - pr_err("gpio_request failed on pin %d (rc=%d)\n", - suspend_pin, rc); - goto err_gpioconfig; - } - rc = gpio_tlmm_config(suspend_cfg, GPIO_ENABLE); - if (rc) { - pr_err("gpio_tlmm_config failed on pin %d (rc=%d)\n", - suspend_pin, rc); - goto err_gpioconfig; - } - rc = gpio_tlmm_config(irq_cfg, GPIO_ENABLE); - if (rc) { - pr_err("gpio_tlmm_config failed on pin %d (rc=%d)\n", - irq_pin, rc); - goto err_gpioconfig; - } - return rc; - -err_gpioconfig: - touchpad_gpio_release(); - return rc; -} - -static struct msm_touchpad_platform_data msm_touchpad_data = { - .gpioirq = TOUCHPAD_IRQ, - .gpiosuspend = TOUCHPAD_SUSPEND, - .gpio_setup = touchpad_gpio_setup, - .gpio_shutdown = touchpad_gpio_release }; #define KBD_RST 35 @@ -891,76 +188,6 @@ static struct msm_i2ckbd_platform_data msm_kybd_data = { .gpio_setup = kbd_gpio_setup, .gpio_shutdown = kbd_gpio_release, }; - -static struct i2c_board_info msm_i2c_board_info[] __initdata = { - { - I2C_BOARD_INFO("glidesensor", 0x2A), - .irq = MSM_GPIO_TO_INT(TOUCHPAD_IRQ), - .platform_data = &msm_touchpad_data - }, - { - I2C_BOARD_INFO("msm-i2ckbd", 0x3A), - .type = "msm-i2ckbd", - .irq = MSM_GPIO_TO_INT(KBD_IRQ), - .platform_data = &msm_kybd_data - }, - { - I2C_BOARD_INFO("mt9d112", 0x78 >> 1), - }, - { - I2C_BOARD_INFO("s5k3e2fx", 0x20 >> 1), - }, - { - I2C_BOARD_INFO("mt9p012", 0x6C >> 1), - }, - { - I2C_BOARD_INFO("mt9t013", 0x6C), - }, - { - I2C_BOARD_INFO("tps65023", 0x48), - }, -}; - -static uint32_t camera_off_gpio_table[] = { - /* parallel CAMERA interfaces */ - GPIO_CFG(0, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT0 */ - GPIO_CFG(1, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT1 */ - GPIO_CFG(2, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT2 */ - GPIO_CFG(3, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT3 */ - GPIO_CFG(4, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT4 */ - GPIO_CFG(5, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT5 */ - GPIO_CFG(6, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT6 */ - GPIO_CFG(7, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT7 */ - GPIO_CFG(8, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT8 */ - GPIO_CFG(9, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT9 */ - GPIO_CFG(10, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT10 */ - GPIO_CFG(11, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT11 */ - GPIO_CFG(12, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* PCLK */ - GPIO_CFG(13, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* HSYNC_IN */ - GPIO_CFG(14, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* VSYNC_IN */ - GPIO_CFG(15, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* MCLK */ -}; - -static uint32_t camera_on_gpio_table[] = { - /* parallel CAMERA interfaces */ - GPIO_CFG(0, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT0 */ - GPIO_CFG(1, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT1 */ - GPIO_CFG(2, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT2 */ - GPIO_CFG(3, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT3 */ - GPIO_CFG(4, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT4 */ - GPIO_CFG(5, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT5 */ - GPIO_CFG(6, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT6 */ - GPIO_CFG(7, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT7 */ - GPIO_CFG(8, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT8 */ - GPIO_CFG(9, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT9 */ - GPIO_CFG(10, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT10 */ - GPIO_CFG(11, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT11 */ - GPIO_CFG(12, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* PCLK */ - GPIO_CFG(13, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* HSYNC_IN */ - GPIO_CFG(14, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* VSYNC_IN */ - GPIO_CFG(15, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_16MA), /* MCLK */ -}; - static void config_gpio_table(uint32_t *table, int len) { int n, rc; @@ -974,95 +201,6 @@ static void config_gpio_table(uint32_t *table, int len) } } -static void config_camera_on_gpios(void) -{ - config_gpio_table(camera_on_gpio_table, - ARRAY_SIZE(camera_on_gpio_table)); -} - -static void config_camera_off_gpios(void) -{ - config_gpio_table(camera_off_gpio_table, - ARRAY_SIZE(camera_off_gpio_table)); -} - -#define MSM_PROBE_INIT(name) name##_probe_init -static struct msm_camera_sensor_info msm_camera_sensor[] = { - { - .sensor_reset = 17, - .sensor_pwd = 85, - .vcm_pwd = 0, - .sensor_name = "mt9d112", - .flash_type = MSM_CAMERA_FLASH_NONE, -#ifdef CONFIG_MSM_CAMERA - .sensor_probe = MSM_PROBE_INIT(mt9d112), -#endif - }, - { - .sensor_reset = 17, - .sensor_pwd = 85, - .vcm_pwd = 0, - .sensor_name = "s5k3e2fx", - .flash_type = MSM_CAMERA_FLASH_NONE, -#ifdef CONFIG_MSM_CAMERA - .sensor_probe = MSM_PROBE_INIT(s5k3e2fx), -#endif - }, - { - .sensor_reset = 17, - .sensor_pwd = 85, - .vcm_pwd = 0, - .sensor_name = "mt9p012", - .flash_type = MSM_CAMERA_FLASH_LED, -#ifdef CONFIG_MSM_CAMERA - .sensor_probe = MSM_PROBE_INIT(mt9p012), -#endif - }, - { - .sensor_reset = 17, - .sensor_pwd = 85, - .vcm_pwd = 0, - .sensor_name = "mt9t013", - .flash_type = MSM_CAMERA_FLASH_NONE, -#ifdef CONFIG_MSM_CAMERA - .sensor_probe = MSM_PROBE_INIT(mt9t013), -#endif - }, -}; -#undef MSM_PROBE_INIT - -static struct msm_camera_device_platform_data msm_camera_device_data = { - .camera_gpio_on = config_camera_on_gpios, - .camera_gpio_off = config_camera_off_gpios, - .snum = ARRAY_SIZE(msm_camera_sensor), - .sinfo = &msm_camera_sensor[0], - .ioext.mdcphy = MSM_MDC_PHYS, - .ioext.mdcsz = MSM_MDC_SIZE, - .ioext.appphy = MSM_CLK_CTL_PHYS, - .ioext.appsz = MSM_CLK_CTL_SIZE, -}; - -static struct resource msm_camera_resources[] = { - { - .start = 0xA0F00000, - .end = 0xA0F00000 + SZ_1M - 1, - .flags = IORESOURCE_MEM, - }, - { - .start = INT_VFE, - .end = INT_VFE, - .flags = IORESOURCE_IRQ, - }, -}; - -static void __init msm_camera_add_device(void) -{ - msm_camera_register_device(&msm_camera_resources, - ARRAY_SIZE(msm_camera_resources), &msm_camera_device_data); - - config_camera_off_gpios(); -} - static void __init qsd8x50_init_irq(void) { msm_init_irq(); @@ -1242,36 +380,6 @@ static struct mmc_platform_data qsd8x50_sdcc_data = { .translate_vdd = msm_sdcc_setup_power, }; -static void __init qsd8x50_init_mmc(void) -{ - if (!machine_is_qsd8x50_ffa()) - vreg_mmc = vreg_get(NULL, "gp5"); - - if (IS_ERR(vreg_mmc)) { - printk(KERN_ERR "%s: vreg get failed (%ld)\n", - __func__, PTR_ERR(vreg_mmc)); - return; - } - - sdcc_gpio_init(); -#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT - msm_add_sdcc(1, &qsd8x50_sdcc_data); -#endif - - if (machine_is_qsd8x50_surf()) { -#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT - msm_add_sdcc(2, &qsd8x50_sdcc_data); -#endif -#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT - msm_add_sdcc(3, &qsd8x50_sdcc_data); -#endif -#ifdef CONFIG_MMC_MSM_SDC4_SUPPORT - msm_add_sdcc(4, &qsd8x50_sdcc_data); -#endif - } - -} - static void __init qsd8x50_cfg_smc91x(void) { int rc = 0; @@ -1298,15 +406,6 @@ static void __init qsd8x50_cfg_smc91x(void) printk(KERN_ERR "%s: invalid machine type\n", __func__); } -static struct msm_i2c_platform_data msm_i2c_pdata = { - .clk_freq = 100000, -}; - -static void __init msm_device_i2c_init(void) -{ - msm_device_i2c.dev.platform_data = &msm_i2c_pdata; -} - static struct msm_pm_platform_data msm_pm_data[MSM_PM_SLEEP_MODE_NR] = { [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].supported = 1, [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].suspend_enabled = 1, @@ -1371,21 +470,8 @@ static void __init qsd8x50_init(void) printk(KERN_ERR "%s: socinfo_init() failed!\n", __func__); qsd8x50_cfg_smc91x(); - msm_acpu_clock_init(&qsd8x50_clock_data); - msm_device_hsusb_peripheral.dev.platform_data = &msm_hsusb_pdata; - msm_device_hsusb_host.dev.platform_data = &msm_hsusb_pdata; platform_add_devices(devices, ARRAY_SIZE(devices)); - msm_fb_add_devices(); - msm_camera_add_device(); gp6_init(); - qsd8x50_init_mmc(); - bt_power_init(); - audio_gpio_init(); - msm_device_i2c_init(); - i2c_register_board_info(0, msm_i2c_board_info, - ARRAY_SIZE(msm_i2c_board_info)); - spi_register_board_info(msm_spi_board_info, - ARRAY_SIZE(msm_spi_board_info)); msm_pm_set_platform_data(msm_pm_data); #ifdef CONFIG_SURF_FFA_GPIO_KEYPAD @@ -1396,58 +482,10 @@ static void __init qsd8x50_init(void) #endif } -static void __init qsd8x50_allocate_memory_regions(void) -{ - void *addr; - unsigned long size; - - size = MSM_PMEM_CAMERA_SIZE; - addr = alloc_bootmem(size); - android_pmem_camera_pdata.start = __pa(addr); - android_pmem_camera_pdata.size = size; - printk(KERN_INFO "allocating %lu bytes at %p (%lx physical)" - "for camera pmem\n", size, addr, __pa(addr)); - - size = MSM_PMEM_MDP_SIZE; - addr = alloc_bootmem(size); - android_pmem_pdata.start = __pa(addr); - android_pmem_pdata.size = size; - printk(KERN_INFO "allocating %lu bytes at %p (%lx physical)" - "for pmem\n", size, addr, __pa(addr)); - - size = MSM_PMEM_ADSP_SIZE; - addr = alloc_bootmem(size); - android_pmem_adsp_pdata.start = __pa(addr); - android_pmem_adsp_pdata.size = size; - printk(KERN_INFO "allocating %lu bytes at %p (%lx physical)" - "for adsp pmem\n", size, addr, __pa(addr)); - - size = MSM_PMEM_GPU1_SIZE; - addr = alloc_bootmem_aligned(size, 0x100000); - android_pmem_gpu1_pdata.start = __pa(addr); - android_pmem_gpu1_pdata.size = size; - printk(KERN_INFO "allocating %lu bytes at %p (%lx physical)" - "for gpu1 pmem\n", size, addr, __pa(addr)); - - size = MSM_FB_SIZE; - addr = (void *)MSM_FB_BASE; - msm_fb_resources[0].start = (unsigned long)addr; - msm_fb_resources[0].end = msm_fb_resources[0].start + size - 1; - printk(KERN_INFO "using %lu bytes of SMI at %lx physical for fb\n", - size, (unsigned long)addr); - - size = MSM_AUDIO_SIZE; - addr = alloc_bootmem(size); - msm_audio_resources[0].start = __pa(addr); - msm_audio_resources[0].end = __pa(addr) + MSM_AUDIO_SIZE; - printk(KERN_INFO "allocating %lu bytes at %p (%lx physical)" - "for audio\n", size, addr, __pa(addr)); -} static void __init qsd8x50_map_io(void) { msm_map_qsd8x50_io(); - qsd8x50_allocate_memory_regions(); msm_clock_init(msm_clocks_8x50, msm_num_clocks_8x50); } -- cgit v1.2.3 From eb1995d87bb68fea6e149748d86c25aa76e41805 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Mon, 28 Dec 2009 16:08:00 -0800 Subject: Drop more unused code from devices.c --- arch/arm/mach-msm/devices.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/devices.c b/arch/arm/mach-msm/devices.c index d25191acdaec..a64578f1a032 100644 --- a/arch/arm/mach-msm/devices.c +++ b/arch/arm/mach-msm/devices.c @@ -285,7 +285,6 @@ struct clk msm_clocks_7x01a[] = { CLK_PCOM("emdh_clk", EMDH_CLK, NULL, OFF | CLK_MINMAX), CLK_PCOM("gp_clk", GP_CLK, NULL, 0), CLK_PCOM("grp_clk", GRP_CLK, NULL, OFF), - CLK_PCOM("i2c_clk", I2C_CLK, &msm_device_i2c.dev, 0), CLK_PCOM("icodec_rx_clk", ICODEC_RX_CLK, NULL, 0), CLK_PCOM("icodec_tx_clk", ICODEC_TX_CLK, NULL, 0), CLK_PCOM("imem_clk", IMEM_CLK, NULL, OFF), @@ -328,7 +327,6 @@ struct clk msm_clocks_7x25[] = { CLK_PCOM("ebi2_clk", EBI2_CLK, NULL, 0), CLK_PCOM("ecodec_clk", ECODEC_CLK, NULL, 0), CLK_PCOM("gp_clk", GP_CLK, NULL, 0), - CLK_PCOM("i2c_clk", I2C_CLK, &msm_device_i2c.dev, 0), CLK_PCOM("icodec_rx_clk", ICODEC_RX_CLK, NULL, 0), CLK_PCOM("icodec_tx_clk", ICODEC_TX_CLK, NULL, 0), CLK_PCOM("imem_clk", IMEM_CLK, NULL, OFF), @@ -372,7 +370,6 @@ struct clk msm_clocks_7x27[] = { CLK_PCOM("gp_clk", GP_CLK, NULL, 0), CLK_PCOM("grp_clk", GRP_CLK, NULL, 0), CLK_PCOM("grp_pclk", GRP_PCLK, NULL, 0), - CLK_PCOM("i2c_clk", I2C_CLK, &msm_device_i2c.dev, 0), CLK_PCOM("icodec_rx_clk", ICODEC_RX_CLK, NULL, 0), CLK_PCOM("icodec_tx_clk", ICODEC_TX_CLK, NULL, 0), CLK_PCOM("imem_clk", IMEM_CLK, NULL, OFF), @@ -421,7 +418,6 @@ struct clk msm_clocks_7x30[] = { CLK_PCOM("grp_clk", GRP_CLK, NULL, 0), CLK_PCOM("grp_pclk", GRP_PCLK, NULL, 0), CLK_PCOM("hdmi_clk", HDMI_CLK, NULL, 0), - CLK_PCOM("i2c_clk", I2C_CLK, &msm_device_i2c.dev, 0), CLK_PCOM("imem_clk", IMEM_CLK, NULL, OFF), CLK_PCOM("lpa_codec_clk", LPA_CODEC_CLK, NULL, 0), CLK_PCOM("lpa_core_clk", LPA_CORE_CLK, NULL, 0), @@ -487,7 +483,6 @@ struct clk msm_clocks_8x50[] = { CLK_PCOM("emdh_clk", EMDH_CLK, NULL, OFF | CLK_MINMAX), CLK_PCOM("gp_clk", GP_CLK, NULL, 0), CLK_PCOM("grp_clk", GRP_CLK, NULL, 0), - CLK_PCOM("i2c_clk", I2C_CLK, &msm_device_i2c.dev, 0), CLK_PCOM("icodec_rx_clk", ICODEC_RX_CLK, NULL, 0), CLK_PCOM("icodec_tx_clk", ICODEC_TX_CLK, NULL, 0), CLK_PCOM("imem_clk", IMEM_CLK, NULL, OFF), -- cgit v1.2.3 From 6baaef89b3b82e37dc38a8180192426aea0db25a Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Wed, 23 Dec 2009 10:00:34 -0800 Subject: arm: msm: convert cyc2ns to clocksource_cyc2ns Just a little update to convert over to the new API for this fucntion call. Signed-off-by: Daniel Walker --- arch/arm/mach-msm/timer.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c index 0f668dcd098a..02fbdca60525 100644 --- a/arch/arm/mach-msm/timer.c +++ b/arch/arm/mach-msm/timer.c @@ -571,7 +571,7 @@ int64_t msm_timer_enter_idle(void) } if (delta <= 0) return 0; - return cyc2ns(&clock->clocksource, (alarm - count) >> clock->shift); + return clocksource_cyc2ns((alarm - count) >> clock->shift , clock->clocksource.mult, clock->clocksource.shift); } void msm_timer_exit_idle(int low_power) @@ -716,13 +716,13 @@ unsigned long long sched_clock(void) if (!saved_ticks_valid) { saved_ticks_valid = 1; last_ticks = ticks; - base -= cyc2ns(cs, ticks); + base -= clocksource_cyc2ns(ticks, cs->mult, cs->shift); } if (ticks < last_ticks) { - base += cyc2ns(cs, cs->mask); - base += cyc2ns(cs, 1); + base += clocksource_cyc2ns(cs->mask, cs->mult, cs->shift); + base += clocksource_cyc2ns(1, cs->mult, cs->shift); } - last_result = result = cyc2ns(cs, ticks) + base; + last_result = result = clocksource_cyc2ns(ticks, cs->mult, cs->shift) + base; } else { base = result = last_result; saved_ticks_valid = 0; -- cgit v1.2.3 From 91b91325daf46ba88a8e54720457b1020e616eaa Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Fri, 25 Dec 2009 14:39:38 -0800 Subject: arm: msm: move suspend_late to pm_ops Signed-off-by: Daniel Walker --- arch/arm/mach-msm/dma.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/dma.c b/arch/arm/mach-msm/dma.c index fae9dc88b8e4..bbfab84938c6 100644 --- a/arch/arm/mach-msm/dma.c +++ b/arch/arm/mach-msm/dma.c @@ -268,8 +268,7 @@ static irqreturn_t msm_datamover_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } -static int msm_dmov_suspend_late(struct platform_device *pdev, - pm_message_t state) +static int msm_dmov_suspend_noirq(struct device *dev) { unsigned long irq_flags; @@ -284,11 +283,15 @@ static int msm_dmov_suspend_late(struct platform_device *pdev, return 0; } +static struct dev_pm_ops dmov_pm = { + .suspend_noirq = msm_dmov_suspend_noirq, +}; + static struct platform_driver msm_dmov_driver = { - .suspend_late = msm_dmov_suspend_late, .driver = { - .name = MODULE_NAME, - .owner = THIS_MODULE, + .name = MODULE_NAME, + .owner = THIS_MODULE, + .pm = &dmov_pm, }, }; -- cgit v1.2.3 From 3658a9cc2ed554ad597005a30d0dde2c21563c9d Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Fri, 25 Dec 2009 14:42:06 -0800 Subject: arm: msm: add pm_restart argument Signed-off-by: Daniel Walker --- arch/arm/mach-msm/pm.c | 2 +- arch/arm/mach-msm/pm2.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/pm.c b/arch/arm/mach-msm/pm.c index 78ca91ff42e0..d5d26cc021ed 100644 --- a/arch/arm/mach-msm/pm.c +++ b/arch/arm/mach-msm/pm.c @@ -692,7 +692,7 @@ static void msm_pm_power_off(void) for (;;) ; } -static void msm_pm_restart(char str) +static void msm_pm_restart(char str, const char *cmd) { msm_proc_comm(PCOM_RESET_CHIP, &restart_reason, 0); diff --git a/arch/arm/mach-msm/pm2.c b/arch/arm/mach-msm/pm2.c index b601a528f91a..dd5d690b76a5 100644 --- a/arch/arm/mach-msm/pm2.c +++ b/arch/arm/mach-msm/pm2.c @@ -1554,7 +1554,7 @@ static void msm_pm_power_off(void) ; } -static void msm_pm_restart(char str) +static void msm_pm_restart(char str, const char *cmd ) { msm_proc_comm(PCOM_RESET_CHIP, &restart_reason, 0); -- cgit v1.2.3 From bf8cb0341446473a9fe3f8ae3477b0e3e9319f9b Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Sat, 2 Jan 2010 08:19:29 -0800 Subject: Remove usage of generic msm_rpcrouter.h --- arch/arm/mach-msm/smd_rpcrouter.h | 1 - 1 file changed, 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/smd_rpcrouter.h b/arch/arm/mach-msm/smd_rpcrouter.h index dfdd51492f08..fa5bc84267f7 100644 --- a/arch/arm/mach-msm/smd_rpcrouter.h +++ b/arch/arm/mach-msm/smd_rpcrouter.h @@ -22,7 +22,6 @@ #include #include #include -#include #include #include -- cgit v1.2.3 From e0c23a7a0e1229d4adc32de696bf3a6a135bedbb Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Wed, 6 Jan 2010 13:33:42 -0800 Subject: trout: drop mmc.h commits. --- arch/arm/mach-msm/board-trout-mmc.c | 2 +- arch/arm/mach-msm/board-trout.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/board-trout-mmc.c b/arch/arm/mach-msm/board-trout-mmc.c index f417fa4f4152..aee7378b6728 100644 --- a/arch/arm/mach-msm/board-trout-mmc.c +++ b/arch/arm/mach-msm/board-trout-mmc.c @@ -17,7 +17,7 @@ #include #include -#include +#include #include "devices.h" diff --git a/arch/arm/mach-msm/board-trout.c b/arch/arm/mach-msm/board-trout.c index 637253ec3f78..97ee39a5db23 100644 --- a/arch/arm/mach-msm/board-trout.c +++ b/arch/arm/mach-msm/board-trout.c @@ -50,7 +50,7 @@ #include #include -#include +#include #include #include -- cgit v1.2.3 From b334b4519cb4094e08bcbfaca693f81d8b6ea014 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Wed, 6 Jan 2010 13:36:46 -0800 Subject: drop all mmc.h commits. --- arch/arm/mach-msm/board-comet.c | 2 +- arch/arm/mach-msm/board-halibut.c | 2 +- arch/arm/mach-msm/board-qsd8x50.c | 2 +- arch/arm/mach-msm/devices.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/board-comet.c b/arch/arm/mach-msm/board-comet.c index 9d8e290e8930..01333821f343 100644 --- a/arch/arm/mach-msm/board-comet.c +++ b/arch/arm/mach-msm/board-comet.c @@ -66,7 +66,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-msm/board-halibut.c b/arch/arm/mach-msm/board-halibut.c index 537516723f16..abb123aab8e2 100644 --- a/arch/arm/mach-msm/board-halibut.c +++ b/arch/arm/mach-msm/board-halibut.c @@ -34,7 +34,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-msm/board-qsd8x50.c b/arch/arm/mach-msm/board-qsd8x50.c index 75e59be7fd4b..f9a038db9310 100644 --- a/arch/arm/mach-msm/board-qsd8x50.c +++ b/arch/arm/mach-msm/board-qsd8x50.c @@ -67,7 +67,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-msm/devices.c b/arch/arm/mach-msm/devices.c index a64578f1a032..737fd09d2841 100644 --- a/arch/arm/mach-msm/devices.c +++ b/arch/arm/mach-msm/devices.c @@ -29,7 +29,7 @@ #include #include -#include +#include static struct resource resources_uart1[] = { { -- cgit v1.2.3 From e25676c38b01d033137d550ce1e851fa019a289d Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Wed, 13 Jan 2010 11:25:01 -0800 Subject: Add the generic remote spinlock code into the platform specific header. --- arch/arm/mach-msm/include/mach/remote_spinlock.h | 50 ++++++++++++++++++++++++ 1 file changed, 50 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-msm/include/mach/remote_spinlock.h b/arch/arm/mach-msm/include/mach/remote_spinlock.h index 8d8a5ddb8a4e..015b6ffd89af 100644 --- a/arch/arm/mach-msm/include/mach/remote_spinlock.h +++ b/arch/arm/mach-msm/include/mach/remote_spinlock.h @@ -35,6 +35,7 @@ #define __ASM__ARCH_QC_REMOTE_SPINLOCK_H #include +#include typedef struct { volatile uint32_t lock; @@ -111,5 +112,54 @@ int _remote_spin_lock_init(remote_spin_lock_id_t id, _remote_spinlock_t *lock); #define _remote_spin_unlock(lock) __raw_remote_ex_spin_unlock(*lock) #endif /* CONFIG_ARCH_MSM_ARM11 */ + +/* Grabbing a local spin lock before going for a remote lock has several + * advantages: + * 1. Get calls to preempt enable/disable and IRQ save/restore for free. + * 2. For UP kernel, there is no overhead. + * 3. Reduces the possibility of executing the remote spin lock code. This is + * especially useful when the remote CPUs' mutual exclusion instructions + * don't work with the local CPUs' instructions. In such cases, one has to + * use software based mutex algorithms (e.g. Lamport's bakery algorithm) + * which could get expensive when the no. of contending CPUs is high. + * 4. In the case of software based mutex algorithm the exection time will be + * smaller since the no. of contending CPUs is reduced by having just one + * contender for all the local CPUs. + * 5. Get most of the spin lock debug features for free. + * 6. The code will continue to work "gracefully" even when the remote spin + * lock code is stubbed out for debug purposes or when there is no remote + * CPU in some board/machine types. + */ +typedef struct { + spinlock_t local; + _remote_spinlock_t remote; +} remote_spinlock_t; + +#define remote_spin_lock_init(lock,id) \ + do { \ + spin_lock_init(&((lock)->local)); \ + _remote_spin_lock_init(id, &((lock)->remote)); \ + } while (0) +#define remote_spin_lock(lock) \ + do { \ + spin_lock(&((lock)->local)); \ + _remote_spin_lock(&((lock)->remote)); \ + } while (0) +#define remote_spin_unlock(lock) \ + do { \ + _remote_spin_unlock(&((lock)->remote)); \ + spin_unlock(&((lock)->local)); \ + } while (0) +#define remote_spin_lock_irqsave(lock, flags) \ + do { \ + spin_lock_irqsave(&((lock)->local), flags); \ + _remote_spin_lock(&((lock)->remote)); \ + } while (0) +#define remote_spin_unlock_irqrestore(lock, flags) \ + do { \ + _remote_spin_unlock(&((lock)->remote)); \ + spin_unlock_irqrestore(&((lock)->local), flags); \ + } while (0) + #endif /* __ASM__ARCH_QC_REMOTE_SPINLOCK_H */ -- cgit v1.2.3 From 8813297af3f60e75ca0993c13e5a239ffed272fa Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Wed, 13 Jan 2010 11:25:44 -0800 Subject: Change the smem_log remote_spinlock header to platform specific. --- arch/arm/mach-msm/smem_log.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/smem_log.c b/arch/arm/mach-msm/smem_log.c index c2809109fc62..33c81e234726 100644 --- a/arch/arm/mach-msm/smem_log.c +++ b/arch/arm/mach-msm/smem_log.c @@ -65,11 +65,11 @@ #include #include #include -#include #include #include #include +#include #include #include -- cgit v1.2.3 From 4c02b76c8d8cb19c508a6effcd419022982b4726 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Wed, 13 Jan 2010 11:27:15 -0800 Subject: Change the acpu_clock remote_spinlock header to platform specific. --- arch/arm/mach-msm/acpuclock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/acpuclock.c b/arch/arm/mach-msm/acpuclock.c index bcc8491ab342..7214a9235c30 100644 --- a/arch/arm/mach-msm/acpuclock.c +++ b/arch/arm/mach-msm/acpuclock.c @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include #include -- cgit v1.2.3 From cdf6c137865357112aa31666b65b938ab29fa736 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Tue, 19 Jan 2010 07:08:15 -0800 Subject: msm: compile fixes for dream. Signed-off-by: Daniel Walker --- arch/arm/mach-msm/Makefile | 6 ------ arch/arm/mach-msm/board-dream.c | 4 +--- 2 files changed, 1 insertion(+), 9 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 6d7937fa50ce..3f1c74dbb131 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -23,7 +23,6 @@ obj-$(CONFIG_MSM_JTAG_V7) += jtag-v7.o obj-$(CONFIG_ARCH_QSD8X50) += sirc.o obj-$(CONFIG_MSM_FIQ_SUPPORT) += fiq_glue.o -obj-$(CONFIG_MACH_TROUT) += board-trout-rfkill.o obj-$(CONFIG_MSM_SMD) += smd.o obj-$(CONFIG_MSM_SMD_LOGGING) += smem_log.o obj-$(CONFIG_MSM_SMD_TTY) += smd_tty.o @@ -52,11 +51,6 @@ obj-$(CONFIG_MSM_DMA_TEST) += dma_test.o obj-$(CONFIG_SURF_FFA_GPIO_KEYPAD) += keypad-surf-ffa.o obj-$(CONFIG_MACH_TROUT) += board-dream.o -obj-$(CONFIG_ARCH_MSM7X01A) += board-halibut.o -obj-$(CONFIG_MACH_TROUT) += board-trout.o board-trout-gpio.o -obj-$(CONFIG_MACH_TROUT) += board-trout-keypad.o board-trout-panel.o -obj-$(CONFIG_MACH_TROUT) += htc_akm_cal.o htc_wifi_nvs.o htc_acoustic.o -obj-$(CONFIG_MACH_TROUT) += board-trout-mmc.o board-trout-wifi.o obj-$(CONFIG_MACH_QSD8X50_SURF) += board-qsd8x50.o obj-$(CONFIG_MACH_QSD8X50_FFA) += board-qsd8x50.o obj-$(CONFIG_MACH_QSD8X50_COMET) += board-comet.o diff --git a/arch/arm/mach-msm/board-dream.c b/arch/arm/mach-msm/board-dream.c index 21afa8513168..96ac5c2256bf 100644 --- a/arch/arm/mach-msm/board-dream.c +++ b/arch/arm/mach-msm/board-dream.c @@ -34,8 +34,6 @@ static struct platform_device *devices[] __initdata = { &msm_device_uart3, &msm_device_smd, &msm_device_nand, - &msm_device_hsusb, - &msm_device_i2c, }; extern struct sys_timer msm_timer; @@ -78,7 +76,7 @@ static void __init trout_map_io(void) writeb(0x80, TROUT_CPLD_BASE + 0x00); #endif - msm_clock_init(); + msm_clock_init(msm_clocks_7x01a, msm_num_clocks_7x01a); } MACHINE_START(TROUT, "HTC Dream") -- cgit v1.2.3