Changeset 34167


Ignore:
Timestamp:
2012-11-12T09:21:38+01:00 (5 years ago)
Author:
kaloz
Message:

[cns3xxx]: split the i2c patch, merge the retry fixup

Location:
trunk/target/linux/cns3xxx
Files:
3 added
1 deleted
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/target/linux/cns3xxx/patches-3.3/050-cns3xxx_i2c_controller.patch

    r31809 r34167  
    3030 obj-$(CONFIG_SCx200_I2C)       += scx200_i2c.o 
    3131  
    32 --- /dev/null 
    33 +++ b/drivers/i2c/busses/i2c-cns3xxx.c 
    34 @@ -0,0 +1,387 @@ 
    35 +/* 
    36 + * Cavium CNS3xxx I2C Host Controller 
    37 + * 
    38 + * Copyright 2010 Cavium Network 
    39 + * Copyright 2011 Gateworks Corporation 
    40 + *               Chris Lang <clang@gateworks.com> 
    41 + * 
    42 + * This file is free software; you can redistribute it and/or modify 
    43 + * it under the terms of the GNU General Public License, Version 2, as 
    44 + * published by the Free Software Foundation. 
    45 + */ 
    46 + 
    47 +#include <linux/kernel.h> 
    48 +#include <linux/module.h> 
    49 +#include <linux/init.h> 
    50 +#include <linux/platform_device.h> 
    51 +#include <asm/io.h> 
    52 +#include <linux/wait.h> 
    53 +#include <linux/interrupt.h> 
    54 +#include <linux/delay.h> 
    55 +#include <linux/i2c.h> 
    56 +#include <linux/slab.h> 
    57 +#include <mach/pm.h> 
    58 +#include <mach/cns3xxx.h> 
    59 + 
    60 +/* 
    61 + * We need the memory map 
    62 + */ 
    63 + 
    64 + 
    65 +#define MISC_MEM_MAP_VALUE(reg_offset) (*((uint32_t volatile *)(CNS3XXX_MISC_BASE_VIRT + reg_offset))) 
    66 +#define MISC_IOCDB_CTRL                                MISC_MEM_MAP_VALUE(0x020) 
    67 + 
    68 +#define I2C_MEM_MAP_ADDR(x)         (CNS3XXX_SSP_BASE_VIRT + x) 
    69 +#define I2C_MEM_MAP_VALUE(x)        (*((unsigned int volatile*)I2C_MEM_MAP_ADDR(x))) 
    70 + 
    71 +#define I2C_CONTROLLER_REG                    I2C_MEM_MAP_VALUE(0x20) 
    72 +#define I2C_TIME_OUT_REG                      I2C_MEM_MAP_VALUE(0x24) 
    73 +#define I2C_SLAVE_ADDRESS_REG                 I2C_MEM_MAP_VALUE(0x28) 
    74 +#define I2C_WRITE_DATA_REG                    I2C_MEM_MAP_VALUE(0x2C) 
    75 +#define I2C_READ_DATA_REG                     I2C_MEM_MAP_VALUE(0x30) 
    76 +#define I2C_INTERRUPT_STATUS_REG              I2C_MEM_MAP_VALUE(0x34) 
    77 +#define I2C_INTERRUPT_ENABLE_REG              I2C_MEM_MAP_VALUE(0x38) 
    78 +#define I2C_TWI_OUT_DLY_REG                                                    I2C_MEM_MAP_VALUE(0x3C) 
    79 + 
    80 +#define I2C_BUS_ERROR_FLAG     (0x1) 
    81 +#define I2C_ACTION_DONE_FLAG   (0x2) 
    82 + 
    83 +#define CNS3xxx_I2C_ENABLE()          (I2C_CONTROLLER_REG) |= ((unsigned int)0x1 << 31) 
    84 +#define CNS3xxx_I2C_DISABLE()         (I2C_CONTROLLER_REG) &= ~((unsigned int)0x1 << 31) 
    85 +#define CNS3xxx_I2C_ENABLE_INTR()     (I2C_INTERRUPT_ENABLE_REG) |= 0x03 
    86 +#define CNS3xxx_I2C_DISABLE_INTR()    (I2C_INTERRUPT_ENABLE_REG) &= 0xfc 
    87 + 
    88 +#define TWI_TIMEOUT         (10*HZ) 
    89 +#define I2C_100KHZ          100000 
    90 +#define I2C_200KHZ          200000 
    91 +#define I2C_300KHZ          300000 
    92 +#define I2C_400KHZ          400000 
    93 + 
    94 +#define CNS3xxx_I2C_CLK     I2C_100KHZ 
    95 + 
    96 +#define STATE_DONE             1 
    97 +#define STATE_ERROR            2 
    98 + 
    99 +struct cns3xxx_i2c { 
    100 +       void __iomem *base; 
    101 +       wait_queue_head_t wait; 
    102 +       struct i2c_adapter adap; 
    103 +       struct i2c_msg *msg; 
    104 +       int state;              /* see STATE_ */ 
    105 +       int rd_wr_len; 
    106 +       u8 *buf; 
    107 +}; 
    108 + 
    109 +static u32 cns3xxx_i2c_func(struct i2c_adapter *adap) 
    110 +{ 
    111 +       return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; 
    112 +} 
    113 + 
    114 +static int 
    115 +cns3xxx_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg) 
    116 +{ 
    117 +       struct cns3xxx_i2c *i2c = i2c_get_adapdata(adap); 
    118 +       int i, j; 
    119 +       u8 buf[1] = { 0 }; 
    120 + 
    121 +       if (msg->len == 0) { 
    122 +               /* 
    123 +                *      We are probably doing a probe for a device here, 
    124 +                *      so set the length to one, and data to 0 
    125 +                */ 
    126 +               msg->len = 1; 
    127 +               i2c->buf = buf; 
    128 +       } else { 
    129 +               i2c->buf = msg->buf; 
    130 +       } 
    131 + 
    132 +       if (msg->flags & I2C_M_TEN) { 
    133 +               printk 
    134 +                       ("%s:%d: Presently the driver does not handle extended addressing\n", 
    135 +                               __FUNCTION__, __LINE__); 
    136 +               return -EINVAL; 
    137 +       } 
    138 +       i2c->msg = msg; 
    139 + 
    140 +       for (i = 0; i < msg->len; i++) { 
    141 +               if (msg->len - i >= 4) 
    142 +                       i2c->rd_wr_len = 3; 
    143 +               else 
    144 +                       i2c->rd_wr_len = msg->len - i - 1; 
    145 + 
    146 +               // Set Data Width       and TWI_EN 
    147 +               I2C_CONTROLLER_REG = 0x80000000 | (i2c->rd_wr_len << 2) | (i2c->rd_wr_len); 
    148 + 
    149 +               // Clear Write Reg 
    150 +               I2C_WRITE_DATA_REG = 0; 
    151 + 
    152 +               // Set the slave address 
    153 +               I2C_SLAVE_ADDRESS_REG = (msg->addr << 1); 
    154 + 
    155 +               // Are we Writing 
    156 +               if (!(msg->flags & I2C_M_RD)) { 
    157 +                       I2C_CONTROLLER_REG |= (1 << 4); 
    158 +                       if (i != 0) { 
    159 +                               /* 
    160 +                                * We need to set the address in the first byte. 
    161 +                                * The base address is going to be in buf[0] and then 
    162 +                                * it needs to be incremented by i - 1. 
    163 +                                */ 
    164 +                               i2c->buf--; 
    165 +                               *i2c->buf = buf[0] + i - 1; 
    166 + 
    167 +                               if (i2c->rd_wr_len < 3) { 
    168 +                                       i += i2c->rd_wr_len; 
    169 +                                       i2c->rd_wr_len++; 
    170 +                                       I2C_CONTROLLER_REG = 0x80000000 | (1 << 4) | (i2c->rd_wr_len << 2) | (i2c->rd_wr_len); 
    171 +                               } else { 
    172 +                                       i += i2c->rd_wr_len - 1; 
    173 +                               } 
    174 +                       } else { 
    175 +                               i += i2c->rd_wr_len; 
    176 +                               buf[0] = *i2c->buf; 
    177 +                       } 
    178 +                       for (j = 0; j <= i2c->rd_wr_len; j++) { 
    179 +                               I2C_WRITE_DATA_REG |= ((*i2c->buf++) << (8 * j)); 
    180 +                       } 
    181 +               } else { 
    182 +                       i += i2c->rd_wr_len; 
    183 +               } 
    184 + 
    185 +               // Start the Transfer 
    186 +               i2c->state = 0;         // Clear out the State 
    187 +               I2C_CONTROLLER_REG |= (1 << 6); 
    188 + 
    189 +               if (wait_event_timeout(i2c->wait, (i2c->state == STATE_ERROR) || 
    190 +                               (i2c->state == STATE_DONE), TWI_TIMEOUT)) { 
    191 +                       if (i2c->state == STATE_ERROR) { 
    192 +                               return -EIO; 
    193 +                       } 
    194 +               } else { 
    195 +                       return -ETIMEDOUT; 
    196 +               } 
    197 +       } 
    198 +       return 0; 
    199 +} 
    200 + 
    201 +static int 
    202 +cns3xxx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) 
    203 +{ 
    204 +       int i; 
    205 +       int ret; 
    206 +       for (i = 0; i < num; i++) 
    207 +       { 
    208 +               ret = cns3xxx_i2c_xfer_msg(adap, &msgs[i]); 
    209 +               if (ret < 0) { 
    210 +                       return ret; 
    211 +               } 
    212 +       } 
    213 +       return num; 
    214 +} 
    215 + 
    216 + 
    217 +static struct i2c_algorithm cns3xxx_i2c_algo = { 
    218 +       .master_xfer = cns3xxx_i2c_xfer, 
    219 +       .functionality = cns3xxx_i2c_func, 
    220 +}; 
    221 + 
    222 +static struct i2c_adapter cns3xxx_i2c_adapter = { 
    223 +       .owner = THIS_MODULE, 
    224 +       .algo = &cns3xxx_i2c_algo, 
    225 +       .algo_data = NULL, 
    226 +       .nr = 0, 
    227 +       .name = "CNS3xxx I2C 0", 
    228 +       .retries = 5, 
    229 +}; 
    230 + 
    231 +static void cns3xxx_i2c_adapter_init(struct cns3xxx_i2c *i2c) 
    232 +{ 
    233 +        cns3xxx_pwr_clk_en(1 << PM_CLK_GATE_REG_OFFSET_SPI_PCM_I2C); 
    234 +        cns3xxx_pwr_power_up(1 << PM_CLK_GATE_REG_OFFSET_SPI_PCM_I2C); 
    235 +        cns3xxx_pwr_soft_rst(1 << PM_CLK_GATE_REG_OFFSET_SPI_PCM_I2C); 
    236 + 
    237 +       /* Disable the I2C */ 
    238 +       I2C_CONTROLLER_REG = 0; /* Disabled the I2C */ 
    239 + 
    240 +       //enable SCL and SDA which share pin with GPIOB_PIN_EN(0x18) 
    241 +       //GPIOB[12]: SCL 
    242 +       //GPIOB[13]: SDA 
    243 +       (*(u32*)(CNS3XXX_MISC_BASE_VIRT+0x18)) |= ((1<<12)|(1<<13)); 
    244 + 
    245 +       MISC_IOCDB_CTRL &= ~0x300; 
    246 +       MISC_IOCDB_CTRL |= 0x300; //21mA... 
    247 + 
    248 +       /* Check the Reg Dump when testing */ 
    249 +       I2C_TIME_OUT_REG = 
    250 +           ((((((cns3xxx_cpu_clock()*(1000000/8)) / (2 * CNS3xxx_I2C_CLK)) - 
    251 +               1) & 0x3FF) << 8) | (1 << 7) | 0x7F); 
    252 +       I2C_TWI_OUT_DLY_REG |= 0x3; 
    253 + 
    254 +       /* Enable The Interrupt */ 
    255 +       CNS3xxx_I2C_ENABLE_INTR(); 
    256 + 
    257 +       /* Clear Interrupt Status (0x2 | 0x1) */ 
    258 +       I2C_INTERRUPT_STATUS_REG |= (I2C_ACTION_DONE_FLAG | I2C_BUS_ERROR_FLAG); 
    259 + 
    260 +       /* Enable the I2C Controller */ 
    261 +       CNS3xxx_I2C_ENABLE(); 
    262 +} 
    263 + 
    264 +static irqreturn_t cns3xxx_i2c_isr(int irq, void *dev_id) 
    265 +{ 
    266 +       struct cns3xxx_i2c *i2c = dev_id; 
    267 +       int i; 
    268 +       uint32_t stat = I2C_INTERRUPT_STATUS_REG; 
    269 + 
    270 +       /* Clear Interrupt */ 
    271 +       I2C_INTERRUPT_STATUS_REG |= 0x1; 
    272 + 
    273 +       if (stat & I2C_BUS_ERROR_FLAG) { 
    274 +               i2c->state = STATE_ERROR; 
    275 +       } else { 
    276 +               if (i2c->msg->flags & I2C_M_RD) { 
    277 +                       for (i = 0; i <= i2c->rd_wr_len; i++) 
    278 +                       { 
    279 +                               *i2c->buf++ = ((I2C_READ_DATA_REG >> (8 * i)) & 0xff); 
    280 +                       } 
    281 +               } 
    282 +               i2c->state = STATE_DONE; 
    283 +       } 
    284 +       wake_up(&i2c->wait); 
    285 +       return IRQ_HANDLED; 
    286 +} 
    287 + 
    288 +static int __devinit cns3xxx_i2c_probe(struct platform_device *pdev) 
    289 +{ 
    290 +       struct cns3xxx_i2c *i2c; 
    291 +       struct resource *res, *res2; 
    292 +       int ret; 
    293 + 
    294 +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 
    295 +       if (!res) { 
    296 +               printk("%s: IORESOURCE_MEM not defined \n", __FUNCTION__); 
    297 +               return -ENODEV; 
    298 +       } 
    299 + 
    300 +       res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 
    301 +       if (!res2) { 
    302 +               printk("%s: IORESOURCE_IRQ not defined \n", __FUNCTION__); 
    303 +               return -ENODEV; 
    304 +       } 
    305 + 
    306 +       i2c = kzalloc(sizeof(*i2c), GFP_KERNEL); 
    307 +       if (!i2c) 
    308 +               return -ENOMEM; 
    309 + 
    310 +       if (!request_mem_region(res->start, res->end - res->start + 1, 
    311 +                               pdev->name)) { 
    312 +               dev_err(&pdev->dev, "Memory region busy\n"); 
    313 +               ret = -EBUSY; 
    314 +               goto request_mem_failed; 
    315 +       } 
    316 + 
    317 +       i2c->base = ioremap(res->start, res->end - res->start + 1); 
    318 +       if (!i2c->base) { 
    319 +               dev_err(&pdev->dev, "Unable to map registers\n"); 
    320 +               ret = -EIO; 
    321 +               goto map_failed; 
    322 +       } 
    323 + 
    324 +       cns3xxx_i2c_adapter_init(i2c); 
    325 + 
    326 +       init_waitqueue_head(&i2c->wait); 
    327 +       ret = request_irq(res2->start, cns3xxx_i2c_isr, 0, pdev->name, i2c); 
    328 +       if (ret) { 
    329 +               dev_err(&pdev->dev, "Cannot claim IRQ\n"); 
    330 +               goto request_irq_failed; 
    331 +       } 
    332 + 
    333 +       platform_set_drvdata(pdev, i2c); 
    334 +       i2c->adap = cns3xxx_i2c_adapter; 
    335 +       i2c_set_adapdata(&i2c->adap, i2c); 
    336 +       i2c->adap.dev.parent = &pdev->dev; 
    337 + 
    338 +       /* add i2c adapter to i2c tree */ 
    339 +       ret = i2c_add_numbered_adapter(&i2c->adap); 
    340 +       if (ret) { 
    341 +               dev_err(&pdev->dev, "Failed to add adapter\n"); 
    342 +               goto add_adapter_failed; 
    343 +       } 
    344 + 
    345 +       return 0; 
    346 + 
    347 +      add_adapter_failed: 
    348 +       free_irq(res2->start, i2c); 
    349 +      request_irq_failed: 
    350 +       iounmap(i2c->base); 
    351 +      map_failed: 
    352 +       release_mem_region(res->start, res->end - res->start + 1); 
    353 +      request_mem_failed: 
    354 +       kfree(i2c); 
    355 + 
    356 +       return ret; 
    357 +} 
    358 + 
    359 +static int __devexit cns3xxx_i2c_remove(struct platform_device *pdev) 
    360 +{ 
    361 +       struct cns3xxx_i2c *i2c = platform_get_drvdata(pdev); 
    362 +       struct resource *res; 
    363 + 
    364 +       /* disable i2c logic */ 
    365 +       CNS3xxx_I2C_DISABLE_INTR(); 
    366 +       CNS3xxx_I2C_DISABLE(); 
    367 +       /* remove adapter & data */ 
    368 +       i2c_del_adapter(&i2c->adap); 
    369 +       platform_set_drvdata(pdev, NULL); 
    370 + 
    371 +       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 
    372 +       if (res) 
    373 +               free_irq(res->start, i2c); 
    374 + 
    375 +       iounmap(i2c->base); 
    376 + 
    377 +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 
    378 +       if (res) 
    379 +               release_mem_region(res->start, res->end - res->start + 1); 
    380 + 
    381 +       kfree(i2c); 
    382 + 
    383 +       return 0; 
    384 +} 
    385 + 
    386 +#ifdef CONFIG_PM 
    387 +#warning "CONFIG_PM defined: suspend and resume not implemented" 
    388 +#define cns3xxx_i2c_suspend    NULL 
    389 +#define cns3xxx_i2c_resume     NULL 
    390 +#else 
    391 +#define cns3xxx_i2c_suspend    NULL 
    392 +#define cns3xxx_i2c_resume     NULL 
    393 +#endif 
    394 + 
    395 +static struct platform_driver cns3xxx_i2c_driver = { 
    396 +       .probe = cns3xxx_i2c_probe, 
    397 +       .remove = cns3xxx_i2c_remove, 
    398 +       .suspend = cns3xxx_i2c_suspend, 
    399 +       .resume = cns3xxx_i2c_resume, 
    400 +       .driver = { 
    401 +               .owner = THIS_MODULE, 
    402 +               .name = "cns3xxx-i2c", 
    403 +       }, 
    404 +}; 
    405 + 
    406 +static int __init cns3xxx_i2c_init(void) 
    407 +{ 
    408 +       return platform_driver_register(&cns3xxx_i2c_driver); 
    409 +} 
    410 + 
    411 +static void __exit cns3xxx_i2c_exit(void) 
    412 +{ 
    413 +       platform_driver_unregister(&cns3xxx_i2c_driver); 
    414 +} 
    415 + 
    416 +module_init(cns3xxx_i2c_init); 
    417 +module_exit(cns3xxx_i2c_exit); 
    418 + 
    419 +MODULE_AUTHOR("Cavium Networks"); 
    420 +MODULE_DESCRIPTION("Cavium CNS3XXX I2C Controller"); 
    421 +MODULE_LICENSE("GPL"); 
Note: See TracChangeset for help on using the changeset viewer.