Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
qe_io.c
Go to the documentation of this file.
1 /*
2  * arch/powerpc/sysdev/qe_lib/qe_io.c
3  *
4  * QE Parallel I/O ports configuration routines
5  *
6  * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved.
7  *
8  * Author: Li Yang <[email protected]>
9  * Based on code from Shlomi Gridish <[email protected]>
10  *
11  * This program is free software; you can redistribute it and/or modify it
12  * under the terms of the GNU General Public License as published by the
13  * Free Software Foundation; either version 2 of the License, or (at your
14  * option) any later version.
15  */
16 
17 #include <linux/stddef.h>
18 #include <linux/kernel.h>
19 #include <linux/init.h>
20 #include <linux/errno.h>
21 #include <linux/module.h>
22 #include <linux/ioport.h>
23 
24 #include <asm/io.h>
25 #include <asm/qe.h>
26 #include <asm/prom.h>
27 #include <sysdev/fsl_soc.h>
28 
29 #undef DEBUG
30 
31 static struct qe_pio_regs __iomem *par_io;
32 static int num_par_io_ports = 0;
33 
34 int par_io_init(struct device_node *np)
35 {
36  struct resource res;
37  int ret;
38  const u32 *num_ports;
39 
40  /* Map Parallel I/O ports registers */
41  ret = of_address_to_resource(np, 0, &res);
42  if (ret)
43  return ret;
44  par_io = ioremap(res.start, resource_size(&res));
45 
46  num_ports = of_get_property(np, "num-ports", NULL);
47  if (num_ports)
48  num_par_io_ports = *num_ports;
49 
50  return 0;
51 }
52 
53 void __par_io_config_pin(struct qe_pio_regs __iomem *par_io, u8 pin, int dir,
54  int open_drain, int assignment, int has_irq)
55 {
56  u32 pin_mask1bit;
57  u32 pin_mask2bits;
58  u32 new_mask2bits;
59  u32 tmp_val;
60 
61  /* calculate pin location for single and 2 bits information */
62  pin_mask1bit = (u32) (1 << (QE_PIO_PINS - (pin + 1)));
63 
64  /* Set open drain, if required */
65  tmp_val = in_be32(&par_io->cpodr);
66  if (open_drain)
67  out_be32(&par_io->cpodr, pin_mask1bit | tmp_val);
68  else
69  out_be32(&par_io->cpodr, ~pin_mask1bit & tmp_val);
70 
71  /* define direction */
72  tmp_val = (pin > (QE_PIO_PINS / 2) - 1) ?
73  in_be32(&par_io->cpdir2) :
74  in_be32(&par_io->cpdir1);
75 
76  /* get all bits mask for 2 bit per port */
77  pin_mask2bits = (u32) (0x3 << (QE_PIO_PINS -
78  (pin % (QE_PIO_PINS / 2) + 1) * 2));
79 
80  /* Get the final mask we need for the right definition */
81  new_mask2bits = (u32) (dir << (QE_PIO_PINS -
82  (pin % (QE_PIO_PINS / 2) + 1) * 2));
83 
84  /* clear and set 2 bits mask */
85  if (pin > (QE_PIO_PINS / 2) - 1) {
86  out_be32(&par_io->cpdir2,
87  ~pin_mask2bits & tmp_val);
88  tmp_val &= ~pin_mask2bits;
89  out_be32(&par_io->cpdir2, new_mask2bits | tmp_val);
90  } else {
91  out_be32(&par_io->cpdir1,
92  ~pin_mask2bits & tmp_val);
93  tmp_val &= ~pin_mask2bits;
94  out_be32(&par_io->cpdir1, new_mask2bits | tmp_val);
95  }
96  /* define pin assignment */
97  tmp_val = (pin > (QE_PIO_PINS / 2) - 1) ?
98  in_be32(&par_io->cppar2) :
99  in_be32(&par_io->cppar1);
100 
101  new_mask2bits = (u32) (assignment << (QE_PIO_PINS -
102  (pin % (QE_PIO_PINS / 2) + 1) * 2));
103  /* clear and set 2 bits mask */
104  if (pin > (QE_PIO_PINS / 2) - 1) {
105  out_be32(&par_io->cppar2,
106  ~pin_mask2bits & tmp_val);
107  tmp_val &= ~pin_mask2bits;
108  out_be32(&par_io->cppar2, new_mask2bits | tmp_val);
109  } else {
110  out_be32(&par_io->cppar1,
111  ~pin_mask2bits & tmp_val);
112  tmp_val &= ~pin_mask2bits;
113  out_be32(&par_io->cppar1, new_mask2bits | tmp_val);
114  }
115 }
117 
118 int par_io_config_pin(u8 port, u8 pin, int dir, int open_drain,
119  int assignment, int has_irq)
120 {
121  if (!par_io || port >= num_par_io_ports)
122  return -EINVAL;
123 
124  __par_io_config_pin(&par_io[port], pin, dir, open_drain, assignment,
125  has_irq);
126  return 0;
127 }
129 
131 {
132  u32 pin_mask, tmp_val;
133 
134  if (port >= num_par_io_ports)
135  return -EINVAL;
136  if (pin >= QE_PIO_PINS)
137  return -EINVAL;
138  /* calculate pin location */
139  pin_mask = (u32) (1 << (QE_PIO_PINS - 1 - pin));
140 
141  tmp_val = in_be32(&par_io[port].cpdata);
142 
143  if (val == 0) /* clear */
144  out_be32(&par_io[port].cpdata, ~pin_mask & tmp_val);
145  else /* set */
146  out_be32(&par_io[port].cpdata, pin_mask | tmp_val);
147 
148  return 0;
149 }
151 
153 {
154  struct device_node *pio;
155  const phandle *ph;
156  int pio_map_len;
157  const unsigned int *pio_map;
158 
159  if (par_io == NULL) {
160  printk(KERN_ERR "par_io not initialized\n");
161  return -1;
162  }
163 
164  ph = of_get_property(np, "pio-handle", NULL);
165  if (ph == NULL) {
166  printk(KERN_ERR "pio-handle not available\n");
167  return -1;
168  }
169 
170  pio = of_find_node_by_phandle(*ph);
171 
172  pio_map = of_get_property(pio, "pio-map", &pio_map_len);
173  if (pio_map == NULL) {
174  printk(KERN_ERR "pio-map is not set!\n");
175  return -1;
176  }
177  pio_map_len /= sizeof(unsigned int);
178  if ((pio_map_len % 6) != 0) {
179  printk(KERN_ERR "pio-map format wrong!\n");
180  return -1;
181  }
182 
183  while (pio_map_len > 0) {
184  par_io_config_pin((u8) pio_map[0], (u8) pio_map[1],
185  (int) pio_map[2], (int) pio_map[3],
186  (int) pio_map[4], (int) pio_map[5]);
187  pio_map += 6;
188  pio_map_len -= 6;
189  }
190  of_node_put(pio);
191  return 0;
192 }
194 
195 #ifdef DEBUG
196 static void dump_par_io(void)
197 {
198  unsigned int i;
199 
200  printk(KERN_INFO "%s: par_io=%p\n", __func__, par_io);
201  for (i = 0; i < num_par_io_ports; i++) {
202  printk(KERN_INFO " cpodr[%u]=%08x\n", i,
203  in_be32(&par_io[i].cpodr));
204  printk(KERN_INFO " cpdata[%u]=%08x\n", i,
205  in_be32(&par_io[i].cpdata));
206  printk(KERN_INFO " cpdir1[%u]=%08x\n", i,
207  in_be32(&par_io[i].cpdir1));
208  printk(KERN_INFO " cpdir2[%u]=%08x\n", i,
209  in_be32(&par_io[i].cpdir2));
210  printk(KERN_INFO " cppar1[%u]=%08x\n", i,
211  in_be32(&par_io[i].cppar1));
212  printk(KERN_INFO " cppar2[%u]=%08x\n", i,
213  in_be32(&par_io[i].cppar2));
214  }
215 
216 }
217 EXPORT_SYMBOL(dump_par_io);
218 #endif /* DEBUG */