diff options
| -rw-r--r-- | drivers/i2c/busses/Kconfig | 9 | ||||
| -rw-r--r-- | drivers/i2c/busses/Makefile | 1 | ||||
| -rw-r--r-- | drivers/i2c/busses/i2c-sh7760.c | 577 | ||||
| -rw-r--r-- | include/asm-sh/i2c-sh7760.h | 22 |
4 files changed, 609 insertions, 0 deletions
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 1577bcad288a..d01d0b175e1c 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig | |||
| @@ -683,4 +683,13 @@ config I2C_PMCMSP | |||
| 683 | This driver can also be built as module. If so, the module | 683 | This driver can also be built as module. If so, the module |
| 684 | will be called i2c-pmcmsp. | 684 | will be called i2c-pmcmsp. |
| 685 | 685 | ||
| 686 | config I2C_SH7760 | ||
| 687 | tristate "Renesas SH7760 I2C Controller" | ||
| 688 | depends on CPU_SUBTYPE_SH7760 | ||
| 689 | help | ||
| 690 | This driver supports the 2 I2C interfaces on the Renesas SH7760. | ||
| 691 | |||
| 692 | This driver can also be built as a module. If so, the module | ||
| 693 | will be called i2c-sh7760. | ||
| 694 | |||
| 686 | endmenu | 695 | endmenu |
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 378d5c07e048..8e72b2649dc7 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile | |||
| @@ -38,6 +38,7 @@ obj-$(CONFIG_I2C_PROSAVAGE) += i2c-prosavage.o | |||
| 38 | obj-$(CONFIG_I2C_PXA) += i2c-pxa.o | 38 | obj-$(CONFIG_I2C_PXA) += i2c-pxa.o |
| 39 | obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o | 39 | obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o |
| 40 | obj-$(CONFIG_I2C_SAVAGE4) += i2c-savage4.o | 40 | obj-$(CONFIG_I2C_SAVAGE4) += i2c-savage4.o |
| 41 | obj-$(CONFIG_I2C_SH7760) += i2c-sh7760.o | ||
| 41 | obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o | 42 | obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o |
| 42 | obj-$(CONFIG_I2C_SIMTEC) += i2c-simtec.o | 43 | obj-$(CONFIG_I2C_SIMTEC) += i2c-simtec.o |
| 43 | obj-$(CONFIG_I2C_SIS5595) += i2c-sis5595.o | 44 | obj-$(CONFIG_I2C_SIS5595) += i2c-sis5595.o |
diff --git a/drivers/i2c/busses/i2c-sh7760.c b/drivers/i2c/busses/i2c-sh7760.c new file mode 100644 index 000000000000..5e0e254976de --- /dev/null +++ b/drivers/i2c/busses/i2c-sh7760.c | |||
| @@ -0,0 +1,577 @@ | |||
| 1 | /* | ||
| 2 | * I2C bus driver for the SH7760 I2C Interfaces. | ||
| 3 | * | ||
| 4 | * (c) 2005-2008 MSC Vertriebsges.m.b.H, Manuel Lauss <mlau@msc-ge.com> | ||
| 5 | * | ||
| 6 | * licensed under the terms outlined in the file COPYING. | ||
| 7 | * | ||
| 8 | */ | ||
| 9 | |||
| 10 | #include <linux/completion.h> | ||
| 11 | #include <linux/delay.h> | ||
| 12 | #include <linux/err.h> | ||
| 13 | #include <linux/i2c.h> | ||
| 14 | #include <linux/init.h> | ||
| 15 | #include <linux/interrupt.h> | ||
| 16 | #include <linux/ioport.h> | ||
| 17 | #include <linux/platform_device.h> | ||
| 18 | #include <linux/slab.h> | ||
| 19 | |||
| 20 | #include <asm/clock.h> | ||
| 21 | #include <asm/i2c-sh7760.h> | ||
| 22 | #include <asm/io.h> | ||
| 23 | |||
| 24 | /* register offsets */ | ||
| 25 | #define I2CSCR 0x0 /* slave ctrl */ | ||
| 26 | #define I2CMCR 0x4 /* master ctrl */ | ||
| 27 | #define I2CSSR 0x8 /* slave status */ | ||
| 28 | #define I2CMSR 0xC /* master status */ | ||
| 29 | #define I2CSIER 0x10 /* slave irq enable */ | ||
| 30 | #define I2CMIER 0x14 /* master irq enable */ | ||
| 31 | #define I2CCCR 0x18 /* clock dividers */ | ||
| 32 | #define I2CSAR 0x1c /* slave address */ | ||
| 33 | #define I2CMAR 0x20 /* master address */ | ||
| 34 | #define I2CRXTX 0x24 /* data port */ | ||
| 35 | #define I2CFCR 0x28 /* fifo control */ | ||
| 36 | #define I2CFSR 0x2C /* fifo status */ | ||
| 37 | #define I2CFIER 0x30 /* fifo irq enable */ | ||
| 38 | #define I2CRFDR 0x34 /* rx fifo count */ | ||
| 39 | #define I2CTFDR 0x38 /* tx fifo count */ | ||
| 40 | |||
| 41 | #define REGSIZE 0x3C | ||
| 42 | |||
| 43 | #define MCR_MDBS 0x80 /* non-fifo mode switch */ | ||
| 44 | #define MCR_FSCL 0x40 /* override SCL pin */ | ||
| 45 | #define MCR_FSDA 0x20 /* override SDA pin */ | ||
| 46 | #define MCR_OBPC 0x10 /* override pins */ | ||
| 47 | #define MCR_MIE 0x08 /* master if enable */ | ||
| 48 | #define MCR_TSBE 0x04 | ||
| 49 | #define MCR_FSB 0x02 /* force stop bit */ | ||
| 50 | #define MCR_ESG 0x01 /* en startbit gen. */ | ||
| 51 | |||
| 52 | #define MSR_MNR 0x40 /* nack received */ | ||
| 53 | #define MSR_MAL 0x20 /* arbitration lost */ | ||
| 54 | #define MSR_MST 0x10 /* sent a stop */ | ||
| 55 | #define MSR_MDE 0x08 | ||
| 56 | #define MSR_MDT 0x04 | ||
| 57 | #define MSR_MDR 0x02 | ||
| 58 | #define MSR_MAT 0x01 /* slave addr xfer done */ | ||
| 59 | |||
| 60 | #define MIE_MNRE 0x40 /* nack irq en */ | ||
| 61 | #define MIE_MALE 0x20 /* arblos irq en */ | ||
| 62 | #define MIE_MSTE 0x10 /* stop irq en */ | ||
| 63 | #define MIE_MDEE 0x08 | ||
| 64 | #define MIE_MDTE 0x04 | ||
| 65 | #define MIE_MDRE 0x02 | ||
| 66 | #define MIE_MATE 0x01 /* address sent irq en */ | ||
| 67 | |||
| 68 | #define FCR_RFRST 0x02 /* reset rx fifo */ | ||
| 69 | #define FCR_TFRST 0x01 /* reset tx fifo */ | ||
| 70 | |||
| 71 | #define FSR_TEND 0x04 /* last byte sent */ | ||
| 72 | #define FSR_RDF 0x02 /* rx fifo trigger */ | ||
| 73 | #define FSR_TDFE 0x01 /* tx fifo empty */ | ||
| 74 | |||
| 75 | #define FIER_TEIE 0x04 /* tx fifo empty irq en */ | ||
| 76 | #define FIER_RXIE 0x02 /* rx fifo trig irq en */ | ||
| 77 | #define FIER_TXIE 0x01 /* tx fifo trig irq en */ | ||
| 78 | |||
| 79 | #define FIFO_SIZE 16 | ||
| 80 | |||
| 81 | struct cami2c { | ||
| 82 | void __iomem *iobase; | ||
| 83 | struct i2c_adapter adap; | ||
| 84 | |||
| 85 | /* message processing */ | ||
| 86 | struct i2c_msg *msg; | ||
| 87 | #define IDF_SEND 1 | ||
| 88 | #define IDF_RECV 2 | ||
| 89 | #define IDF_STOP 4 | ||
| 90 | int flags; | ||
| 91 | |||
| 92 | #define IDS_DONE 1 | ||
| 93 | #define IDS_ARBLOST 2 | ||
| 94 | #define IDS_NACK 4 | ||
| 95 | int status; | ||
| 96 | struct completion xfer_done; | ||
| 97 | |||
| 98 | int irq; | ||
| 99 | struct resource *ioarea; | ||
| 100 | }; | ||
| 101 | |||
| 102 | static inline void OUT32(struct cami2c *cam, int reg, unsigned long val) | ||
| 103 | { | ||
| 104 | ctrl_outl(val, (unsigned long)cam->iobase + reg); | ||
| 105 | } | ||
| 106 | |||
| 107 | static inline unsigned long IN32(struct cami2c *cam, int reg) | ||
| 108 | { | ||
| 109 | return ctrl_inl((unsigned long)cam->iobase + reg); | ||
| 110 | } | ||
| 111 | |||
| 112 | static irqreturn_t sh7760_i2c_irq(int irq, void *ptr) | ||
| 113 | { | ||
| 114 | struct cami2c *id = ptr; | ||
| 115 | struct i2c_msg *msg = id->msg; | ||
| 116 | char *data = msg->buf; | ||
| 117 | unsigned long msr, fsr, fier, len; | ||
| 118 | |||
| 119 | msr = IN32(id, I2CMSR); | ||
| 120 | fsr = IN32(id, I2CFSR); | ||
| 121 | |||
| 122 | /* arbitration lost */ | ||
| 123 | if (msr & MSR_MAL) { | ||
| 124 | OUT32(id, I2CMCR, 0); | ||
| 125 | OUT32(id, I2CSCR, 0); | ||
| 126 | OUT32(id, I2CSAR, 0); | ||
| 127 | id->status |= IDS_DONE | IDS_ARBLOST; | ||
| 128 | goto out; | ||
| 129 | } | ||
| 130 | |||
| 131 | if (msr & MSR_MNR) { | ||
| 132 | /* NACK handling is very screwed up. After receiving a | ||
| 133 | * NAK IRQ one has to wait a bit before writing to any | ||
| 134 | * registers, or the ctl will lock up. After that delay | ||
| 135 | * do a normal i2c stop. Then wait at least 1 ms before | ||
| 136 | * attempting another transfer or ctl will stop working | ||
| 137 | */ | ||
| 138 | udelay(100); /* wait or risk ctl hang */ | ||
| 139 | OUT32(id, I2CFCR, FCR_RFRST | FCR_TFRST); | ||
| 140 | OUT32(id, I2CMCR, MCR_MIE | MCR_FSB); | ||
| 141 | OUT32(id, I2CFIER, 0); | ||
| 142 | OUT32(id, I2CMIER, MIE_MSTE); | ||
| 143 | OUT32(id, I2CSCR, 0); | ||
| 144 | OUT32(id, I2CSAR, 0); | ||
| 145 | id->status |= IDS_NACK; | ||
| 146 | msr &= ~MSR_MAT; | ||
| 147 | fsr = 0; | ||
| 148 | /* In some cases the MST bit is also set. */ | ||
| 149 | } | ||
| 150 | |||
| 151 | /* i2c-stop was sent */ | ||
| 152 | if (msr & MSR_MST) { | ||
| 153 | id->status |= IDS_DONE; | ||
| 154 | goto out; | ||
| 155 | } | ||
| 156 | |||
| 157 | /* i2c slave addr was sent; set to "normal" operation */ | ||
| 158 | if (msr & MSR_MAT) | ||
| 159 | OUT32(id, I2CMCR, MCR_MIE); | ||
| 160 | |||
| 161 | fier = IN32(id, I2CFIER); | ||
| 162 | |||
| 163 | if (fsr & FSR_RDF) { | ||
| 164 | len = IN32(id, I2CRFDR); | ||
| 165 | if (msg->len <= len) { | ||
| 166 | if (id->flags & IDF_STOP) { | ||
| 167 | OUT32(id, I2CMCR, MCR_MIE | MCR_FSB); | ||
| 168 | OUT32(id, I2CFIER, 0); | ||
| 169 | /* manual says: wait >= 0.5 SCL times */ | ||
| 170 | udelay(5); | ||
| 171 | /* next int should be MST */ | ||
| 172 | } else { | ||
| 173 | id->status |= IDS_DONE; | ||
| 174 | /* keep the RDF bit: ctrl holds SCL low | ||
| 175 | * until the setup for the next i2c_msg | ||
| 176 | * clears this bit. | ||
| 177 | */ | ||
| 178 | fsr &= ~FSR_RDF; | ||
| 179 | } | ||
| 180 | } | ||
| 181 | while (msg->len && len) { | ||
| 182 | *data++ = IN32(id, I2CRXTX); | ||
| 183 | msg->len--; | ||
| 184 | len--; | ||
| 185 | } | ||
| 186 | |||
| 187 | if (msg->len) { | ||
| 188 | len = (msg->len >= FIFO_SIZE) ? FIFO_SIZE - 1 | ||
| 189 | : msg->len - 1; | ||
| 190 | |||
| 191 | OUT32(id, I2CFCR, FCR_TFRST | ((len & 0xf) << 4)); | ||
| 192 | } | ||
| 193 | |||
| 194 | } else if (id->flags & IDF_SEND) { | ||
| 195 | if ((fsr & FSR_TEND) && (msg->len < 1)) { | ||
| 196 | if (id->flags & IDF_STOP) { | ||
| 197 | OUT32(id, I2CMCR, MCR_MIE | MCR_FSB); | ||
| 198 | } else { | ||
| 199 | id->status |= IDS_DONE; | ||
| 200 | /* keep the TEND bit: ctl holds SCL low | ||
| 201 | * until the setup for the next i2c_msg | ||
| 202 | * clears this bit. | ||
| 203 | */ | ||
| 204 | fsr &= ~FSR_TEND; | ||
| 205 | } | ||
| 206 | } | ||
| 207 | if (fsr & FSR_TDFE) { | ||
| 208 | while (msg->len && (IN32(id, I2CTFDR) < FIFO_SIZE)) { | ||
| 209 | OUT32(id, I2CRXTX, *data++); | ||
| 210 | msg->len--; | ||
| 211 | } | ||
| 212 | |||
| 213 | if (msg->len < 1) { | ||
| 214 | fier &= ~FIER_TXIE; | ||
| 215 | OUT32(id, I2CFIER, fier); | ||
| 216 | } else { | ||
| 217 | len = (msg->len >= FIFO_SIZE) ? 2 : 0; | ||
| 218 | OUT32(id, I2CFCR, | ||
| 219 | FCR_RFRST | ((len & 3) << 2)); | ||
| 220 | } | ||
| 221 | } | ||
| 222 | } | ||
| 223 | out: | ||
| 224 | if (id->status & IDS_DONE) { | ||
| 225 | OUT32(id, I2CMIER, 0); | ||
| 226 | OUT32(id, I2CFIER, 0); | ||
| 227 | id->msg = NULL; | ||
| 228 | complete(&id->xfer_done); | ||
| 229 | } | ||
| 230 | /* clear status flags and ctrl resumes work */ | ||
| 231 | OUT32(id, I2CMSR, ~msr); | ||
| 232 | OUT32(id, I2CFSR, ~fsr); | ||
| 233 | OUT32(id, I2CSSR, 0); | ||
| 234 | |||
| 235 | return IRQ_HANDLED; | ||
| 236 | } | ||
| 237 | |||
| 238 | |||
| 239 | /* prepare and start a master receive operation */ | ||
| 240 | static void sh7760_i2c_mrecv(struct cami2c *id) | ||
| 241 | { | ||
| 242 | int len; | ||
| 243 | |||
| 244 | id->flags |= IDF_RECV; | ||
| 245 | |||
| 246 | /* set the slave addr reg; otherwise rcv wont work! */ | ||
| 247 | OUT32(id, I2CSAR, 0xfe); | ||
| 248 | OUT32(id, I2CMAR, (id->msg->addr << 1) | 1); | ||
| 249 | |||
| 250 | /* adjust rx fifo trigger */ | ||
| 251 | if (id->msg->len >= FIFO_SIZE) | ||
| 252 | len = FIFO_SIZE - 1; /* trigger at fifo full */ | ||
| 253 | else | ||
| 254 | len = id->msg->len - 1; /* trigger before all received */ | ||
| 255 | |||
| 256 | OUT32(id, I2CFCR, FCR_RFRST | FCR_TFRST); | ||
| 257 | OUT32(id, I2CFCR, FCR_TFRST | ((len & 0xF) << 4)); | ||
| 258 | |||
| 259 | OUT32(id, I2CMSR, 0); | ||
| 260 | OUT32(id, I2CMCR, MCR_MIE | MCR_ESG); | ||
| 261 | OUT32(id, I2CMIER, MIE_MNRE | MIE_MALE | MIE_MSTE | MIE_MATE); | ||
| 262 | OUT32(id, I2CFIER, FIER_RXIE); | ||
| 263 | } | ||
| 264 | |||
| 265 | /* prepare and start a master send operation */ | ||
| 266 | static void sh7760_i2c_msend(struct cami2c *id) | ||
| 267 | { | ||
| 268 | int len; | ||
| 269 | |||
| 270 | id->flags |= IDF_SEND; | ||
| 271 | |||
| 272 | /* set the slave addr reg; otherwise xmit wont work! */ | ||
| 273 | OUT32(id, I2CSAR, 0xfe); | ||
| 274 | OUT32(id, I2CMAR, (id->msg->addr << 1) | 0); | ||
| 275 | |||
| 276 | /* adjust tx fifo trigger */ | ||
| 277 | if (id->msg->len >= FIFO_SIZE) | ||
| 278 | len = 2; /* trig: 2 bytes left in TX fifo */ | ||
| 279 | else | ||
| 280 | len = 0; /* trig: 8 bytes left in TX fifo */ | ||
| 281 | |||
| 282 | OUT32(id, I2CFCR, FCR_RFRST | FCR_TFRST); | ||
| 283 | OUT32(id, I2CFCR, FCR_RFRST | ((len & 3) << 2)); | ||
| 284 | |||
| 285 | while (id->msg->len && IN32(id, I2CTFDR) < FIFO_SIZE) { | ||
| 286 | OUT32(id, I2CRXTX, *(id->msg->buf)); | ||
| 287 | (id->msg->len)--; | ||
| 288 | (id->msg->buf)++; | ||
| 289 | } | ||
| 290 | |||
| 291 | OUT32(id, I2CMSR, 0); | ||
| 292 | OUT32(id, I2CMCR, MCR_MIE | MCR_ESG); | ||
| 293 | OUT32(id, I2CFSR, 0); | ||
| 294 | OUT32(id, I2CMIER, MIE_MNRE | MIE_MALE | MIE_MSTE | MIE_MATE); | ||
| 295 | OUT32(id, I2CFIER, FIER_TEIE | (id->msg->len ? FIER_TXIE : 0)); | ||
| 296 | } | ||
| 297 | |||
| 298 | static inline int sh7760_i2c_busy_check(struct cami2c *id) | ||
| 299 | { | ||
| 300 | return (IN32(id, I2CMCR) & MCR_FSDA); | ||
| 301 | } | ||
| 302 | |||
| 303 | static int sh7760_i2c_master_xfer(struct i2c_adapter *adap, | ||
| 304 | struct i2c_msg *msgs, | ||
| 305 | int num) | ||
| 306 | { | ||
| 307 | struct cami2c *id = adap->algo_data; | ||
| 308 | int i, retr; | ||
| 309 | |||
| 310 | if (sh7760_i2c_busy_check(id)) { | ||
| 311 | dev_err(&adap->dev, "sh7760-i2c%d: bus busy!\n", adap->nr); | ||
| 312 | return -EBUSY; | ||
| 313 | } | ||
| 314 | |||
| 315 | i = 0; | ||
| 316 | while (i < num) { | ||
| 317 | retr = adap->retries; | ||
| 318 | retry: | ||
| 319 | id->flags = ((i == (num-1)) ? IDF_STOP : 0); | ||
| 320 | id->status = 0; | ||
| 321 | id->msg = msgs; | ||
| 322 | init_completion(&id->xfer_done); | ||
| 323 | |||
| 324 | if (msgs->flags & I2C_M_RD) | ||
| 325 | sh7760_i2c_mrecv(id); | ||
| 326 | else | ||
| 327 | sh7760_i2c_msend(id); | ||
| 328 | |||
| 329 | wait_for_completion(&id->xfer_done); | ||
| 330 | |||
| 331 | if (id->status == 0) { | ||
| 332 | num = -EIO; | ||
| 333 | break; | ||
| 334 | } | ||
| 335 | |||
| 336 | if (id->status & IDS_NACK) { | ||
| 337 | /* wait a bit or i2c module stops working */ | ||
| 338 | mdelay(1); | ||
| 339 | num = -EREMOTEIO; | ||
| 340 | break; | ||
| 341 | } | ||
| 342 | |||
| 343 | if (id->status & IDS_ARBLOST) { | ||
| 344 | if (retr--) { | ||
| 345 | mdelay(2); | ||
| 346 | goto retry; | ||
| 347 | } | ||
| 348 | num = -EREMOTEIO; | ||
| 349 | break; | ||
| 350 | } | ||
| 351 | |||
| 352 | msgs++; | ||
| 353 | i++; | ||
| 354 | } | ||
| 355 | |||
| 356 | id->msg = NULL; | ||
| 357 | id->flags = 0; | ||
| 358 | id->status = 0; | ||
| 359 | |||
| 360 | OUT32(id, I2CMCR, 0); | ||
| 361 | OUT32(id, I2CMSR, 0); | ||
| 362 | OUT32(id, I2CMIER, 0); | ||
| 363 | OUT32(id, I2CFIER, 0); | ||
| 364 | |||
| 365 | /* reset slave module registers too: master mode enables slave | ||
| 366 | * module for receive ops (ack, data). Without this reset, | ||
| 367 | * eternal bus activity might be reported after NACK / ARBLOST. | ||
| 368 | */ | ||
| 369 | OUT32(id, I2CSCR, 0); | ||
| 370 | OUT32(id, I2CSAR, 0); | ||
| 371 | OUT32(id, I2CSSR, 0); | ||
| 372 | |||
| 373 | return num; | ||
| 374 | } | ||
| 375 | |||
| 376 | static u32 sh7760_i2c_func(struct i2c_adapter *adap) | ||
| 377 | { | ||
| 378 | return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK); | ||
| 379 | } | ||
| 380 | |||
| 381 | static const struct i2c_algorithm sh7760_i2c_algo = { | ||
| 382 | .master_xfer = sh7760_i2c_master_xfer, | ||
| 383 | .functionality = sh7760_i2c_func, | ||
| 384 | }; | ||
| 385 | |||
| 386 | /* calculate CCR register setting for a desired scl clock. SCL clock is | ||
| 387 | * derived from I2C module clock (iclk) which in turn is derived from | ||
| 388 | * peripheral module clock (mclk, usually around 33MHz): | ||
| 389 | * iclk = mclk/(CDF + 1). iclk must be < 20MHz. | ||
| 390 | * scl = iclk/(SCGD*8 + 20). | ||
| 391 | */ | ||
| 392 | static int __devinit calc_CCR(unsigned long scl_hz) | ||
| 393 | { | ||
| 394 | struct clk *mclk; | ||
| 395 | unsigned long mck, m1, dff, odff, iclk; | ||
| 396 | signed char cdf, cdfm; | ||
| 397 | int scgd, scgdm, scgds; | ||
| 398 | |||
| 399 | mclk = clk_get(NULL, "module_clk"); | ||
| 400 | if (IS_ERR(mclk)) { | ||
| 401 | return PTR_ERR(mclk); | ||
| 402 | } else { | ||
| 403 | mck = mclk->rate; | ||
| 404 | clk_put(mclk); | ||
| 405 | } | ||
| 406 | |||
| 407 | odff = scl_hz; | ||
| 408 | scgdm = cdfm = m1 = 0; | ||
| 409 | for (cdf = 3; cdf >= 0; cdf--) { | ||
| 410 | iclk = mck / (1 + cdf); | ||
| 411 | if (iclk >= 20000000) | ||
| 412 | continue; | ||
| 413 | scgds = ((iclk / scl_hz) - 20) >> 3; | ||
| 414 | for (scgd = scgds; (scgd < 63) && scgd <= scgds + 1; scgd++) { | ||
| 415 | m1 = iclk / (20 + (scgd << 3)); | ||
| 416 | dff = abs(scl_hz - m1); | ||
| 417 | if (dff < odff) { | ||
| 418 | odff = dff; | ||
| 419 | cdfm = cdf; | ||
| 420 | scgdm = scgd; | ||
| 421 | } | ||
| 422 | } | ||
| 423 | } | ||
| 424 | /* fail if more than 25% off of requested SCL */ | ||
| 425 | if (odff > (scl_hz >> 2)) | ||
| 426 | return -EINVAL; | ||
| 427 | |||
| 428 | /* create a CCR register value */ | ||
| 429 | return ((scgdm << 2) | cdfm); | ||
| 430 | } | ||
| 431 | |||
| 432 | static int __devinit sh7760_i2c_probe(struct platform_device *pdev) | ||
| 433 | { | ||
| 434 | struct sh7760_i2c_platdata *pd; | ||
| 435 | struct resource *res; | ||
| 436 | struct cami2c *id; | ||
| 437 | int ret; | ||
| 438 | |||
| 439 | pd = pdev->dev.platform_data; | ||
| 440 | if (!pd) { | ||
| 441 | dev_err(&pdev->dev, "no platform_data!\n"); | ||
| 442 | ret = -ENODEV; | ||
| 443 | goto out0; | ||
| 444 | } | ||
| 445 | |||
| 446 | id = kzalloc(sizeof(struct cami2c), GFP_KERNEL); | ||
| 447 | if (!id) { | ||
| 448 | dev_err(&pdev->dev, "no mem for private data\n"); | ||
| 449 | ret = -ENOMEM; | ||
| 450 | goto out0; | ||
| 451 | } | ||
| 452 | |||
| 453 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 454 | if (!res) { | ||
| 455 | dev_err(&pdev->dev, "no mmio resources\n"); | ||
| 456 | ret = -ENODEV; | ||
| 457 | goto out1; | ||
| 458 | } | ||
| 459 | |||
| 460 | id->ioarea = request_mem_region(res->start, REGSIZE, pdev->name); | ||
| 461 | if (!id->ioarea) { | ||
| 462 | dev_err(&pdev->dev, "mmio already reserved\n"); | ||
| 463 | ret = -EBUSY; | ||
| 464 | goto out1; | ||
| 465 | } | ||
| 466 | |||
| 467 | id->iobase = ioremap(res->start, REGSIZE); | ||
| 468 | if (!id->iobase) { | ||
| 469 | dev_err(&pdev->dev, "cannot ioremap\n"); | ||
| 470 | ret = -ENODEV; | ||
| 471 | goto out2; | ||
| 472 | } | ||
| 473 | |||
| 474 | id->irq = platform_get_irq(pdev, 0); | ||
| 475 | |||
| 476 | id->adap.nr = pdev->id; | ||
| 477 | id->adap.algo = &sh7760_i2c_algo; | ||
| 478 | id->adap.class = I2C_CLASS_ALL; | ||
| 479 | id->adap.retries = 3; | ||
| 480 | id->adap.algo_data = id; | ||
| 481 | id->adap.dev.parent = &pdev->dev; | ||
| 482 | snprintf(id->adap.name, sizeof(id->adap.name), | ||
| 483 | "SH7760 I2C at %08lx", (unsigned long)res->start); | ||
| 484 | |||
| 485 | OUT32(id, I2CMCR, 0); | ||
| 486 | OUT32(id, I2CMSR, 0); | ||
| 487 | OUT32(id, I2CMIER, 0); | ||
| 488 | OUT32(id, I2CMAR, 0); | ||
| 489 | OUT32(id, I2CSIER, 0); | ||
| 490 | OUT32(id, I2CSAR, 0); | ||
| 491 | OUT32(id, I2CSCR, 0); | ||
| 492 | OUT32(id, I2CSSR, 0); | ||
| 493 | OUT32(id, I2CFIER, 0); | ||
| 494 | OUT32(id, I2CFCR, FCR_RFRST | FCR_TFRST); | ||
| 495 | OUT32(id, I2CFSR, 0); | ||
| 496 | |||
| 497 | ret = calc_CCR(pd->speed_khz * 1000); | ||
| 498 | if (ret < 0) { | ||
| 499 | dev_err(&pdev->dev, "invalid SCL clock: %dkHz\n", | ||
| 500 | pd->speed_khz); | ||
| 501 | goto out3; | ||
| 502 | } | ||
| 503 | OUT32(id, I2CCCR, ret); | ||
| 504 | |||
| 505 | if (request_irq(id->irq, sh7760_i2c_irq, IRQF_DISABLED, | ||
| 506 | SH7760_I2C_DEVNAME, id)) { | ||
| 507 | dev_err(&pdev->dev, "cannot get irq %d\n", id->irq); | ||
| 508 | ret = -EBUSY; | ||
| 509 | goto out3; | ||
| 510 | } | ||
| 511 | |||
| 512 | ret = i2c_add_numbered_adapter(&id->adap); | ||
| 513 | if (ret < 0) { | ||
| 514 | dev_err(&pdev->dev, "reg adap failed: %d\n", ret); | ||
| 515 | goto out4; | ||
| 516 | } | ||
| 517 | |||
| 518 | platform_set_drvdata(pdev, id); | ||
| 519 | |||
| 520 | dev_info(&pdev->dev, "%d kHz mmio %08x irq %d\n", | ||
| 521 | pd->speed_khz, res->start, id->irq); | ||
| 522 | |||
| 523 | return 0; | ||
| 524 | |||
| 525 | out4: | ||
| 526 | free_irq(id->irq, id); | ||
| 527 | out3: | ||
| 528 | iounmap(id->iobase); | ||
| 529 | out2: | ||
| 530 | release_resource(id->ioarea); | ||
| 531 | kfree(id->ioarea); | ||
| 532 | out1: | ||
| 533 | kfree(id); | ||
| 534 | out0: | ||
| 535 | return ret; | ||
| 536 | } | ||
| 537 | |||
| 538 | static int __devexit sh7760_i2c_remove(struct platform_device *pdev) | ||
| 539 | { | ||
| 540 | struct cami2c *id = platform_get_drvdata(pdev); | ||
| 541 | |||
| 542 | i2c_del_adapter(&id->adap); | ||
| 543 | free_irq(id->irq, id); | ||
| 544 | iounmap(id->iobase); | ||
| 545 | release_resource(id->ioarea); | ||
| 546 | kfree(id->ioarea); | ||
| 547 | kfree(id); | ||
| 548 | platform_set_drvdata(pdev, NULL); | ||
| 549 | |||
| 550 | return 0; | ||
| 551 | } | ||
| 552 | |||
| 553 | static struct platform_driver sh7760_i2c_drv = { | ||
| 554 | .driver = { | ||
| 555 | .name = SH7760_I2C_DEVNAME, | ||
| 556 | .owner = THIS_MODULE, | ||
| 557 | }, | ||
| 558 | .probe = sh7760_i2c_probe, | ||
| 559 | .remove = __devexit_p(sh7760_i2c_remove), | ||
| 560 | }; | ||
| 561 | |||
| 562 | static int __init sh7760_i2c_init(void) | ||
| 563 | { | ||
| 564 | return platform_driver_register(&sh7760_i2c_drv); | ||
| 565 | } | ||
| 566 | |||
| 567 | static void __exit sh7760_i2c_exit(void) | ||
| 568 | { | ||
| 569 | platform_driver_unregister(&sh7760_i2c_drv); | ||
| 570 | } | ||
| 571 | |||
| 572 | module_init(sh7760_i2c_init); | ||
| 573 | module_exit(sh7760_i2c_exit); | ||
| 574 | |||
| 575 | MODULE_LICENSE("GPL"); | ||
| 576 | MODULE_DESCRIPTION("SH7760 I2C bus driver"); | ||
| 577 | MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>"); | ||
diff --git a/include/asm-sh/i2c-sh7760.h b/include/asm-sh/i2c-sh7760.h new file mode 100644 index 000000000000..24182116711f --- /dev/null +++ b/include/asm-sh/i2c-sh7760.h | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | /* | ||
| 2 | * MMIO/IRQ and platform data for SH7760 I2C channels | ||
| 3 | */ | ||
| 4 | |||
| 5 | #ifndef _I2C_SH7760_H_ | ||
| 6 | #define _I2C_SH7760_H_ | ||
| 7 | |||
| 8 | #define SH7760_I2C_DEVNAME "sh7760-i2c" | ||
| 9 | |||
| 10 | #define SH7760_I2C0_MMIO 0xFE140000 | ||
| 11 | #define SH7760_I2C0_MMIOEND 0xFE14003B | ||
| 12 | #define SH7760_I2C0_IRQ 62 | ||
| 13 | |||
| 14 | #define SH7760_I2C1_MMIO 0xFE150000 | ||
| 15 | #define SH7760_I2C1_MMIOEND 0xFE15003B | ||
| 16 | #define SH7760_I2C1_IRQ 63 | ||
| 17 | |||
| 18 | struct sh7760_i2c_platdata { | ||
| 19 | unsigned int speed_khz; | ||
| 20 | }; | ||
| 21 | |||
| 22 | #endif | ||
