Blame view

drivers/mfd/sm501.c 41 KB
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
  /* linux/drivers/mfd/sm501.c
   *
   * Copyright (C) 2006 Simtec Electronics
   *	Ben Dooks <ben@simtec.co.uk>
   *	Vincent Sanders <vince@simtec.co.uk>
   *
   * 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.
   *
   * SM501 MFD driver
  */
  
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/delay.h>
  #include <linux/init.h>
  #include <linux/list.h>
  #include <linux/device.h>
  #include <linux/platform_device.h>
  #include <linux/pci.h>
42cd2366f   Ben Dooks   sm501: gpio I2C s...
22
  #include <linux/i2c-gpio.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
23
  #include <linux/slab.h>
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
24
25
26
  
  #include <linux/sm501.h>
  #include <linux/sm501-regs.h>
61711f8fd   Magnus Damm   sm501: add uart s...
27
  #include <linux/serial_8250.h>
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
28

f77401d4d   Axel Lin   mfd: Include <lin...
29
  #include <linux/io.h>
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
30
31
32
33
34
  
  struct sm501_device {
  	struct list_head		list;
  	struct platform_device		pdev;
  };
f61be273d   Ben Dooks   sm501: add gpioli...
35
  struct sm501_gpio;
f2999209d   Ben Dooks   mfd: sm501 build ...
36
37
  #ifdef CONFIG_MFD_SM501_GPIO
  #include <linux/gpio.h>
f61be273d   Ben Dooks   sm501: add gpioli...
38
39
40
41
  struct sm501_gpio_chip {
  	struct gpio_chip	gpio;
  	struct sm501_gpio	*ourgpio;	/* to get back to parent. */
  	void __iomem		*regbase;
98325f8f8   Ben Dooks   mfd: Ensure sm501...
42
  	void __iomem		*control;	/* address of control reg. */
f61be273d   Ben Dooks   sm501: add gpioli...
43
44
45
46
47
48
49
50
51
52
53
  };
  
  struct sm501_gpio {
  	struct sm501_gpio_chip	low;
  	struct sm501_gpio_chip	high;
  	spinlock_t		lock;
  
  	unsigned int		 registered : 1;
  	void __iomem		*regs;
  	struct resource		*regs_res;
  };
f2999209d   Ben Dooks   mfd: sm501 build ...
54
55
56
57
58
  #else
  struct sm501_gpio {
  	/* no gpio support, empty definition for sm501_devdata. */
  };
  #endif
f61be273d   Ben Dooks   sm501: add gpioli...
59

b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
60
61
62
63
  struct sm501_devdata {
  	spinlock_t			 reg_lock;
  	struct mutex			 clock_lock;
  	struct list_head		 devices;
f61be273d   Ben Dooks   sm501: add gpioli...
64
  	struct sm501_gpio		 gpio;
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
65
66
67
68
69
70
  
  	struct device			*dev;
  	struct resource			*io_res;
  	struct resource			*mem_res;
  	struct resource			*regs_claim;
  	struct sm501_platdata		*platdata;
f61be273d   Ben Dooks   sm501: add gpioli...
71

331d74750   Ben Dooks   SM501: suspend su...
72
73
  	unsigned int			 in_suspend;
  	unsigned long			 pm_misc;
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
74
75
76
77
  	int				 unit_power[20];
  	unsigned int			 pdev_id;
  	unsigned int			 irq;
  	void __iomem			*regs;
3149be50d   Ville Syrjala   sm501: add suppor...
78
  	unsigned int			 rev;
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
79
  };
f61be273d   Ben Dooks   sm501: add gpioli...
80

b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
81
82
83
  #define MHZ (1000 * 1000)
  
  #ifdef DEBUG
245904a4c   Ville Syrjala   sm501: remove a d...
84
  static const unsigned int div_tab[] = {
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
  	[0]		= 1,
  	[1]		= 2,
  	[2]		= 4,
  	[3]		= 8,
  	[4]		= 16,
  	[5]		= 32,
  	[6]		= 64,
  	[7]		= 128,
  	[8]		= 3,
  	[9]		= 6,
  	[10]	        = 12,
  	[11]		= 24,
  	[12]		= 48,
  	[13]		= 96,
  	[14]		= 192,
  	[15]		= 384,
  	[16]		= 5,
  	[17]		= 10,
  	[18]		= 20,
  	[19]		= 40,
  	[20]		= 80,
  	[21]		= 160,
  	[22]		= 320,
  	[23]		= 604,
  };
  
  static unsigned long decode_div(unsigned long pll2, unsigned long val,
  				unsigned int lshft, unsigned int selbit,
245904a4c   Ville Syrjala   sm501: remove a d...
113
  				unsigned long mask)
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
114
115
116
  {
  	if (val & selbit)
  		pll2 = 288 * MHZ;
245904a4c   Ville Syrjala   sm501: remove a d...
117
  	return pll2 / div_tab[(val >> lshft) & mask];
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
118
119
120
121
122
123
124
125
126
127
128
  }
  
  #define fmt_freq(x) ((x) / MHZ), ((x) % MHZ), (x)
  
  /* sm501_dump_clk
   *
   * Print out the current clock configuration for the device
  */
  
  static void sm501_dump_clk(struct sm501_devdata *sm)
  {
bf5f00190   Heiko Schocher   video, sm501: add...
129
130
131
132
  	unsigned long misct = smc501_readl(sm->regs + SM501_MISC_TIMING);
  	unsigned long pm0 = smc501_readl(sm->regs + SM501_POWER_MODE_0_CLOCK);
  	unsigned long pm1 = smc501_readl(sm->regs + SM501_POWER_MODE_1_CLOCK);
  	unsigned long pmc = smc501_readl(sm->regs + SM501_POWER_MODE_CONTROL);
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
  	unsigned long sdclk0, sdclk1;
  	unsigned long pll2 = 0;
  
  	switch (misct & 0x30) {
  	case 0x00:
  		pll2 = 336 * MHZ;
  		break;
  	case 0x10:
  		pll2 = 288 * MHZ;
  		break;
  	case 0x20:
  		pll2 = 240 * MHZ;
  		break;
  	case 0x30:
  		pll2 = 192 * MHZ;
  		break;
  	}
  
  	sdclk0 = (misct & (1<<12)) ? pll2 : 288 * MHZ;
245904a4c   Ville Syrjala   sm501: remove a d...
152
  	sdclk0 /= div_tab[((misct >> 8) & 0xf)];
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
153
154
  
  	sdclk1 = (misct & (1<<20)) ? pll2 : 288 * MHZ;
245904a4c   Ville Syrjala   sm501: remove a d...
155
  	sdclk1 /= div_tab[((misct >> 16) & 0xf)];
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
156
157
158
159
160
161
162
163
164
165
166
167
168
169
  
  	dev_dbg(sm->dev, "MISCT=%08lx, PM0=%08lx, PM1=%08lx
  ",
  		misct, pm0, pm1);
  
  	dev_dbg(sm->dev, "PLL2 = %ld.%ld MHz (%ld), SDCLK0=%08lx, SDCLK1=%08lx
  ",
  		fmt_freq(pll2), sdclk0, sdclk1);
  
  	dev_dbg(sm->dev, "SDRAM: PM0=%ld, PM1=%ld
  ", sdclk0, sdclk1);
  
  	dev_dbg(sm->dev, "PM0[%c]: "
  		 "P2 %ld.%ld MHz (%ld), V2 %ld.%ld (%ld), "
48986f06b   Ben Dooks   MFD: SM501 debug ...
170
171
  		 "M %ld.%ld (%ld), MX1 %ld.%ld (%ld)
  ",
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
172
  		 (pmc & 3 ) == 0 ? '*' : '-',
245904a4c   Ville Syrjala   sm501: remove a d...
173
174
175
176
  		 fmt_freq(decode_div(pll2, pm0, 24, 1<<29, 31)),
  		 fmt_freq(decode_div(pll2, pm0, 16, 1<<20, 15)),
  		 fmt_freq(decode_div(pll2, pm0, 8,  1<<12, 15)),
  		 fmt_freq(decode_div(pll2, pm0, 0,  1<<4,  15)));
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
177
178
179
180
181
182
  
  	dev_dbg(sm->dev, "PM1[%c]: "
  		"P2 %ld.%ld MHz (%ld), V2 %ld.%ld (%ld), "
  		"M %ld.%ld (%ld), MX1 %ld.%ld (%ld)
  ",
  		(pmc & 3 ) == 1 ? '*' : '-',
245904a4c   Ville Syrjala   sm501: remove a d...
183
184
185
186
  		fmt_freq(decode_div(pll2, pm1, 24, 1<<29, 31)),
  		fmt_freq(decode_div(pll2, pm1, 16, 1<<20, 15)),
  		fmt_freq(decode_div(pll2, pm1, 8,  1<<12, 15)),
  		fmt_freq(decode_div(pll2, pm1, 0,  1<<4,  15)));
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
187
  }
331d74750   Ben Dooks   SM501: suspend su...
188
189
190
191
192
193
194
  
  static void sm501_dump_regs(struct sm501_devdata *sm)
  {
  	void __iomem *regs = sm->regs;
  
  	dev_info(sm->dev, "System Control   %08x
  ",
bf5f00190   Heiko Schocher   video, sm501: add...
195
  			smc501_readl(regs + SM501_SYSTEM_CONTROL));
331d74750   Ben Dooks   SM501: suspend su...
196
197
  	dev_info(sm->dev, "Misc Control     %08x
  ",
bf5f00190   Heiko Schocher   video, sm501: add...
198
  			smc501_readl(regs + SM501_MISC_CONTROL));
331d74750   Ben Dooks   SM501: suspend su...
199
200
  	dev_info(sm->dev, "GPIO Control Low %08x
  ",
bf5f00190   Heiko Schocher   video, sm501: add...
201
  			smc501_readl(regs + SM501_GPIO31_0_CONTROL));
331d74750   Ben Dooks   SM501: suspend su...
202
203
  	dev_info(sm->dev, "GPIO Control Hi  %08x
  ",
bf5f00190   Heiko Schocher   video, sm501: add...
204
  			smc501_readl(regs + SM501_GPIO63_32_CONTROL));
331d74750   Ben Dooks   SM501: suspend su...
205
206
  	dev_info(sm->dev, "DRAM Control     %08x
  ",
bf5f00190   Heiko Schocher   video, sm501: add...
207
  			smc501_readl(regs + SM501_DRAM_CONTROL));
331d74750   Ben Dooks   SM501: suspend su...
208
209
  	dev_info(sm->dev, "Arbitration Ctrl %08x
  ",
bf5f00190   Heiko Schocher   video, sm501: add...
210
  			smc501_readl(regs + SM501_ARBTRTN_CONTROL));
331d74750   Ben Dooks   SM501: suspend su...
211
212
  	dev_info(sm->dev, "Misc Timing      %08x
  ",
bf5f00190   Heiko Schocher   video, sm501: add...
213
  			smc501_readl(regs + SM501_MISC_TIMING));
331d74750   Ben Dooks   SM501: suspend su...
214
215
216
  }
  
  static void sm501_dump_gate(struct sm501_devdata *sm)
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
217
  {
331d74750   Ben Dooks   SM501: suspend su...
218
219
  	dev_info(sm->dev, "CurrentGate      %08x
  ",
bf5f00190   Heiko Schocher   video, sm501: add...
220
  			smc501_readl(sm->regs + SM501_CURRENT_GATE));
331d74750   Ben Dooks   SM501: suspend su...
221
222
  	dev_info(sm->dev, "CurrentClock     %08x
  ",
bf5f00190   Heiko Schocher   video, sm501: add...
223
  			smc501_readl(sm->regs + SM501_CURRENT_CLOCK));
331d74750   Ben Dooks   SM501: suspend su...
224
225
  	dev_info(sm->dev, "PowerModeControl %08x
  ",
bf5f00190   Heiko Schocher   video, sm501: add...
226
  			smc501_readl(sm->regs + SM501_POWER_MODE_CONTROL));
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
227
  }
331d74750   Ben Dooks   SM501: suspend su...
228
229
230
231
232
  
  #else
  static inline void sm501_dump_gate(struct sm501_devdata *sm) { }
  static inline void sm501_dump_regs(struct sm501_devdata *sm) { }
  static inline void sm501_dump_clk(struct sm501_devdata *sm) { }
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
233
234
235
236
237
238
239
240
241
  #endif
  
  /* sm501_sync_regs
   *
   * ensure the
  */
  
  static void sm501_sync_regs(struct sm501_devdata *sm)
  {
bf5f00190   Heiko Schocher   video, sm501: add...
242
  	smc501_readl(sm->regs);
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
243
  }
331d74750   Ben Dooks   SM501: suspend su...
244
245
246
247
248
249
250
251
252
253
254
  static inline void sm501_mdelay(struct sm501_devdata *sm, unsigned int delay)
  {
  	/* during suspend/resume, we are currently not allowed to sleep,
  	 * so change to using mdelay() instead of msleep() if we
  	 * are in one of these paths */
  
  	if (sm->in_suspend)
  		mdelay(delay);
  	else
  		msleep(delay);
  }
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
255
256
  /* sm501_misc_control
   *
331d74750   Ben Dooks   SM501: suspend su...
257
   * alters the miscellaneous control parameters
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
258
259
260
261
262
263
264
265
266
267
268
  */
  
  int sm501_misc_control(struct device *dev,
  		       unsigned long set, unsigned long clear)
  {
  	struct sm501_devdata *sm = dev_get_drvdata(dev);
  	unsigned long misc;
  	unsigned long save;
  	unsigned long to;
  
  	spin_lock_irqsave(&sm->reg_lock, save);
bf5f00190   Heiko Schocher   video, sm501: add...
269
  	misc = smc501_readl(sm->regs + SM501_MISC_CONTROL);
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
270
271
272
  	to = (misc & ~clear) | set;
  
  	if (to != misc) {
bf5f00190   Heiko Schocher   video, sm501: add...
273
  		smc501_writel(to, sm->regs + SM501_MISC_CONTROL);
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
  		sm501_sync_regs(sm);
  
  		dev_dbg(sm->dev, "MISC_CONTROL %08lx
  ", misc);
  	}
  
  	spin_unlock_irqrestore(&sm->reg_lock, save);
  	return to;
  }
  
  EXPORT_SYMBOL_GPL(sm501_misc_control);
  
  /* sm501_modify_reg
   *
   * Modify a register in the SM501 which may be shared with other
   * drivers.
  */
  
  unsigned long sm501_modify_reg(struct device *dev,
  			       unsigned long reg,
  			       unsigned long set,
  			       unsigned long clear)
  {
  	struct sm501_devdata *sm = dev_get_drvdata(dev);
  	unsigned long data;
  	unsigned long save;
  
  	spin_lock_irqsave(&sm->reg_lock, save);
bf5f00190   Heiko Schocher   video, sm501: add...
302
  	data = smc501_readl(sm->regs + reg);
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
303
304
  	data |= set;
  	data &= ~clear;
bf5f00190   Heiko Schocher   video, sm501: add...
305
  	smc501_writel(data, sm->regs + reg);
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
306
307
308
309
310
311
312
313
  	sm501_sync_regs(sm);
  
  	spin_unlock_irqrestore(&sm->reg_lock, save);
  
  	return data;
  }
  
  EXPORT_SYMBOL_GPL(sm501_modify_reg);
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
314
315
316
317
318
319
320
321
322
323
324
325
326
  /* sm501_unit_power
   *
   * alters the power active gate to set specific units on or off
   */
  
  int sm501_unit_power(struct device *dev, unsigned int unit, unsigned int to)
  {
  	struct sm501_devdata *sm = dev_get_drvdata(dev);
  	unsigned long mode;
  	unsigned long gate;
  	unsigned long clock;
  
  	mutex_lock(&sm->clock_lock);
bf5f00190   Heiko Schocher   video, sm501: add...
327
328
329
  	mode = smc501_readl(sm->regs + SM501_POWER_MODE_CONTROL);
  	gate = smc501_readl(sm->regs + SM501_CURRENT_GATE);
  	clock = smc501_readl(sm->regs + SM501_CURRENT_CLOCK);
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
330
331
  
  	mode &= 3;		/* get current power mode */
bf703c3f1   Adrian Bunk   [PATCH] drivers/m...
332
  	if (unit >= ARRAY_SIZE(sm->unit_power)) {
145980a0b   Harvey Harrison   drivers: replace ...
333
334
  		dev_err(dev, "%s: bad unit %d
  ", __func__, unit);
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
335
336
  		goto already;
  	}
145980a0b   Harvey Harrison   drivers: replace ...
337
338
  	dev_dbg(sm->dev, "%s: unit %d, cur %d, to %d
  ", __func__, unit,
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
  		sm->unit_power[unit], to);
  
  	if (to == 0 && sm->unit_power[unit] == 0) {
  		dev_err(sm->dev, "unit %d is already shutdown
  ", unit);
  		goto already;
  	}
  
  	sm->unit_power[unit] += to ? 1 : -1;
  	to = sm->unit_power[unit] ? 1 : 0;
  
  	if (to) {
  		if (gate & (1 << unit))
  			goto already;
  		gate |= (1 << unit);
  	} else {
  		if (!(gate & (1 << unit)))
  			goto already;
  		gate &= ~(1 << unit);
  	}
  
  	switch (mode) {
  	case 1:
bf5f00190   Heiko Schocher   video, sm501: add...
362
363
  		smc501_writel(gate, sm->regs + SM501_POWER_MODE_0_GATE);
  		smc501_writel(clock, sm->regs + SM501_POWER_MODE_0_CLOCK);
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
364
365
366
367
  		mode = 0;
  		break;
  	case 2:
  	case 0:
bf5f00190   Heiko Schocher   video, sm501: add...
368
369
  		smc501_writel(gate, sm->regs + SM501_POWER_MODE_1_GATE);
  		smc501_writel(clock, sm->regs + SM501_POWER_MODE_1_CLOCK);
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
370
371
372
373
  		mode = 1;
  		break;
  
  	default:
992bb253c   Jiri Slaby   mfd: sm501, fix l...
374
375
  		gate = -1;
  		goto already;
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
376
  	}
bf5f00190   Heiko Schocher   video, sm501: add...
377
  	smc501_writel(mode, sm->regs + SM501_POWER_MODE_CONTROL);
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
378
379
380
381
382
  	sm501_sync_regs(sm);
  
  	dev_dbg(sm->dev, "gate %08lx, clock %08lx, mode %08lx
  ",
  		gate, clock, mode);
331d74750   Ben Dooks   SM501: suspend su...
383
  	sm501_mdelay(sm, 16);
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
  
   already:
  	mutex_unlock(&sm->clock_lock);
  	return gate;
  }
  
  EXPORT_SYMBOL_GPL(sm501_unit_power);
  
  
  /* Perform a rounded division. */
  static long sm501fb_round_div(long num, long denom)
  {
          /* n / d + 1 / 2 = (2n + d) / 2d */
          return (2 * num + denom) / (2 * denom);
  }
  
  /* clock value structure. */
  struct sm501_clock {
  	unsigned long mclk;
  	int divider;
  	int shift;
3149be50d   Ville Syrjala   sm501: add suppor...
405
  	unsigned int m, n, k;
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
406
  };
3149be50d   Ville Syrjala   sm501: add suppor...
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
  /* sm501_calc_clock
   *
   * Calculates the nearest discrete clock frequency that
   * can be achieved with the specified input clock.
   *   the maximum divisor is 3 or 5
   */
  
  static int sm501_calc_clock(unsigned long freq,
  			    struct sm501_clock *clock,
  			    int max_div,
  			    unsigned long mclk,
  			    long *best_diff)
  {
  	int ret = 0;
  	int divider;
  	int shift;
  	long diff;
  
  	/* try dividers 1 and 3 for CRT and for panel,
  	   try divider 5 for panel only.*/
  
  	for (divider = 1; divider <= max_div; divider += 2) {
  		/* try all 8 shift values.*/
  		for (shift = 0; shift < 8; shift++) {
  			/* Calculate difference to requested clock */
  			diff = sm501fb_round_div(mclk, divider << shift) - freq;
  			if (diff < 0)
  				diff = -diff;
  
  			/* If it is less than the current, use it */
  			if (diff < *best_diff) {
  				*best_diff = diff;
  
  				clock->mclk = mclk;
  				clock->divider = divider;
  				clock->shift = shift;
  				ret = 1;
  			}
  		}
  	}
  
  	return ret;
  }
  
  /* sm501_calc_pll
   *
   * Calculates the nearest discrete clock frequency that can be
   * achieved using the programmable PLL.
   *   the maximum divisor is 3 or 5
   */
  
  static unsigned long sm501_calc_pll(unsigned long freq,
  					struct sm501_clock *clock,
  					int max_div)
  {
  	unsigned long mclk;
  	unsigned int m, n, k;
  	long best_diff = 999999999;
  
  	/*
  	 * The SM502 datasheet doesn't specify the min/max values for M and N.
  	 * N = 1 at least doesn't work in practice.
  	 */
  	for (m = 2; m <= 255; m++) {
  		for (n = 2; n <= 127; n++) {
  			for (k = 0; k <= 1; k++) {
  				mclk = (24000000UL * m / n) >> k;
  
  				if (sm501_calc_clock(freq, clock, max_div,
  						     mclk, &best_diff)) {
  					clock->m = m;
  					clock->n = n;
  					clock->k = k;
  				}
  			}
  		}
  	}
  
  	/* Return best clock. */
  	return clock->mclk / (clock->divider << clock->shift);
  }
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
488
489
  /* sm501_select_clock
   *
3149be50d   Ville Syrjala   sm501: add suppor...
490
491
   * Calculates the nearest discrete clock frequency that can be
   * achieved using the 288MHz and 336MHz PLLs.
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
492
493
   *   the maximum divisor is 3 or 5
   */
3149be50d   Ville Syrjala   sm501: add suppor...
494

b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
495
496
497
498
499
  static unsigned long sm501_select_clock(unsigned long freq,
  					struct sm501_clock *clock,
  					int max_div)
  {
  	unsigned long mclk;
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
500
501
502
503
  	long best_diff = 999999999;
  
  	/* Try 288MHz and 336MHz clocks. */
  	for (mclk = 288000000; mclk <= 336000000; mclk += 48000000) {
3149be50d   Ville Syrjala   sm501: add suppor...
504
  		sm501_calc_clock(freq, clock, max_div, mclk, &best_diff);
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
  	}
  
  	/* Return best clock. */
  	return clock->mclk / (clock->divider << clock->shift);
  }
  
  /* sm501_set_clock
   *
   * set one of the four clock sources to the closest available frequency to
   *  the one specified
  */
  
  unsigned long sm501_set_clock(struct device *dev,
  			      int clksrc,
  			      unsigned long req_freq)
  {
  	struct sm501_devdata *sm = dev_get_drvdata(dev);
bf5f00190   Heiko Schocher   video, sm501: add...
522
523
524
  	unsigned long mode = smc501_readl(sm->regs + SM501_POWER_MODE_CONTROL);
  	unsigned long gate = smc501_readl(sm->regs + SM501_CURRENT_GATE);
  	unsigned long clock = smc501_readl(sm->regs + SM501_CURRENT_CLOCK);
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
525
  	unsigned char reg;
3149be50d   Ville Syrjala   sm501: add suppor...
526
  	unsigned int pll_reg = 0;
3ad2f3fbb   Daniel Mack   tree-wide: Assort...
527
  	unsigned long sm501_freq; /* the actual frequency achieved */
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
528
529
530
531
532
533
534
535
536
  
  	struct sm501_clock to;
  
  	/* find achivable discrete frequency and setup register value
  	 * accordingly, V2XCLK, MCLK and M1XCLK are the same P2XCLK
  	 * has an extra bit for the divider */
  
  	switch (clksrc) {
  	case SM501_CLOCK_P2XCLK:
3ad2f3fbb   Daniel Mack   tree-wide: Assort...
537
  		/* This clock is divided in half so to achieve the
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
538
539
  		 * requested frequency the value must be multiplied by
  		 * 2. This clock also has an additional pre divisor */
3149be50d   Ville Syrjala   sm501: add suppor...
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
  		if (sm->rev >= 0xC0) {
  			/* SM502 -> use the programmable PLL */
  			sm501_freq = (sm501_calc_pll(2 * req_freq,
  						     &to, 5) / 2);
  			reg = to.shift & 0x07;/* bottom 3 bits are shift */
  			if (to.divider == 3)
  				reg |= 0x08; /* /3 divider required */
  			else if (to.divider == 5)
  				reg |= 0x10; /* /5 divider required */
  			reg |= 0x40; /* select the programmable PLL */
  			pll_reg = 0x20000 | (to.k << 15) | (to.n << 8) | to.m;
  		} else {
  			sm501_freq = (sm501_select_clock(2 * req_freq,
  							 &to, 5) / 2);
  			reg = to.shift & 0x07;/* bottom 3 bits are shift */
  			if (to.divider == 3)
  				reg |= 0x08; /* /3 divider required */
  			else if (to.divider == 5)
  				reg |= 0x10; /* /5 divider required */
  			if (to.mclk != 288000000)
  				reg |= 0x20; /* which mclk pll is source */
  		}
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
562
563
564
  		break;
  
  	case SM501_CLOCK_V2XCLK:
3ad2f3fbb   Daniel Mack   tree-wide: Assort...
565
  		/* This clock is divided in half so to achieve the
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
  		 * requested frequency the value must be multiplied by 2. */
  
  		sm501_freq = (sm501_select_clock(2 * req_freq, &to, 3) / 2);
  		reg=to.shift & 0x07;	/* bottom 3 bits are shift */
  		if (to.divider == 3)
  			reg |= 0x08;	/* /3 divider required */
  		if (to.mclk != 288000000)
  			reg |= 0x10;	/* which mclk pll is source */
  		break;
  
  	case SM501_CLOCK_MCLK:
  	case SM501_CLOCK_M1XCLK:
  		/* These clocks are the same and not further divided */
  
  		sm501_freq = sm501_select_clock( req_freq, &to, 3);
  		reg=to.shift & 0x07;	/* bottom 3 bits are shift */
  		if (to.divider == 3)
  			reg |= 0x08;	/* /3 divider required */
  		if (to.mclk != 288000000)
  			reg |= 0x10;	/* which mclk pll is source */
  		break;
  
  	default:
  		return 0; /* this is bad */
  	}
  
  	mutex_lock(&sm->clock_lock);
bf5f00190   Heiko Schocher   video, sm501: add...
593
594
595
  	mode = smc501_readl(sm->regs + SM501_POWER_MODE_CONTROL);
  	gate = smc501_readl(sm->regs + SM501_CURRENT_GATE);
  	clock = smc501_readl(sm->regs + SM501_CURRENT_CLOCK);
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
596
597
598
599
600
601
602
603
  
  	clock = clock & ~(0xFF << clksrc);
  	clock |= reg<<clksrc;
  
  	mode &= 3;	/* find current mode */
  
  	switch (mode) {
  	case 1:
bf5f00190   Heiko Schocher   video, sm501: add...
604
605
  		smc501_writel(gate, sm->regs + SM501_POWER_MODE_0_GATE);
  		smc501_writel(clock, sm->regs + SM501_POWER_MODE_0_CLOCK);
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
606
607
608
609
  		mode = 0;
  		break;
  	case 2:
  	case 0:
bf5f00190   Heiko Schocher   video, sm501: add...
610
611
  		smc501_writel(gate, sm->regs + SM501_POWER_MODE_1_GATE);
  		smc501_writel(clock, sm->regs + SM501_POWER_MODE_1_CLOCK);
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
612
613
614
615
616
617
618
  		mode = 1;
  		break;
  
  	default:
  		mutex_unlock(&sm->clock_lock);
  		return -1;
  	}
bf5f00190   Heiko Schocher   video, sm501: add...
619
  	smc501_writel(mode, sm->regs + SM501_POWER_MODE_CONTROL);
3149be50d   Ville Syrjala   sm501: add suppor...
620
621
  
  	if (pll_reg)
bf5f00190   Heiko Schocher   video, sm501: add...
622
623
  		smc501_writel(pll_reg,
  				sm->regs + SM501_PROGRAMMABLE_PLL_CONTROL);
3149be50d   Ville Syrjala   sm501: add suppor...
624

b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
625
  	sm501_sync_regs(sm);
80e74a805   Ben Dooks   mfd: update sm501...
626
627
628
  	dev_dbg(sm->dev, "gate %08lx, clock %08lx, mode %08lx
  ",
  		gate, clock, mode);
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
629

331d74750   Ben Dooks   SM501: suspend su...
630
  	sm501_mdelay(sm, 16);
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
631
632
633
634
635
636
637
638
639
640
641
642
643
  	mutex_unlock(&sm->clock_lock);
  
  	sm501_dump_clk(sm);
  
  	return sm501_freq;
  }
  
  EXPORT_SYMBOL_GPL(sm501_set_clock);
  
  /* sm501_find_clock
   *
   * finds the closest available frequency for a given clock
  */
3149be50d   Ville Syrjala   sm501: add suppor...
644
645
  unsigned long sm501_find_clock(struct device *dev,
  			       int clksrc,
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
646
647
  			       unsigned long req_freq)
  {
3149be50d   Ville Syrjala   sm501: add suppor...
648
  	struct sm501_devdata *sm = dev_get_drvdata(dev);
3ad2f3fbb   Daniel Mack   tree-wide: Assort...
649
  	unsigned long sm501_freq; /* the frequency achieveable by the 501 */
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
650
651
652
653
  	struct sm501_clock to;
  
  	switch (clksrc) {
  	case SM501_CLOCK_P2XCLK:
3149be50d   Ville Syrjala   sm501: add suppor...
654
655
656
657
658
659
660
661
  		if (sm->rev >= 0xC0) {
  			/* SM502 -> use the programmable PLL */
  			sm501_freq = (sm501_calc_pll(2 * req_freq,
  						     &to, 5) / 2);
  		} else {
  			sm501_freq = (sm501_select_clock(2 * req_freq,
  							 &to, 5) / 2);
  		}
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
  		break;
  
  	case SM501_CLOCK_V2XCLK:
  		sm501_freq = (sm501_select_clock(2 * req_freq, &to, 3) / 2);
  		break;
  
  	case SM501_CLOCK_MCLK:
  	case SM501_CLOCK_M1XCLK:
  		sm501_freq = sm501_select_clock(req_freq, &to, 3);
  		break;
  
  	default:
  		sm501_freq = 0;		/* error */
  	}
  
  	return sm501_freq;
  }
  
  EXPORT_SYMBOL_GPL(sm501_find_clock);
  
  static struct sm501_device *to_sm_device(struct platform_device *pdev)
  {
  	return container_of(pdev, struct sm501_device, pdev);
  }
  
  /* sm501_device_release
   *
   * A release function for the platform devices we create to allow us to
   * free any items we allocated
  */
  
  static void sm501_device_release(struct device *dev)
  {
  	kfree(to_sm_device(to_platform_device(dev)));
  }
  
  /* sm501_create_subdev
   *
   * Create a skeleton platform device with resources for passing to a
   * sub-driver
  */
  
  static struct platform_device *
61711f8fd   Magnus Damm   sm501: add uart s...
705
706
  sm501_create_subdev(struct sm501_devdata *sm, char *name,
  		    unsigned int res_count, unsigned int platform_data_size)
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
707
708
709
710
  {
  	struct sm501_device *smdev;
  
  	smdev = kzalloc(sizeof(struct sm501_device) +
61711f8fd   Magnus Damm   sm501: add uart s...
711
712
  			(sizeof(struct resource) * res_count) +
  			platform_data_size, GFP_KERNEL);
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
713
714
715
716
717
718
719
  	if (!smdev)
  		return NULL;
  
  	smdev->pdev.dev.release = sm501_device_release;
  
  	smdev->pdev.name = name;
  	smdev->pdev.id = sm->pdev_id;
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
720
  	smdev->pdev.dev.parent = sm->dev;
61711f8fd   Magnus Damm   sm501: add uart s...
721
722
723
724
725
726
  	if (res_count) {
  		smdev->pdev.resource = (struct resource *)(smdev+1);
  		smdev->pdev.num_resources = res_count;
  	}
  	if (platform_data_size)
  		smdev->pdev.dev.platform_data = (void *)(smdev+1);
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
  	return &smdev->pdev;
  }
  
  /* sm501_register_device
   *
   * Register a platform device created with sm501_create_subdev()
  */
  
  static int sm501_register_device(struct sm501_devdata *sm,
  				 struct platform_device *pdev)
  {
  	struct sm501_device *smdev = to_sm_device(pdev);
  	int ptr;
  	int ret;
  
  	for (ptr = 0; ptr < pdev->num_resources; ptr++) {
3f3d4310b   Joe Perches   mfd: Use printf e...
743
744
745
  		printk(KERN_DEBUG "%s[%d] %pR
  ",
  		       pdev->name, ptr, &pdev->resource[ptr]);
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
  	}
  
  	ret = platform_device_register(pdev);
  
  	if (ret >= 0) {
  		dev_dbg(sm->dev, "registered %s
  ", pdev->name);
  		list_add_tail(&smdev->list, &sm->devices);
  	} else
  		dev_err(sm->dev, "error registering %s (%d)
  ",
  			pdev->name, ret);
  
  	return ret;
  }
  
  /* sm501_create_subio
   *
   * Fill in an IO resource for a sub device
  */
  
  static void sm501_create_subio(struct sm501_devdata *sm,
  			       struct resource *res,
  			       resource_size_t offs,
  			       resource_size_t size)
  {
  	res->flags = IORESOURCE_MEM;
  	res->parent = sm->io_res;
  	res->start = sm->io_res->start + offs;
  	res->end = res->start + size - 1;
  }
  
  /* sm501_create_mem
   *
   * Fill in an MEM resource for a sub device
  */
  
  static void sm501_create_mem(struct sm501_devdata *sm,
  			     struct resource *res,
  			     resource_size_t *offs,
  			     resource_size_t size)
  {
  	*offs -= size;		/* adjust memory size */
  
  	res->flags = IORESOURCE_MEM;
  	res->parent = sm->mem_res;
  	res->start = sm->mem_res->start + *offs;
  	res->end = res->start + size - 1;
  }
  
  /* sm501_create_irq
   *
   * Fill in an IRQ resource for a sub device
  */
  
  static void sm501_create_irq(struct sm501_devdata *sm,
  			     struct resource *res)
  {
  	res->flags = IORESOURCE_IRQ;
  	res->parent = NULL;
  	res->start = res->end = sm->irq;
  }
  
  static int sm501_register_usbhost(struct sm501_devdata *sm,
  				  resource_size_t *mem_avail)
  {
  	struct platform_device *pdev;
61711f8fd   Magnus Damm   sm501: add uart s...
813
  	pdev = sm501_create_subdev(sm, "sm501-usb", 3, 0);
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
814
815
816
817
818
819
820
821
822
  	if (!pdev)
  		return -ENOMEM;
  
  	sm501_create_subio(sm, &pdev->resource[0], 0x40000, 0x20000);
  	sm501_create_mem(sm, &pdev->resource[1], mem_avail, 256*1024);
  	sm501_create_irq(sm, &pdev->resource[2]);
  
  	return sm501_register_device(sm, pdev);
  }
61711f8fd   Magnus Damm   sm501: add uart s...
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
  static void sm501_setup_uart_data(struct sm501_devdata *sm,
  				  struct plat_serial8250_port *uart_data,
  				  unsigned int offset)
  {
  	uart_data->membase = sm->regs + offset;
  	uart_data->mapbase = sm->io_res->start + offset;
  	uart_data->iotype = UPIO_MEM;
  	uart_data->irq = sm->irq;
  	uart_data->flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ;
  	uart_data->regshift = 2;
  	uart_data->uartclk = (9600 * 16);
  }
  
  static int sm501_register_uart(struct sm501_devdata *sm, int devices)
  {
  	struct platform_device *pdev;
  	struct plat_serial8250_port *uart_data;
  
  	pdev = sm501_create_subdev(sm, "serial8250", 0,
  				   sizeof(struct plat_serial8250_port) * 3);
  	if (!pdev)
  		return -ENOMEM;
  
  	uart_data = pdev->dev.platform_data;
  
  	if (devices & SM501_USE_UART0) {
  		sm501_setup_uart_data(sm, uart_data++, 0x30000);
  		sm501_unit_power(sm->dev, SM501_GATE_UART0, 1);
  		sm501_modify_reg(sm->dev, SM501_IRQ_MASK, 1 << 12, 0);
  		sm501_modify_reg(sm->dev, SM501_GPIO63_32_CONTROL, 0x01e0, 0);
  	}
  	if (devices & SM501_USE_UART1) {
  		sm501_setup_uart_data(sm, uart_data++, 0x30020);
  		sm501_unit_power(sm->dev, SM501_GATE_UART1, 1);
  		sm501_modify_reg(sm->dev, SM501_IRQ_MASK, 1 << 13, 0);
  		sm501_modify_reg(sm->dev, SM501_GPIO63_32_CONTROL, 0x1e00, 0);
  	}
  
  	pdev->id = PLAT8250_DEV_SM501;
  
  	return sm501_register_device(sm, pdev);
  }
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
865
866
867
868
  static int sm501_register_display(struct sm501_devdata *sm,
  				  resource_size_t *mem_avail)
  {
  	struct platform_device *pdev;
61711f8fd   Magnus Damm   sm501: add uart s...
869
  	pdev = sm501_create_subdev(sm, "sm501-fb", 4, 0);
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
870
871
872
873
874
875
876
877
878
879
  	if (!pdev)
  		return -ENOMEM;
  
  	sm501_create_subio(sm, &pdev->resource[0], 0x80000, 0x10000);
  	sm501_create_subio(sm, &pdev->resource[1], 0x100000, 0x50000);
  	sm501_create_mem(sm, &pdev->resource[2], mem_avail, *mem_avail);
  	sm501_create_irq(sm, &pdev->resource[3]);
  
  	return sm501_register_device(sm, pdev);
  }
f61be273d   Ben Dooks   sm501: add gpioli...
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
  #ifdef CONFIG_MFD_SM501_GPIO
  
  static inline struct sm501_gpio_chip *to_sm501_gpio(struct gpio_chip *gc)
  {
  	return container_of(gc, struct sm501_gpio_chip, gpio);
  }
  
  static inline struct sm501_devdata *sm501_gpio_to_dev(struct sm501_gpio *gpio)
  {
  	return container_of(gpio, struct sm501_devdata, gpio);
  }
  
  static int sm501_gpio_get(struct gpio_chip *chip, unsigned offset)
  
  {
  	struct sm501_gpio_chip *smgpio = to_sm501_gpio(chip);
  	unsigned long result;
bf5f00190   Heiko Schocher   video, sm501: add...
897
  	result = smc501_readl(smgpio->regbase + SM501_GPIO_DATA_LOW);
f61be273d   Ben Dooks   sm501: add gpioli...
898
899
900
901
  	result >>= offset;
  
  	return result & 1UL;
  }
98325f8f8   Ben Dooks   mfd: Ensure sm501...
902
903
904
905
906
907
  static void sm501_gpio_ensure_gpio(struct sm501_gpio_chip *smchip,
  				   unsigned long bit)
  {
  	unsigned long ctrl;
  
  	/* check and modify if this pin is not set as gpio. */
bf5f00190   Heiko Schocher   video, sm501: add...
908
  	if (smc501_readl(smchip->control) & bit) {
98325f8f8   Ben Dooks   mfd: Ensure sm501...
909
910
911
  		dev_info(sm501_gpio_to_dev(smchip->ourgpio)->dev,
  			 "changing mode of gpio, bit %08lx
  ", bit);
bf5f00190   Heiko Schocher   video, sm501: add...
912
  		ctrl = smc501_readl(smchip->control);
98325f8f8   Ben Dooks   mfd: Ensure sm501...
913
  		ctrl &= ~bit;
bf5f00190   Heiko Schocher   video, sm501: add...
914
  		smc501_writel(ctrl, smchip->control);
98325f8f8   Ben Dooks   mfd: Ensure sm501...
915
916
917
918
  
  		sm501_sync_regs(sm501_gpio_to_dev(smchip->ourgpio));
  	}
  }
f61be273d   Ben Dooks   sm501: add gpioli...
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
  static void sm501_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
  
  {
  	struct sm501_gpio_chip *smchip = to_sm501_gpio(chip);
  	struct sm501_gpio *smgpio = smchip->ourgpio;
  	unsigned long bit = 1 << offset;
  	void __iomem *regs = smchip->regbase;
  	unsigned long save;
  	unsigned long val;
  
  	dev_dbg(sm501_gpio_to_dev(smgpio)->dev, "%s(%p,%d)
  ",
  		__func__, chip, offset);
  
  	spin_lock_irqsave(&smgpio->lock, save);
bf5f00190   Heiko Schocher   video, sm501: add...
934
  	val = smc501_readl(regs + SM501_GPIO_DATA_LOW) & ~bit;
f61be273d   Ben Dooks   sm501: add gpioli...
935
936
  	if (value)
  		val |= bit;
bf5f00190   Heiko Schocher   video, sm501: add...
937
  	smc501_writel(val, regs);
f61be273d   Ben Dooks   sm501: add gpioli...
938
939
  
  	sm501_sync_regs(sm501_gpio_to_dev(smgpio));
98325f8f8   Ben Dooks   mfd: Ensure sm501...
940
  	sm501_gpio_ensure_gpio(smchip, bit);
f61be273d   Ben Dooks   sm501: add gpioli...
941
942
943
944
945
946
947
948
949
950
951
  	spin_unlock_irqrestore(&smgpio->lock, save);
  }
  
  static int sm501_gpio_input(struct gpio_chip *chip, unsigned offset)
  {
  	struct sm501_gpio_chip *smchip = to_sm501_gpio(chip);
  	struct sm501_gpio *smgpio = smchip->ourgpio;
  	void __iomem *regs = smchip->regbase;
  	unsigned long bit = 1 << offset;
  	unsigned long save;
  	unsigned long ddr;
98325f8f8   Ben Dooks   mfd: Ensure sm501...
952
953
954
  	dev_dbg(sm501_gpio_to_dev(smgpio)->dev, "%s(%p,%d)
  ",
  		__func__, chip, offset);
f61be273d   Ben Dooks   sm501: add gpioli...
955
956
  
  	spin_lock_irqsave(&smgpio->lock, save);
bf5f00190   Heiko Schocher   video, sm501: add...
957
958
  	ddr = smc501_readl(regs + SM501_GPIO_DDR_LOW);
  	smc501_writel(ddr & ~bit, regs + SM501_GPIO_DDR_LOW);
f61be273d   Ben Dooks   sm501: add gpioli...
959
960
  
  	sm501_sync_regs(sm501_gpio_to_dev(smgpio));
98325f8f8   Ben Dooks   mfd: Ensure sm501...
961
  	sm501_gpio_ensure_gpio(smchip, bit);
f61be273d   Ben Dooks   sm501: add gpioli...
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
  	spin_unlock_irqrestore(&smgpio->lock, save);
  
  	return 0;
  }
  
  static int sm501_gpio_output(struct gpio_chip *chip,
  			     unsigned offset, int value)
  {
  	struct sm501_gpio_chip *smchip = to_sm501_gpio(chip);
  	struct sm501_gpio *smgpio = smchip->ourgpio;
  	unsigned long bit = 1 << offset;
  	void __iomem *regs = smchip->regbase;
  	unsigned long save;
  	unsigned long val;
  	unsigned long ddr;
  
  	dev_dbg(sm501_gpio_to_dev(smgpio)->dev, "%s(%p,%d,%d)
  ",
  		__func__, chip, offset, value);
  
  	spin_lock_irqsave(&smgpio->lock, save);
bf5f00190   Heiko Schocher   video, sm501: add...
983
  	val = smc501_readl(regs + SM501_GPIO_DATA_LOW);
f61be273d   Ben Dooks   sm501: add gpioli...
984
985
986
987
  	if (value)
  		val |= bit;
  	else
  		val &= ~bit;
bf5f00190   Heiko Schocher   video, sm501: add...
988
  	smc501_writel(val, regs);
f61be273d   Ben Dooks   sm501: add gpioli...
989

bf5f00190   Heiko Schocher   video, sm501: add...
990
991
  	ddr = smc501_readl(regs + SM501_GPIO_DDR_LOW);
  	smc501_writel(ddr | bit, regs + SM501_GPIO_DDR_LOW);
f61be273d   Ben Dooks   sm501: add gpioli...
992
993
  
  	sm501_sync_regs(sm501_gpio_to_dev(smgpio));
bf5f00190   Heiko Schocher   video, sm501: add...
994
  	smc501_writel(val, regs + SM501_GPIO_DATA_LOW);
f61be273d   Ben Dooks   sm501: add gpioli...
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
  
  	sm501_sync_regs(sm501_gpio_to_dev(smgpio));
  	spin_unlock_irqrestore(&smgpio->lock, save);
  
  	return 0;
  }
  
  static struct gpio_chip gpio_chip_template = {
  	.ngpio			= 32,
  	.direction_input	= sm501_gpio_input,
  	.direction_output	= sm501_gpio_output,
  	.set			= sm501_gpio_set,
  	.get			= sm501_gpio_get,
  };
  
  static int __devinit sm501_gpio_register_chip(struct sm501_devdata *sm,
  					      struct sm501_gpio *gpio,
  					      struct sm501_gpio_chip *chip)
  {
  	struct sm501_platdata *pdata = sm->platdata;
  	struct gpio_chip *gchip = &chip->gpio;
60e540d61   Arnaud Patard   sm501: gpio dynam...
1016
  	int base = pdata->gpio_base;
f61be273d   Ben Dooks   sm501: add gpioli...
1017

28130bea3   Ben Dooks   sm501: fixes for ...
1018
  	chip->gpio = gpio_chip_template;
f61be273d   Ben Dooks   sm501: add gpioli...
1019
1020
  
  	if (chip == &gpio->high) {
60e540d61   Arnaud Patard   sm501: gpio dynam...
1021
1022
  		if (base > 0)
  			base += 32;
f61be273d   Ben Dooks   sm501: add gpioli...
1023
  		chip->regbase = gpio->regs + SM501_GPIO_DATA_HIGH;
98325f8f8   Ben Dooks   mfd: Ensure sm501...
1024
  		chip->control = sm->regs + SM501_GPIO63_32_CONTROL;
f61be273d   Ben Dooks   sm501: add gpioli...
1025
1026
1027
  		gchip->label  = "SM501-HIGH";
  	} else {
  		chip->regbase = gpio->regs + SM501_GPIO_DATA_LOW;
98325f8f8   Ben Dooks   mfd: Ensure sm501...
1028
  		chip->control = sm->regs + SM501_GPIO31_0_CONTROL;
f61be273d   Ben Dooks   sm501: add gpioli...
1029
1030
1031
1032
1033
1034
1035
1036
  		gchip->label  = "SM501-LOW";
  	}
  
  	gchip->base   = base;
  	chip->ourgpio = gpio;
  
  	return gpiochip_add(gchip);
  }
dcd9651ec   Rakib Mullick   mfd: Fix sm501_re...
1037
  static int __devinit sm501_register_gpio(struct sm501_devdata *sm)
f61be273d   Ben Dooks   sm501: add gpioli...
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
  {
  	struct sm501_gpio *gpio = &sm->gpio;
  	resource_size_t iobase = sm->io_res->start + SM501_GPIO;
  	int ret;
  	int tmp;
  
  	dev_dbg(sm->dev, "registering gpio block %08llx
  ",
  		(unsigned long long)iobase);
  
  	spin_lock_init(&gpio->lock);
  
  	gpio->regs_res = request_mem_region(iobase, 0x20, "sm501-gpio");
  	if (gpio->regs_res == NULL) {
  		dev_err(sm->dev, "gpio: failed to request region
  ");
  		return -ENXIO;
  	}
  
  	gpio->regs = ioremap(iobase, 0x20);
  	if (gpio->regs == NULL) {
  		dev_err(sm->dev, "gpio: failed to remap registers
  ");
  		ret = -ENXIO;
28130bea3   Ben Dooks   sm501: fixes for ...
1062
  		goto err_claimed;
f61be273d   Ben Dooks   sm501: add gpioli...
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
  	}
  
  	/* Register both our chips. */
  
  	ret = sm501_gpio_register_chip(sm, gpio, &gpio->low);
  	if (ret) {
  		dev_err(sm->dev, "failed to add low chip
  ");
  		goto err_mapped;
  	}
  
  	ret = sm501_gpio_register_chip(sm, gpio, &gpio->high);
  	if (ret) {
  		dev_err(sm->dev, "failed to add high chip
  ");
  		goto err_low_chip;
  	}
  
  	gpio->registered = 1;
  
  	return 0;
  
   err_low_chip:
  	tmp = gpiochip_remove(&gpio->low.gpio);
  	if (tmp) {
  		dev_err(sm->dev, "cannot remove low chip, cannot tidy up
  ");
  		return ret;
  	}
  
   err_mapped:
28130bea3   Ben Dooks   sm501: fixes for ...
1094
1095
1096
  	iounmap(gpio->regs);
  
   err_claimed:
f61be273d   Ben Dooks   sm501: add gpioli...
1097
1098
1099
1100
1101
1102
1103
1104
  	release_resource(gpio->regs_res);
  	kfree(gpio->regs_res);
  
  	return ret;
  }
  
  static void sm501_gpio_remove(struct sm501_devdata *sm)
  {
28130bea3   Ben Dooks   sm501: fixes for ...
1105
  	struct sm501_gpio *gpio = &sm->gpio;
f61be273d   Ben Dooks   sm501: add gpioli...
1106
  	int ret;
f2999209d   Ben Dooks   mfd: sm501 build ...
1107
1108
  	if (!sm->gpio.registered)
  		return;
28130bea3   Ben Dooks   sm501: fixes for ...
1109
  	ret = gpiochip_remove(&gpio->low.gpio);
f61be273d   Ben Dooks   sm501: add gpioli...
1110
1111
1112
  	if (ret)
  		dev_err(sm->dev, "cannot remove low chip, cannot tidy up
  ");
28130bea3   Ben Dooks   sm501: fixes for ...
1113
  	ret = gpiochip_remove(&gpio->high.gpio);
f61be273d   Ben Dooks   sm501: add gpioli...
1114
1115
1116
  	if (ret)
  		dev_err(sm->dev, "cannot remove high chip, cannot tidy up
  ");
28130bea3   Ben Dooks   sm501: fixes for ...
1117
1118
1119
1120
  
  	iounmap(gpio->regs);
  	release_resource(gpio->regs_res);
  	kfree(gpio->regs_res);
f61be273d   Ben Dooks   sm501: add gpioli...
1121
  }
28130bea3   Ben Dooks   sm501: fixes for ...
1122
  static inline int sm501_gpio_pin2nr(struct sm501_devdata *sm, unsigned int pin)
42cd2366f   Ben Dooks   sm501: gpio I2C s...
1123
1124
  {
  	struct sm501_gpio *gpio = &sm->gpio;
53a9600c6   Ben Dooks   mfd: sm501 fix gp...
1125
1126
1127
  	int base = (pin < 32) ? gpio->low.gpio.base : gpio->high.gpio.base;
  
  	return (pin % 32) + base;
42cd2366f   Ben Dooks   sm501: gpio I2C s...
1128
  }
f2999209d   Ben Dooks   mfd: sm501 build ...
1129
1130
1131
1132
1133
  
  static inline int sm501_gpio_isregistered(struct sm501_devdata *sm)
  {
  	return sm->gpio.registered;
  }
f61be273d   Ben Dooks   sm501: add gpioli...
1134
  #else
28130bea3   Ben Dooks   sm501: fixes for ...
1135
  static inline int sm501_register_gpio(struct sm501_devdata *sm)
f61be273d   Ben Dooks   sm501: add gpioli...
1136
1137
1138
  {
  	return 0;
  }
28130bea3   Ben Dooks   sm501: fixes for ...
1139
  static inline void sm501_gpio_remove(struct sm501_devdata *sm)
f61be273d   Ben Dooks   sm501: add gpioli...
1140
1141
  {
  }
42cd2366f   Ben Dooks   sm501: gpio I2C s...
1142

28130bea3   Ben Dooks   sm501: fixes for ...
1143
  static inline int sm501_gpio_pin2nr(struct sm501_devdata *sm, unsigned int pin)
42cd2366f   Ben Dooks   sm501: gpio I2C s...
1144
1145
1146
  {
  	return -1;
  }
f2999209d   Ben Dooks   mfd: sm501 build ...
1147
1148
1149
1150
1151
  
  static inline int sm501_gpio_isregistered(struct sm501_devdata *sm)
  {
  	return 0;
  }
f61be273d   Ben Dooks   sm501: add gpioli...
1152
  #endif
42cd2366f   Ben Dooks   sm501: gpio I2C s...
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
  static int sm501_register_gpio_i2c_instance(struct sm501_devdata *sm,
  					    struct sm501_platdata_gpio_i2c *iic)
  {
  	struct i2c_gpio_platform_data *icd;
  	struct platform_device *pdev;
  
  	pdev = sm501_create_subdev(sm, "i2c-gpio", 0,
  				   sizeof(struct i2c_gpio_platform_data));
  	if (!pdev)
  		return -ENOMEM;
  
  	icd = pdev->dev.platform_data;
  
  	/* We keep the pin_sda and pin_scl fields relative in case the
  	 * same platform data is passed to >1 SM501.
  	 */
  
  	icd->sda_pin = sm501_gpio_pin2nr(sm, iic->pin_sda);
  	icd->scl_pin = sm501_gpio_pin2nr(sm, iic->pin_scl);
  	icd->timeout = iic->timeout;
  	icd->udelay = iic->udelay;
  
  	/* note, we can't use either of the pin numbers, as the i2c-gpio
  	 * driver uses the platform.id field to generate the bus number
  	 * to register with the i2c core; The i2c core doesn't have enough
  	 * entries to deal with anything we currently use.
  	*/
  
  	pdev->id = iic->bus_num;
  
  	dev_info(sm->dev, "registering i2c-%d: sda=%d (%d), scl=%d (%d)
  ",
  		 iic->bus_num,
  		 icd->sda_pin, iic->pin_sda, icd->scl_pin, iic->pin_scl);
  
  	return sm501_register_device(sm, pdev);
  }
  
  static int sm501_register_gpio_i2c(struct sm501_devdata *sm,
  				   struct sm501_platdata *pdata)
  {
  	struct sm501_platdata_gpio_i2c *iic = pdata->gpio_i2c;
  	int index;
  	int ret;
  
  	for (index = 0; index < pdata->gpio_i2c_nr; index++, iic++) {
  		ret = sm501_register_gpio_i2c_instance(sm, iic);
  		if (ret < 0)
  			return ret;
  	}
  
  	return 0;
  }
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
  /* sm501_dbg_regs
   *
   * Debug attribute to attach to parent device to show core registers
  */
  
  static ssize_t sm501_dbg_regs(struct device *dev,
  			      struct device_attribute *attr, char *buff)
  {
  	struct sm501_devdata *sm = dev_get_drvdata(dev)	;
  	unsigned int reg;
  	char *ptr = buff;
  	int ret;
  
  	for (reg = 0x00; reg < 0x70; reg += 4) {
  		ret = sprintf(ptr, "%08x = %08x
  ",
bf5f00190   Heiko Schocher   video, sm501: add...
1222
  			      reg, smc501_readl(sm->regs + reg));
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
  		ptr += ret;
  	}
  
  	return ptr - buff;
  }
  
  
  static DEVICE_ATTR(dbg_regs, 0666, sm501_dbg_regs, NULL);
  
  /* sm501_init_reg
   *
   * Helper function for the init code to setup a register
5136237bc   Ben Dooks   SM501: Fix sm501_...
1235
1236
1237
   *
   * clear the bits which are set in r->mask, and then set
   * the bits set in r->set.
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
1238
1239
1240
1241
1242
1243
1244
  */
  
  static inline void sm501_init_reg(struct sm501_devdata *sm,
  				  unsigned long reg,
  				  struct sm501_reg_init *r)
  {
  	unsigned long tmp;
bf5f00190   Heiko Schocher   video, sm501: add...
1245
  	tmp = smc501_readl(sm->regs + reg);
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
1246
  	tmp &= ~r->mask;
5136237bc   Ben Dooks   SM501: Fix sm501_...
1247
  	tmp |= r->set;
bf5f00190   Heiko Schocher   video, sm501: add...
1248
  	smc501_writel(tmp, sm->regs + reg);
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
  }
  
  /* sm501_init_regs
   *
   * Setup core register values
  */
  
  static void sm501_init_regs(struct sm501_devdata *sm,
  			    struct sm501_initdata *init)
  {
  	sm501_misc_control(sm->dev,
  			   init->misc_control.set,
  			   init->misc_control.mask);
  
  	sm501_init_reg(sm, SM501_MISC_TIMING, &init->misc_timing);
  	sm501_init_reg(sm, SM501_GPIO31_0_CONTROL, &init->gpio_low);
  	sm501_init_reg(sm, SM501_GPIO63_32_CONTROL, &init->gpio_high);
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
1266
1267
1268
1269
1270
  	if (init->m1xclk) {
  		dev_info(sm->dev, "setting M1XCLK to %ld
  ", init->m1xclk);
  		sm501_set_clock(sm->dev, SM501_CLOCK_M1XCLK, init->m1xclk);
  	}
b5913bbd2   Ben Dooks   SM501: initialise...
1271
1272
1273
1274
1275
1276
  
  	if (init->mclk) {
  		dev_info(sm->dev, "setting MCLK to %ld
  ", init->mclk);
  		sm501_set_clock(sm->dev, SM501_CLOCK_MCLK, init->mclk);
  	}
819062219   Ben Dooks   SM501: Clock upda...
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
  
  }
  
  /* Check the PLL sources for the M1CLK and M1XCLK
   *
   * If the M1CLK and M1XCLKs are not sourced from the same PLL, then
   * there is a risk (see errata AB-5) that the SM501 will cease proper
   * function. If this happens, then it is likely the SM501 will
   * hang the system.
  */
  
  static int sm501_check_clocks(struct sm501_devdata *sm)
  {
bf5f00190   Heiko Schocher   video, sm501: add...
1290
  	unsigned long pwrmode = smc501_readl(sm->regs + SM501_CURRENT_CLOCK);
819062219   Ben Dooks   SM501: Clock upda...
1291
1292
1293
1294
  	unsigned long msrc = (pwrmode & SM501_POWERMODE_M_SRC);
  	unsigned long m1src = (pwrmode & SM501_POWERMODE_M1_SRC);
  
  	return ((msrc == 0 && m1src != 0) || (msrc != 0 && m1src == 0));
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
  }
  
  static unsigned int sm501_mem_local[] = {
  	[0]	= 4*1024*1024,
  	[1]	= 8*1024*1024,
  	[2]	= 16*1024*1024,
  	[3]	= 32*1024*1024,
  	[4]	= 64*1024*1024,
  	[5]	= 2*1024*1024,
  };
  
  /* sm501_init_dev
   *
   * Common init code for an SM501
  */
158abca5f   Alexey Dobriyan   mfd: fix sm501 se...
1310
  static int __devinit sm501_init_dev(struct sm501_devdata *sm)
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
1311
  {
61711f8fd   Magnus Damm   sm501: add uart s...
1312
  	struct sm501_initdata *idata;
42cd2366f   Ben Dooks   sm501: gpio I2C s...
1313
  	struct sm501_platdata *pdata;
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
1314
1315
  	resource_size_t mem_avail;
  	unsigned long dramctrl;
1e27dbe77   Ben Dooks   SM501: Check SM50...
1316
  	unsigned long devid;
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
1317
1318
1319
1320
1321
1322
  	int ret;
  
  	mutex_init(&sm->clock_lock);
  	spin_lock_init(&sm->reg_lock);
  
  	INIT_LIST_HEAD(&sm->devices);
bf5f00190   Heiko Schocher   video, sm501: add...
1323
  	devid = smc501_readl(sm->regs + SM501_DEVICEID);
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
1324

1e27dbe77   Ben Dooks   SM501: Check SM50...
1325
1326
1327
1328
1329
  	if ((devid & SM501_DEVICEID_IDMASK) != SM501_DEVICEID_SM501) {
  		dev_err(sm->dev, "incorrect device id %08lx
  ", devid);
  		return -EINVAL;
  	}
61711f8fd   Magnus Damm   sm501: add uart s...
1330
  	/* disable irqs */
bf5f00190   Heiko Schocher   video, sm501: add...
1331
  	smc501_writel(0, sm->regs + SM501_IRQ_MASK);
61711f8fd   Magnus Damm   sm501: add uart s...
1332

bf5f00190   Heiko Schocher   video, sm501: add...
1333
  	dramctrl = smc501_readl(sm->regs + SM501_DRAM_CONTROL);
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
1334
  	mem_avail = sm501_mem_local[(dramctrl >> 13) & 0x7];
1e27dbe77   Ben Dooks   SM501: Check SM50...
1335
1336
1337
  	dev_info(sm->dev, "SM501 At %p: Version %08lx, %ld Mb, IRQ %d
  ",
  		 sm->regs, devid, (unsigned long)mem_avail >> 20, sm->irq);
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
1338

3149be50d   Ville Syrjala   sm501: add suppor...
1339
  	sm->rev = devid & SM501_DEVICEID_REVMASK;
331d74750   Ben Dooks   SM501: suspend su...
1340
  	sm501_dump_gate(sm);
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
1341
1342
1343
1344
1345
1346
1347
1348
1349
  
  	ret = device_create_file(sm->dev, &dev_attr_dbg_regs);
  	if (ret)
  		dev_err(sm->dev, "failed to create debug regs file
  ");
  
  	sm501_dump_clk(sm);
  
  	/* check to see if we have some device initialisation */
42cd2366f   Ben Dooks   sm501: gpio I2C s...
1350
1351
  	pdata = sm->platdata;
  	idata = pdata ? pdata->init : NULL;
61711f8fd   Magnus Damm   sm501: add uart s...
1352
1353
  	if (idata) {
  		sm501_init_regs(sm, idata);
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
1354

61711f8fd   Magnus Damm   sm501: add uart s...
1355
1356
1357
1358
  		if (idata->devices & SM501_USE_USB_HOST)
  			sm501_register_usbhost(sm, &mem_avail);
  		if (idata->devices & (SM501_USE_UART0 | SM501_USE_UART1))
  			sm501_register_uart(sm, idata->devices);
f61be273d   Ben Dooks   sm501: add gpioli...
1359
1360
  		if (idata->devices & SM501_USE_GPIO)
  			sm501_register_gpio(sm);
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
1361
  	}
4295f9bf7   Heiko Schocher   video, sm501: add...
1362
  	if (pdata && pdata->gpio_i2c != NULL && pdata->gpio_i2c_nr > 0) {
f2999209d   Ben Dooks   mfd: sm501 build ...
1363
1364
1365
  		if (!sm501_gpio_isregistered(sm))
  			dev_err(sm->dev, "no gpio available for i2c gpio.
  ");
42cd2366f   Ben Dooks   sm501: gpio I2C s...
1366
1367
1368
  		else
  			sm501_register_gpio_i2c(sm, pdata);
  	}
819062219   Ben Dooks   SM501: Clock upda...
1369
1370
1371
1372
1373
1374
1375
  	ret = sm501_check_clocks(sm);
  	if (ret) {
  		dev_err(sm->dev, "M1X and M clocks sourced from different "
  					"PLLs
  ");
  		return -EINVAL;
  	}
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
1376
1377
1378
1379
1380
  	/* always create a framebuffer */
  	sm501_register_display(sm, &mem_avail);
  
  	return 0;
  }
158abca5f   Alexey Dobriyan   mfd: fix sm501 se...
1381
  static int __devinit sm501_plat_probe(struct platform_device *dev)
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
1382
1383
  {
  	struct sm501_devdata *sm;
7cf5244ce   Roel Kluin   mfd: check for pl...
1384
  	int ret;
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
1385
1386
1387
1388
1389
  
  	sm = kzalloc(sizeof(struct sm501_devdata), GFP_KERNEL);
  	if (sm == NULL) {
  		dev_err(&dev->dev, "no memory for device data
  ");
7cf5244ce   Roel Kluin   mfd: check for pl...
1390
  		ret = -ENOMEM;
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
1391
1392
1393
1394
1395
  		goto err1;
  	}
  
  	sm->dev = &dev->dev;
  	sm->pdev_id = dev->id;
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
1396
  	sm->platdata = dev->dev.platform_data;
7cf5244ce   Roel Kluin   mfd: check for pl...
1397
1398
  	ret = platform_get_irq(dev, 0);
  	if (ret < 0) {
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
1399
1400
  		dev_err(&dev->dev, "failed to get irq resource
  ");
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
1401
1402
  		goto err_res;
  	}
7cf5244ce   Roel Kluin   mfd: check for pl...
1403
  	sm->irq = ret;
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
1404

7cf5244ce   Roel Kluin   mfd: check for pl...
1405
1406
  	sm->io_res = platform_get_resource(dev, IORESOURCE_MEM, 1);
  	sm->mem_res = platform_get_resource(dev, IORESOURCE_MEM, 0);
4295f9bf7   Heiko Schocher   video, sm501: add...
1407

b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
1408
1409
1410
  	if (sm->io_res == NULL || sm->mem_res == NULL) {
  		dev_err(&dev->dev, "failed to get IO resource
  ");
7cf5244ce   Roel Kluin   mfd: check for pl...
1411
  		ret = -ENOENT;
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
1412
1413
1414
1415
  		goto err_res;
  	}
  
  	sm->regs_claim = request_mem_region(sm->io_res->start,
a5300dcbb   Samuel Ortiz   mfd: Fix sm501 re...
1416
  					    0x100, "sm501");
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
1417
1418
1419
1420
  
  	if (sm->regs_claim == NULL) {
  		dev_err(&dev->dev, "cannot claim registers
  ");
7cf5244ce   Roel Kluin   mfd: check for pl...
1421
  		ret = -EBUSY;
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
1422
1423
1424
1425
  		goto err_res;
  	}
  
  	platform_set_drvdata(dev, sm);
311e54c07   H Hartley Sweeten   mfd: Use resource...
1426
  	sm->regs = ioremap(sm->io_res->start, resource_size(sm->io_res));
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
1427
1428
1429
1430
  
  	if (sm->regs == NULL) {
  		dev_err(&dev->dev, "cannot remap registers
  ");
7cf5244ce   Roel Kluin   mfd: check for pl...
1431
  		ret = -EIO;
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
  		goto err_claim;
  	}
  
  	return sm501_init_dev(sm);
  
   err_claim:
  	release_resource(sm->regs_claim);
  	kfree(sm->regs_claim);
   err_res:
  	kfree(sm);
   err1:
7cf5244ce   Roel Kluin   mfd: check for pl...
1443
  	return ret;
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
1444
1445
  
  }
331d74750   Ben Dooks   SM501: suspend su...
1446
  #ifdef CONFIG_PM
472dba7d1   Ben Dooks   sm501: add power ...
1447

331d74750   Ben Dooks   SM501: suspend su...
1448
  /* power management support */
472dba7d1   Ben Dooks   sm501: add power ...
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
  static void sm501_set_power(struct sm501_devdata *sm, int on)
  {
  	struct sm501_platdata *pd = sm->platdata;
  
  	if (pd == NULL)
  		return;
  
  	if (pd->get_power) {
  		if (pd->get_power(sm->dev) == on) {
  			dev_dbg(sm->dev, "is already %d
  ", on);
  			return;
  		}
  	}
  
  	if (pd->set_power) {
  		dev_dbg(sm->dev, "setting power to %d
  ", on);
  
  		pd->set_power(sm->dev, on);
  		sm501_mdelay(sm, 10);
  	}
  }
331d74750   Ben Dooks   SM501: suspend su...
1472
1473
1474
1475
1476
  static int sm501_plat_suspend(struct platform_device *pdev, pm_message_t state)
  {
  	struct sm501_devdata *sm = platform_get_drvdata(pdev);
  
  	sm->in_suspend = 1;
bf5f00190   Heiko Schocher   video, sm501: add...
1477
  	sm->pm_misc = smc501_readl(sm->regs + SM501_MISC_CONTROL);
331d74750   Ben Dooks   SM501: suspend su...
1478
1479
  
  	sm501_dump_regs(sm);
472dba7d1   Ben Dooks   sm501: add power ...
1480
1481
1482
1483
1484
  
  	if (sm->platdata) {
  		if (sm->platdata->flags & SM501_FLAG_SUSPEND_OFF)
  			sm501_set_power(sm, 0);
  	}
331d74750   Ben Dooks   SM501: suspend su...
1485
1486
1487
1488
1489
1490
  	return 0;
  }
  
  static int sm501_plat_resume(struct platform_device *pdev)
  {
  	struct sm501_devdata *sm = platform_get_drvdata(pdev);
472dba7d1   Ben Dooks   sm501: add power ...
1491
  	sm501_set_power(sm, 1);
331d74750   Ben Dooks   SM501: suspend su...
1492
1493
1494
1495
1496
  	sm501_dump_regs(sm);
  	sm501_dump_gate(sm);
  	sm501_dump_clk(sm);
  
  	/* check to see if we are in the same state as when suspended */
bf5f00190   Heiko Schocher   video, sm501: add...
1497
  	if (smc501_readl(sm->regs + SM501_MISC_CONTROL) != sm->pm_misc) {
331d74750   Ben Dooks   SM501: suspend su...
1498
1499
  		dev_info(sm->dev, "SM501_MISC_CONTROL changed over sleep
  ");
bf5f00190   Heiko Schocher   video, sm501: add...
1500
  		smc501_writel(sm->pm_misc, sm->regs + SM501_MISC_CONTROL);
331d74750   Ben Dooks   SM501: suspend su...
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
  
  		/* our suspend causes the controller state to change,
  		 * either by something attempting setup, power loss,
  		 * or an external reset event on power change */
  
  		if (sm->platdata && sm->platdata->init) {
  			sm501_init_regs(sm, sm->platdata->init);
  		}
  	}
  
  	/* dump our state from resume */
  
  	sm501_dump_regs(sm);
  	sm501_dump_clk(sm);
  
  	sm->in_suspend = 0;
  
  	return 0;
  }
  #else
  #define sm501_plat_suspend NULL
  #define sm501_plat_resume NULL
  #endif
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
  /* Initialisation data for PCI devices */
  
  static struct sm501_initdata sm501_pci_initdata = {
  	.gpio_high	= {
  		.set	= 0x3F000000,		/* 24bit panel */
  		.mask	= 0x0,
  	},
  	.misc_timing	= {
  		.set	= 0x010100,		/* SDRAM timing */
  		.mask	= 0x1F1F00,
  	},
  	.misc_control	= {
  		.set	= SM501_MISC_PNL_24BIT,
  		.mask	= 0,
  	},
  
  	.devices	= SM501_USE_ALL,
819062219   Ben Dooks   SM501: Clock upda...
1541
1542
1543
1544
1545
1546
  
  	/* Errata AB-3 says that 72MHz is the fastest available
  	 * for 33MHZ PCI with proper bus-mastering operation */
  
  	.mclk		= 72 * MHZ,
  	.m1xclk		= 144 * MHZ,
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
  };
  
  static struct sm501_platdata_fbsub sm501_pdata_fbsub = {
  	.flags		= (SM501FB_FLAG_USE_INIT_MODE |
  			   SM501FB_FLAG_USE_HWCURSOR |
  			   SM501FB_FLAG_USE_HWACCEL |
  			   SM501FB_FLAG_DISABLE_AT_EXIT),
  };
  
  static struct sm501_platdata_fb sm501_fb_pdata = {
  	.fb_route	= SM501_FB_OWN,
  	.fb_crt		= &sm501_pdata_fbsub,
  	.fb_pnl		= &sm501_pdata_fbsub,
  };
  
  static struct sm501_platdata sm501_pci_platdata = {
  	.init		= &sm501_pci_initdata,
  	.fb		= &sm501_fb_pdata,
60e540d61   Arnaud Patard   sm501: gpio dynam...
1565
  	.gpio_base	= -1,
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
1566
  };
158abca5f   Alexey Dobriyan   mfd: fix sm501 se...
1567
1568
  static int __devinit sm501_pci_probe(struct pci_dev *dev,
  				     const struct pci_device_id *id)
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
  {
  	struct sm501_devdata *sm;
  	int err;
  
  	sm = kzalloc(sizeof(struct sm501_devdata), GFP_KERNEL);
  	if (sm == NULL) {
  		dev_err(&dev->dev, "no memory for device data
  ");
  		err = -ENOMEM;
  		goto err1;
  	}
  
  	/* set a default set of platform data */
  	dev->dev.platform_data = sm->platdata = &sm501_pci_platdata;
  
  	/* set a hopefully unique id for our child platform devices */
  	sm->pdev_id = 32 + dev->devfn;
  
  	pci_set_drvdata(dev, sm);
  
  	err = pci_enable_device(dev);
  	if (err) {
  		dev_err(&dev->dev, "cannot enable device
  ");
  		goto err2;
  	}
  
  	sm->dev = &dev->dev;
  	sm->irq = dev->irq;
  
  #ifdef __BIG_ENDIAN
  	/* if the system is big-endian, we most probably have a
  	 * translation in the IO layer making the PCI bus little endian
  	 * so make the framebuffer swapped pixels */
  
  	sm501_fb_pdata.flags |= SM501_FBPD_SWAP_FB_ENDIAN;
  #endif
  
  	/* check our resources */
  
  	if (!(pci_resource_flags(dev, 0) & IORESOURCE_MEM)) {
  		dev_err(&dev->dev, "region #0 is not memory?
  ");
  		err = -EINVAL;
  		goto err3;
  	}
  
  	if (!(pci_resource_flags(dev, 1) & IORESOURCE_MEM)) {
  		dev_err(&dev->dev, "region #1 is not memory?
  ");
  		err = -EINVAL;
  		goto err3;
  	}
  
  	/* make our resources ready for sharing */
  
  	sm->io_res = &dev->resource[1];
  	sm->mem_res = &dev->resource[0];
  
  	sm->regs_claim = request_mem_region(sm->io_res->start,
a5300dcbb   Samuel Ortiz   mfd: Fix sm501 re...
1629
  					    0x100, "sm501");
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
1630
1631
1632
1633
1634
1635
  	if (sm->regs_claim == NULL) {
  		dev_err(&dev->dev, "cannot claim registers
  ");
  		err= -EBUSY;
  		goto err3;
  	}
7ab18995e   Arjan van de Ven   mfd: use pci_iore...
1636
  	sm->regs = pci_ioremap_bar(dev, 1);
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
  
  	if (sm->regs == NULL) {
  		dev_err(&dev->dev, "cannot remap registers
  ");
  		err = -EIO;
  		goto err4;
  	}
  
  	sm501_init_dev(sm);
  	return 0;
  
   err4:
  	release_resource(sm->regs_claim);
  	kfree(sm->regs_claim);
   err3:
  	pci_disable_device(dev);
   err2:
  	pci_set_drvdata(dev, NULL);
  	kfree(sm);
   err1:
  	return err;
  }
  
  static void sm501_remove_sub(struct sm501_devdata *sm,
  			     struct sm501_device *smdev)
  {
  	list_del(&smdev->list);
  	platform_device_unregister(&smdev->pdev);
  }
  
  static void sm501_dev_remove(struct sm501_devdata *sm)
  {
  	struct sm501_device *smdev, *tmp;
  
  	list_for_each_entry_safe(smdev, tmp, &sm->devices, list)
  		sm501_remove_sub(sm, smdev);
  
  	device_remove_file(sm->dev, &dev_attr_dbg_regs);
f61be273d   Ben Dooks   sm501: add gpioli...
1675

f2999209d   Ben Dooks   mfd: sm501 build ...
1676
  	sm501_gpio_remove(sm);
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
1677
  }
158abca5f   Alexey Dobriyan   mfd: fix sm501 se...
1678
  static void __devexit sm501_pci_remove(struct pci_dev *dev)
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
  {
  	struct sm501_devdata *sm = pci_get_drvdata(dev);
  
  	sm501_dev_remove(sm);
  	iounmap(sm->regs);
  
  	release_resource(sm->regs_claim);
  	kfree(sm->regs_claim);
  
  	pci_set_drvdata(dev, NULL);
  	pci_disable_device(dev);
  }
  
  static int sm501_plat_remove(struct platform_device *dev)
  {
  	struct sm501_devdata *sm = platform_get_drvdata(dev);
  
  	sm501_dev_remove(sm);
  	iounmap(sm->regs);
  
  	release_resource(sm->regs_claim);
  	kfree(sm->regs_claim);
  
  	return 0;
  }
61485c63c   Axel Lin   mfd: Convert to D...
1704
  static DEFINE_PCI_DEVICE_TABLE(sm501_pci_tbl) = {
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
1705
1706
1707
1708
1709
  	{ 0x126f, 0x0501, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
  	{ 0, },
  };
  
  MODULE_DEVICE_TABLE(pci, sm501_pci_tbl);
158abca5f   Alexey Dobriyan   mfd: fix sm501 se...
1710
  static struct pci_driver sm501_pci_driver = {
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
1711
1712
1713
  	.name		= "sm501",
  	.id_table	= sm501_pci_tbl,
  	.probe		= sm501_pci_probe,
158abca5f   Alexey Dobriyan   mfd: fix sm501 se...
1714
  	.remove		= __devexit_p(sm501_pci_remove),
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
1715
  };
4f46d6e7e   Kay Sievers   mfd: fix platform...
1716
  MODULE_ALIAS("platform:sm501");
4295f9bf7   Heiko Schocher   video, sm501: add...
1717
1718
1719
1720
  static struct of_device_id __devinitdata of_sm501_match_tbl[] = {
  	{ .compatible = "smi,sm501", },
  	{ /* end */ }
  };
158abca5f   Alexey Dobriyan   mfd: fix sm501 se...
1721
  static struct platform_driver sm501_plat_driver = {
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
1722
1723
1724
  	.driver		= {
  		.name	= "sm501",
  		.owner	= THIS_MODULE,
4295f9bf7   Heiko Schocher   video, sm501: add...
1725
  		.of_match_table = of_sm501_match_tbl,
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
1726
1727
1728
  	},
  	.probe		= sm501_plat_probe,
  	.remove		= sm501_plat_remove,
331d74750   Ben Dooks   SM501: suspend su...
1729
1730
  	.suspend	= sm501_plat_suspend,
  	.resume		= sm501_plat_resume,
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
1731
1732
1733
1734
  };
  
  static int __init sm501_base_init(void)
  {
158abca5f   Alexey Dobriyan   mfd: fix sm501 se...
1735
1736
  	platform_driver_register(&sm501_plat_driver);
  	return pci_register_driver(&sm501_pci_driver);
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
1737
1738
1739
1740
  }
  
  static void __exit sm501_base_exit(void)
  {
158abca5f   Alexey Dobriyan   mfd: fix sm501 se...
1741
1742
  	platform_driver_unregister(&sm501_plat_driver);
  	pci_unregister_driver(&sm501_pci_driver);
b6d6454fd   Ben Dooks   [PATCH] mfd: SM50...
1743
1744
1745
1746
1747
1748
1749
1750
  }
  
  module_init(sm501_base_init);
  module_exit(sm501_base_exit);
  
  MODULE_DESCRIPTION("SM501 Core Driver");
  MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>, Vincent Sanders");
  MODULE_LICENSE("GPL v2");