corgi_ssp.c 6.9 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3
/*
 *  SSP control code for Sharp Corgi devices
 *
4
 *  Copyright (c) 2004-2005 Richard Purdie
L
Linus Torvalds 已提交
5 6 7 8 9 10 11 12 13 14 15 16 17
 *
 *  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.
 *
 */

#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/delay.h>
18
#include <linux/platform_device.h>
L
Linus Torvalds 已提交
19
#include <asm/hardware.h>
20
#include <asm/mach-types.h>
L
Linus Torvalds 已提交
21 22 23

#include <asm/arch/ssp.h>
#include <asm/arch/pxa-regs.h>
24
#include "sharpsl.h"
L
Linus Torvalds 已提交
25

26
static DEFINE_SPINLOCK(corgi_ssp_lock);
L
Linus Torvalds 已提交
27 28
static struct ssp_dev corgi_ssp_dev;
static struct ssp_state corgi_ssp_state;
29
static struct corgissp_machinfo *ssp_machinfo;
L
Linus Torvalds 已提交
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52

/*
 * There are three devices connected to the SSP interface:
 *   1. A touchscreen controller (TI ADS7846 compatible)
 *   2. An LCD contoller (with some Backlight functionality)
 *   3. A battery moinitoring IC (Maxim MAX1111)
 *
 * Each device uses a different speed/mode of communication.
 *
 * The touchscreen is very sensitive and the most frequently used
 * so the port is left configured for this.
 *
 * Devices are selected using Chip Selects on GPIOs.
 */

/*
 *  ADS7846 Routines
 */
unsigned long corgi_ssp_ads7846_putget(ulong data)
{
	unsigned long ret,flag;

	spin_lock_irqsave(&corgi_ssp_lock, flag);
53
	GPCR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846);
L
Linus Torvalds 已提交
54 55 56 57

	ssp_write_word(&corgi_ssp_dev,data);
	ret = ssp_read_word(&corgi_ssp_dev);

58
	GPSR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846);
L
Linus Torvalds 已提交
59 60 61 62 63 64 65 66 67 68 69 70
	spin_unlock_irqrestore(&corgi_ssp_lock, flag);

	return ret;
}

/*
 * NOTE: These functions should always be called in interrupt context
 * and use the _lock and _unlock functions. They are very time sensitive.
 */
void corgi_ssp_ads7846_lock(void)
{
	spin_lock(&corgi_ssp_lock);
71
	GPCR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846);
L
Linus Torvalds 已提交
72 73 74 75
}

void corgi_ssp_ads7846_unlock(void)
{
76
	GPSR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846);
L
Linus Torvalds 已提交
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
	spin_unlock(&corgi_ssp_lock);
}

void corgi_ssp_ads7846_put(ulong data)
{
	ssp_write_word(&corgi_ssp_dev,data);
}

unsigned long corgi_ssp_ads7846_get(void)
{
	return ssp_read_word(&corgi_ssp_dev);
}

EXPORT_SYMBOL(corgi_ssp_ads7846_putget);
EXPORT_SYMBOL(corgi_ssp_ads7846_lock);
EXPORT_SYMBOL(corgi_ssp_ads7846_unlock);
EXPORT_SYMBOL(corgi_ssp_ads7846_put);
EXPORT_SYMBOL(corgi_ssp_ads7846_get);


/*
 *  LCD/Backlight Routines
 */
unsigned long corgi_ssp_dac_put(ulong data)
{
102
	unsigned long flag, sscr1 = SSCR1_SPH;
L
Linus Torvalds 已提交
103 104

	spin_lock_irqsave(&corgi_ssp_lock, flag);
105 106 107

	if (machine_is_spitz() || machine_is_akita() || machine_is_borzoi())
		sscr1 = 0;
L
Linus Torvalds 已提交
108 109

	ssp_disable(&corgi_ssp_dev);
110
	ssp_config(&corgi_ssp_dev, (SSCR0_Motorola | (SSCR0_DSS & 0x07 )), sscr1, 0, SSCR0_SerClkDiv(ssp_machinfo->clk_lcdcon));
L
Linus Torvalds 已提交
111 112
	ssp_enable(&corgi_ssp_dev);

113
	GPCR(ssp_machinfo->cs_lcdcon) = GPIO_bit(ssp_machinfo->cs_lcdcon);
L
Linus Torvalds 已提交
114 115 116
	ssp_write_word(&corgi_ssp_dev,data);
	/* Read null data back from device to prevent SSP overflow */
	ssp_read_word(&corgi_ssp_dev);
117
	GPSR(ssp_machinfo->cs_lcdcon) = GPIO_bit(ssp_machinfo->cs_lcdcon);
L
Linus Torvalds 已提交
118 119

	ssp_disable(&corgi_ssp_dev);
120
	ssp_config(&corgi_ssp_dev, (SSCR0_National | (SSCR0_DSS & 0x0b )), 0, 0, SSCR0_SerClkDiv(ssp_machinfo->clk_ads7846));
L
Linus Torvalds 已提交
121
	ssp_enable(&corgi_ssp_dev);
122

L
Linus Torvalds 已提交
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
	spin_unlock_irqrestore(&corgi_ssp_lock, flag);

	return 0;
}

void corgi_ssp_lcdtg_send(u8 adrs, u8 data)
{
	corgi_ssp_dac_put(((adrs & 0x07) << 5) | (data & 0x1f));
}

void corgi_ssp_blduty_set(int duty)
{
	corgi_ssp_lcdtg_send(0x02,duty);
}

EXPORT_SYMBOL(corgi_ssp_lcdtg_send);
EXPORT_SYMBOL(corgi_ssp_blduty_set);

/*
 *  Max1111 Routines
 */
int corgi_ssp_max1111_get(ulong data)
{
	unsigned long flag;
	int voltage,voltage1,voltage2;

	spin_lock_irqsave(&corgi_ssp_lock, flag);
150
	GPCR(ssp_machinfo->cs_max1111) = GPIO_bit(ssp_machinfo->cs_max1111);
L
Linus Torvalds 已提交
151
	ssp_disable(&corgi_ssp_dev);
152
	ssp_config(&corgi_ssp_dev, (SSCR0_Motorola | (SSCR0_DSS & 0x07 )), 0, 0, SSCR0_SerClkDiv(ssp_machinfo->clk_max1111));
L
Linus Torvalds 已提交
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
	ssp_enable(&corgi_ssp_dev);

	udelay(1);

	/* TB1/RB1 */
	ssp_write_word(&corgi_ssp_dev,data);
	ssp_read_word(&corgi_ssp_dev); /* null read */

	/* TB12/RB2 */
	ssp_write_word(&corgi_ssp_dev,0);
	voltage1=ssp_read_word(&corgi_ssp_dev);

	/* TB13/RB3*/
	ssp_write_word(&corgi_ssp_dev,0);
	voltage2=ssp_read_word(&corgi_ssp_dev);

	ssp_disable(&corgi_ssp_dev);
170
	ssp_config(&corgi_ssp_dev, (SSCR0_National | (SSCR0_DSS & 0x0b )), 0, 0, SSCR0_SerClkDiv(ssp_machinfo->clk_ads7846));
L
Linus Torvalds 已提交
171
	ssp_enable(&corgi_ssp_dev);
172
	GPSR(ssp_machinfo->cs_max1111) = GPIO_bit(ssp_machinfo->cs_max1111);
L
Linus Torvalds 已提交
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
	spin_unlock_irqrestore(&corgi_ssp_lock, flag);

	if (voltage1 & 0xc0 || voltage2 & 0x3f)
		voltage = -1;
	else
		voltage = ((voltage1 << 2) & 0xfc) | ((voltage2 >> 6) & 0x03);

	return voltage;
}

EXPORT_SYMBOL(corgi_ssp_max1111_get);

/*
 *  Support Routines
 */
188 189 190 191 192 193

void __init corgi_ssp_set_machinfo(struct corgissp_machinfo *machinfo)
{
	ssp_machinfo = machinfo;
}

194
static int __init corgi_ssp_probe(struct platform_device *dev)
L
Linus Torvalds 已提交
195 196 197 198
{
	int ret;

	/* Chip Select - Disable All */
199 200 201 202 203 204
	GPDR(ssp_machinfo->cs_lcdcon) |= GPIO_bit(ssp_machinfo->cs_lcdcon); /* output */
	GPSR(ssp_machinfo->cs_lcdcon) = GPIO_bit(ssp_machinfo->cs_lcdcon);  /* High - Disable LCD Control/Timing Gen */
	GPDR(ssp_machinfo->cs_max1111) |= GPIO_bit(ssp_machinfo->cs_max1111); /* output */
	GPSR(ssp_machinfo->cs_max1111) = GPIO_bit(ssp_machinfo->cs_max1111);  /* High - Disable MAX1111*/
	GPDR(ssp_machinfo->cs_ads7846) |= GPIO_bit(ssp_machinfo->cs_ads7846);  /* output */
	GPSR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846);   /* High - Disable ADS7846*/
L
Linus Torvalds 已提交
205

206
	ret = ssp_init(&corgi_ssp_dev,ssp_machinfo->port);
L
Linus Torvalds 已提交
207 208 209 210 211

	if (ret)
		printk(KERN_ERR "Unable to register SSP handler!\n");
	else {
		ssp_disable(&corgi_ssp_dev);
212
		ssp_config(&corgi_ssp_dev, (SSCR0_National | (SSCR0_DSS & 0x0b )), 0, 0, SSCR0_SerClkDiv(ssp_machinfo->clk_ads7846));
L
Linus Torvalds 已提交
213 214 215 216 217 218
		ssp_enable(&corgi_ssp_dev);
	}

	return ret;
}

219
static int corgi_ssp_remove(struct platform_device *dev)
L
Linus Torvalds 已提交
220 221 222 223 224
{
	ssp_exit(&corgi_ssp_dev);
	return 0;
}

225
static int corgi_ssp_suspend(struct platform_device *dev, pm_message_t state)
L
Linus Torvalds 已提交
226
{
227 228 229
	ssp_flush(&corgi_ssp_dev);
	ssp_save_state(&corgi_ssp_dev,&corgi_ssp_state);

L
Linus Torvalds 已提交
230 231 232
	return 0;
}

233
static int corgi_ssp_resume(struct platform_device *dev)
L
Linus Torvalds 已提交
234
{
235 236 237 238 239 240
	GPSR(ssp_machinfo->cs_lcdcon) = GPIO_bit(ssp_machinfo->cs_lcdcon);  /* High - Disable LCD Control/Timing Gen */
	GPSR(ssp_machinfo->cs_max1111) = GPIO_bit(ssp_machinfo->cs_max1111); /* High - Disable MAX1111*/
	GPSR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846); /* High - Disable ADS7846*/
	ssp_restore_state(&corgi_ssp_dev,&corgi_ssp_state);
	ssp_enable(&corgi_ssp_dev);

L
Linus Torvalds 已提交
241 242 243
	return 0;
}

244
static struct platform_driver corgissp_driver = {
L
Linus Torvalds 已提交
245 246 247 248
	.probe		= corgi_ssp_probe,
	.remove		= corgi_ssp_remove,
	.suspend	= corgi_ssp_suspend,
	.resume		= corgi_ssp_resume,
249 250 251
	.driver		= {
		.name	= "corgi-ssp",
	},
L
Linus Torvalds 已提交
252 253 254 255
};

int __init corgi_ssp_init(void)
{
256
	return platform_driver_register(&corgissp_driver);
L
Linus Torvalds 已提交
257 258 259
}

arch_initcall(corgi_ssp_init);