|
From: <bob...@us...> - 2007-07-28 07:35:18
|
Revision: 1213
http://hackndev.svn.sourceforge.net/hackndev/?rev=1213&view=rev
Author: bobofdoom
Date: 2007-07-28 00:35:11 -0700 (Sat, 28 Jul 2007)
Log Message:
-----------
PalmT650: GSM driver is now usuable.
* Power is now automatically applied when ttyS0 is opened/closed, no
need to fiddle in /sys to control power.
* The wake and host wake signals are now implemented. The driver will
automatically wake up the GSM module before transmitting and after
no transmits for 1 second will let it go back to its sleep mode.
* minicom now survives suspend/resume although wake CPU on call etc
is not yet implemented, need to find out how gsmd or whatever expects
this to work.
* Radio still needs to have been turned on in Palm OS beforehand, I
guess there's still something in the ASIC that I need to configure.
Modified Paths:
--------------
linux4palm/linux/trunk/arch/arm/mach-pxa/palmt650/palmt650_gsm.c
Modified: linux4palm/linux/trunk/arch/arm/mach-pxa/palmt650/palmt650_gsm.c
===================================================================
--- linux4palm/linux/trunk/arch/arm/mach-pxa/palmt650/palmt650_gsm.c 2007-07-28 01:28:12 UTC (rev 1212)
+++ linux4palm/linux/trunk/arch/arm/mach-pxa/palmt650/palmt650_gsm.c 2007-07-28 07:35:11 UTC (rev 1213)
@@ -9,16 +9,26 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
#include <asm/arch/hardware.h>
#include <asm/arch/palmt650-gpio.h>
+#include <asm/arch/serial.h>
+static DECLARE_WAIT_QUEUE_HEAD (host_wake_queue);
+static int suspending;
+static struct timer_list wake_timer;
+static int wake_timer_running;
+
static ssize_t gsm_power_on_write(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
unsigned long on = simple_strtoul(buf, NULL, 10);
SET_ASIC6_GPIO(GSM_POWER, on);
- printk("Setting GSM power to %ld\n", on);
+ printk(KERN_INFO "palmt650_gsm: Setting GSM power to %ld\n", on);
return count;
}
@@ -26,14 +36,32 @@
struct device_attribute *attr,
char *buf)
{
- printk("GPLR is %d\n", ASIC6_GPLR);
return strlcpy(buf, GET_ASIC6_GPIO(GSM_POWER) ? "1\n" : "0\n", 3);
}
+static ssize_t gsm_wake_write(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long on = simple_strtoul(buf, NULL, 10);
+ SET_PALMT650_GPIO(GSM_WAKE, on);
+ printk(KERN_INFO "palmt650_gsm: Setting GSM wake to %ld\n", on);
+ return count;
+}
+
+static ssize_t gsm_wake_read(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return strlcpy(buf, GET_PALMT650_GPIO(GSM_WAKE) ? "1\n" : "0\n", 3);
+}
+
+
static DEVICE_ATTR(power_on, 0644, gsm_power_on_read, gsm_power_on_write);
+static DEVICE_ATTR(wake, 0644, gsm_wake_read, gsm_wake_write);
static struct attribute *palmt650_gsm_attrs[] = {
&dev_attr_power_on.attr,
+ &dev_attr_wake.attr,
NULL
};
@@ -42,19 +70,143 @@
.attrs = palmt650_gsm_attrs,
};
+static void palmt650_gsm_configure(int state)
+{
+ /* we want to keep the GSM module powered during sleep so ignore
+ * configure requests if the system is going into suspend.
+ */
+ if (suspending) return;
+
+ switch (state) {
+ case PXA_UART_CFG_PRE_STARTUP:
+ printk(KERN_NOTICE "palmt650_gsm_configure: power on\n");
+ SET_ASIC6_GPIO(GSM_POWER, 1);
+ if (!sleep_on_timeout(&host_wake_queue, HZ)) {
+ printk(KERN_ERR "%s: timeout waiting for host wake\n",
+ __FUNCTION__);
+ }
+ break;
+ case PXA_UART_CFG_POST_SHUTDOWN:
+ printk(KERN_NOTICE "palmt650_gsm_configure: power off\n");
+ SET_ASIC6_GPIO(GSM_POWER, 0);
+ break;
+ }
+}
+
+static void palmt650_gsm_set_txrx(int txrx)
+{
+ int old_wake = GET_PALMT650_GPIO(GSM_WAKE) ? 1 : 0;
+ int new_wake = (txrx & PXA_SERIAL_TX) ? 1 : 0;
+ int tmout;
+
+ /* the timer will deassert wake, so we only need to worry about
+ * TX on events.
+ */
+ if (!new_wake)
+ return;
+
+ if (new_wake != old_wake) {
+ SET_PALMT650_GPIO(GSM_WAKE, new_wake);
+
+ /* give the modem time to wakeup. Ideally we'd wait on a
+ * host_wake interrupt but serial_core has interrupts disabled
+ * so we try watching GEDR manually
+ */
+ tmout = 500000;
+ while (--tmout && !(GEDR(GPIO_NR_PALMT650_GSM_HOST_WAKE)
+ & GPIO_bit(GPIO_NR_PALMT650_GSM_HOST_WAKE))) {
+ udelay(1);
+ }
+ if (!tmout) {
+ printk(KERN_ERR "%s: timed out waiting for host wake\n",
+ __FUNCTION__);
+ }
+ }
+
+ /* if there's no transmits for 1 second put the modem back to sleep */
+ mod_timer(&wake_timer, jiffies + HZ);
+}
+
+static int palmt650_gsm_get_txrx(void)
+{
+ return PXA_SERIAL_RX | (GET_PALMT650_GPIO(GSM_WAKE) ? PXA_SERIAL_TX : 0);
+}
+
+static int
+palmt650_gsm_uart_suspend(struct platform_device *dev, pm_message_t state)
+{
+ suspending = 1;
+ /* TODO: ensure RTS is deasserted during sleep to queue messages
+ * and setup waking upon GSM event.
+ */
+ return 0;
+}
+
+static int palmt650_gsm_uart_resume(struct platform_device *dev)
+{
+ suspending = 0;
+ return 0;
+}
+
+static struct platform_pxa_serial_funcs palmt650_gsm_ffuart_funcs = {
+ .configure = palmt650_gsm_configure,
+ .set_txrx = palmt650_gsm_set_txrx,
+ .get_txrx = palmt650_gsm_get_txrx,
+ .suspend = palmt650_gsm_uart_suspend,
+ .resume = palmt650_gsm_uart_resume,
+};
+
+static irqreturn_t palmt650_gsm_host_wake_int(int irq, void *data)
+{
+ wake_up(&host_wake_queue);
+ return IRQ_HANDLED;
+}
+
+void palmt650_gsm_wake_timeout(unsigned long data)
+{
+ SET_PALMT650_GPIO(GSM_WAKE, 0);
+}
+
static int __init palmt650_gsm_probe(struct platform_device *pdev)
{
+ int err;
+
/* configure FFUART gpios */
pxa_gpio_mode(GPIO34_FFRXD_MD);
pxa_gpio_mode(GPIO35_FFCTS_MD);
pxa_gpio_mode(GPIO39_FFTXD_MD);
pxa_gpio_mode(GPIO41_FFRTS_MD);
+ /* extra signals */
+ pxa_gpio_mode(GPIO_NR_PALMT650_GSM_HOST_WAKE_MD);
+ pxa_gpio_mode(GPIO_NR_PALMT650_GSM_WAKE_MD);
+ SET_PALMT650_GPIO(GSM_WAKE, 0);
+ SET_ASIC6_GPIO(GSM_POWER, 0);
+
+ /* setup an interrupt for detecting host wake events */
+ set_irq_type(IRQ_GPIO_PALMT650_GSM_HOST_WAKE, IRQT_RISING);
+ err = request_irq(IRQ_GPIO_PALMT650_GSM_HOST_WAKE, palmt650_gsm_host_wake_int,
+ SA_INTERRUPT, "GSM host wake", pdev);
+ if(err) {
+ printk(KERN_ERR "palmt650_gsm: can't get GSM host wake IRQ\n");
+ return err;
+ }
+
+ /* register our callbacks with the PXA serial driver */
+ pxa_set_ffuart_info(&palmt650_gsm_ffuart_funcs);
+
+ suspending = 0;
+ init_timer(&wake_timer);
+ wake_timer.function = palmt650_gsm_wake_timeout;
+ wake_timer.data = 0;
+ wake_timer_running = 0;
+
return sysfs_create_group(&pdev->dev.kobj, &palmt650_gsm_attr_group);
}
static int palmt650_gsm_remove(struct platform_device *pdev)
{
+ pxa_set_ffuart_info(NULL);
sysfs_remove_group(&pdev->dev.kobj, &palmt650_gsm_attr_group);
return 0;
}
@@ -62,8 +214,6 @@
static struct platform_driver palmt650_gsm_driver = {
.probe = palmt650_gsm_probe,
.remove = palmt650_gsm_remove,
- .suspend = NULL, /* not needed? */
- .resume = NULL,
.driver = {
.name = "palmt650-gsm",
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|