root/arch/arm/mach-integrator/impd1.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. impd1_tweak_control
  2. impd1fb_clcd_disable
  3. impd1fb_clcd_enable
  4. impd1fb_clcd_setup
  5. impd1fb_clcd_mmap
  6. impd1fb_clcd_remove
  7. impd1_probe
  8. impd1_remove_one
  9. impd1_remove
  10. impd1_init
  11. impd1_exit

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  *  linux/arch/arm/mach-integrator/impd1.c
   4  *
   5  *  Copyright (C) 2003 Deep Blue Solutions Ltd, All Rights Reserved.
   6  *
   7  *  This file provides the core support for the IM-PD1 module.
   8  *
   9  * Module / boot parameters.
  10  *   lmid=n   impd1.lmid=n - set the logic module position in stack to 'n'
  11  */
  12 #include <linux/module.h>
  13 #include <linux/moduleparam.h>
  14 #include <linux/init.h>
  15 #include <linux/device.h>
  16 #include <linux/errno.h>
  17 #include <linux/mm.h>
  18 #include <linux/amba/bus.h>
  19 #include <linux/amba/clcd.h>
  20 #include <linux/amba/mmci.h>
  21 #include <linux/io.h>
  22 #include <linux/platform_data/clk-integrator.h>
  23 #include <linux/slab.h>
  24 #include <linux/irqchip/arm-vic.h>
  25 #include <linux/gpio/machine.h>
  26 
  27 #include <linux/sizes.h>
  28 #include "lm.h"
  29 #include "impd1.h"
  30 
  31 static int module_id;
  32 
  33 module_param_named(lmid, module_id, int, 0444);
  34 MODULE_PARM_DESC(lmid, "logic module stack position");
  35 
  36 struct impd1_module {
  37         void __iomem    *base;
  38         void __iomem    *vic_base;
  39 };
  40 
  41 void impd1_tweak_control(struct device *dev, u32 mask, u32 val)
  42 {
  43         struct impd1_module *impd1 = dev_get_drvdata(dev);
  44         u32 cur;
  45 
  46         val &= mask;
  47         cur = readl(impd1->base + IMPD1_CTRL) & ~mask;
  48         writel(cur | val, impd1->base + IMPD1_CTRL);
  49 }
  50 
  51 EXPORT_SYMBOL(impd1_tweak_control);
  52 
  53 /*
  54  * MMC support
  55  */
  56 static struct mmci_platform_data mmc_data = {
  57         .ocr_mask       = MMC_VDD_32_33|MMC_VDD_33_34,
  58 };
  59 
  60 /*
  61  * CLCD support
  62  */
  63 #define PANEL           PROSPECTOR
  64 
  65 #define LTM10C209               1
  66 #define PROSPECTOR              2
  67 #define SVGA                    3
  68 #define VGA                     4
  69 
  70 #if PANEL == VGA
  71 #define PANELTYPE       vga
  72 static struct clcd_panel vga = {
  73         .mode           = {
  74                 .name           = "VGA",
  75                 .refresh        = 60,
  76                 .xres           = 640,
  77                 .yres           = 480,
  78                 .pixclock       = 39721,
  79                 .left_margin    = 40,
  80                 .right_margin   = 24,
  81                 .upper_margin   = 32,
  82                 .lower_margin   = 11,
  83                 .hsync_len      = 96,
  84                 .vsync_len      = 2,
  85                 .sync           = 0,
  86                 .vmode          = FB_VMODE_NONINTERLACED,
  87         },
  88         .width          = -1,
  89         .height         = -1,
  90         .tim2           = TIM2_BCD | TIM2_IPC,
  91         .cntl           = CNTL_LCDTFT | CNTL_LCDVCOMP(1),
  92         .caps           = CLCD_CAP_5551,
  93         .connector      = IMPD1_CTRL_DISP_VGA,
  94         .bpp            = 16,
  95         .grayscale      = 0,
  96 };
  97 
  98 #elif PANEL == SVGA
  99 #define PANELTYPE       svga
 100 static struct clcd_panel svga = {
 101         .mode           = {
 102                 .name           = "SVGA",
 103                 .refresh        = 0,
 104                 .xres           = 800,
 105                 .yres           = 600,
 106                 .pixclock       = 27778,
 107                 .left_margin    = 20,
 108                 .right_margin   = 20,
 109                 .upper_margin   = 5,
 110                 .lower_margin   = 5,
 111                 .hsync_len      = 164,
 112                 .vsync_len      = 62,
 113                 .sync           = 0,
 114                 .vmode          = FB_VMODE_NONINTERLACED,
 115         },
 116         .width          = -1,
 117         .height         = -1,
 118         .tim2           = TIM2_BCD,
 119         .cntl           = CNTL_LCDTFT | CNTL_LCDVCOMP(1),
 120         .connector      = IMPD1_CTRL_DISP_VGA,
 121         .caps           = CLCD_CAP_5551,
 122         .bpp            = 16,
 123         .grayscale      = 0,
 124 };
 125 
 126 #elif PANEL == PROSPECTOR
 127 #define PANELTYPE       prospector
 128 static struct clcd_panel prospector = {
 129         .mode           = {
 130                 .name           = "PROSPECTOR",
 131                 .refresh        = 0,
 132                 .xres           = 640,
 133                 .yres           = 480,
 134                 .pixclock       = 40000,
 135                 .left_margin    = 33,
 136                 .right_margin   = 64,
 137                 .upper_margin   = 36,
 138                 .lower_margin   = 7,
 139                 .hsync_len      = 64,
 140                 .vsync_len      = 25,
 141                 .sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 142                 .vmode          = FB_VMODE_NONINTERLACED,
 143         },
 144         .width          = -1,
 145         .height         = -1,
 146         .tim2           = TIM2_BCD,
 147         .cntl           = CNTL_LCDTFT | CNTL_LCDVCOMP(1),
 148         .caps           = CLCD_CAP_5551,
 149         .fixedtimings   = 1,
 150         .connector      = IMPD1_CTRL_DISP_LCD,
 151         .bpp            = 16,
 152         .grayscale      = 0,
 153 };
 154 
 155 #elif PANEL == LTM10C209
 156 #define PANELTYPE       ltm10c209
 157 /*
 158  * Untested.
 159  */
 160 static struct clcd_panel ltm10c209 = {
 161         .mode           = {
 162                 .name           = "LTM10C209",
 163                 .refresh        = 0,
 164                 .xres           = 640,
 165                 .yres           = 480,
 166                 .pixclock       = 40000,
 167                 .left_margin    = 20,
 168                 .right_margin   = 20,
 169                 .upper_margin   = 19,
 170                 .lower_margin   = 19,
 171                 .hsync_len      = 20,
 172                 .vsync_len      = 10,
 173                 .sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 174                 .vmode          = FB_VMODE_NONINTERLACED,
 175         },
 176         .width          = -1,
 177         .height         = -1,
 178         .tim2           = TIM2_BCD,
 179         .cntl           = CNTL_LCDTFT | CNTL_LCDVCOMP(1),
 180         .caps           = CLCD_CAP_5551,
 181         .fixedtimings   = 1,
 182         .connector      = IMPD1_CTRL_DISP_LCD,
 183         .bpp            = 16,
 184         .grayscale      = 0,
 185 };
 186 #endif
 187 
 188 /*
 189  * Disable all display connectors on the interface module.
 190  */
 191 static void impd1fb_clcd_disable(struct clcd_fb *fb)
 192 {
 193         impd1_tweak_control(fb->dev->dev.parent, IMPD1_CTRL_DISP_MASK, 0);
 194 }
 195 
 196 /*
 197  * Enable the relevant connector on the interface module.
 198  */
 199 static void impd1fb_clcd_enable(struct clcd_fb *fb)
 200 {
 201         impd1_tweak_control(fb->dev->dev.parent, IMPD1_CTRL_DISP_MASK,
 202                         fb->panel->connector | IMPD1_CTRL_DISP_ENABLE);
 203 }
 204 
 205 static int impd1fb_clcd_setup(struct clcd_fb *fb)
 206 {
 207         unsigned long framebase = fb->dev->res.start + 0x01000000;
 208         unsigned long framesize = SZ_1M;
 209         int ret = 0;
 210 
 211         fb->panel = &PANELTYPE;
 212 
 213         if (!request_mem_region(framebase, framesize, "clcd framebuffer")) {
 214                 printk(KERN_ERR "IM-PD1: unable to reserve framebuffer\n");
 215                 return -EBUSY;
 216         }
 217 
 218         fb->fb.screen_base = ioremap(framebase, framesize);
 219         if (!fb->fb.screen_base) {
 220                 printk(KERN_ERR "IM-PD1: unable to map framebuffer\n");
 221                 ret = -ENOMEM;
 222                 goto free_buffer;
 223         }
 224 
 225         fb->fb.fix.smem_start   = framebase;
 226         fb->fb.fix.smem_len     = framesize;
 227 
 228         return 0;
 229 
 230  free_buffer:
 231         release_mem_region(framebase, framesize);
 232         return ret;
 233 }
 234 
 235 static int impd1fb_clcd_mmap(struct clcd_fb *fb, struct vm_area_struct *vma)
 236 {
 237         unsigned long start, size;
 238 
 239         start = vma->vm_pgoff + (fb->fb.fix.smem_start >> PAGE_SHIFT);
 240         size = vma->vm_end - vma->vm_start;
 241 
 242         return remap_pfn_range(vma, vma->vm_start, start, size,
 243                                vma->vm_page_prot);
 244 }
 245 
 246 static void impd1fb_clcd_remove(struct clcd_fb *fb)
 247 {
 248         iounmap(fb->fb.screen_base);
 249         release_mem_region(fb->fb.fix.smem_start, fb->fb.fix.smem_len);
 250 }
 251 
 252 static struct clcd_board impd1_clcd_data = {
 253         .name           = "IM-PD/1",
 254         .caps           = CLCD_CAP_5551 | CLCD_CAP_888,
 255         .check          = clcdfb_check,
 256         .decode         = clcdfb_decode,
 257         .disable        = impd1fb_clcd_disable,
 258         .enable         = impd1fb_clcd_enable,
 259         .setup          = impd1fb_clcd_setup,
 260         .mmap           = impd1fb_clcd_mmap,
 261         .remove         = impd1fb_clcd_remove,
 262 };
 263 
 264 struct impd1_device {
 265         unsigned long   offset;
 266         unsigned int    irq[2];
 267         unsigned int    id;
 268         void            *platform_data;
 269 };
 270 
 271 static struct impd1_device impd1_devs[] = {
 272         {
 273                 .offset = 0x00100000,
 274                 .irq    = { 1 },
 275                 .id     = 0x00141011,
 276         }, {
 277                 .offset = 0x00200000,
 278                 .irq    = { 2 },
 279                 .id     = 0x00141011,
 280         }, {
 281                 .offset = 0x00300000,
 282                 .irq    = { 3 },
 283                 .id     = 0x00041022,
 284         }, {
 285                 .offset = 0x00400000,
 286                 .irq    = { 4 },
 287                 .id     = 0x00041061,
 288         }, {
 289                 .offset = 0x00500000,
 290                 .irq    = { 5 },
 291                 .id     = 0x00041061,
 292         }, {
 293                 .offset = 0x00600000,
 294                 .irq    = { 6 },
 295                 .id     = 0x00041130,
 296         }, {
 297                 .offset = 0x00700000,
 298                 .irq    = { 7, 8 },
 299                 .id     = 0x00041181,
 300                 .platform_data = &mmc_data,
 301         }, {
 302                 .offset = 0x00800000,
 303                 .irq    = { 9 },
 304                 .id     = 0x00041041,
 305         }, {
 306                 .offset = 0x01000000,
 307                 .irq    = { 11 },
 308                 .id     = 0x00041110,
 309                 .platform_data = &impd1_clcd_data,
 310         }
 311 };
 312 
 313 /*
 314  * Valid IRQs: 0 thru 9 and 11, 10 unused.
 315  */
 316 #define IMPD1_VALID_IRQS 0x00000bffU
 317 
 318 /*
 319  * As this module is bool, it is OK to have this as __ref() - no
 320  * probe calls will be done after the initial system bootup, as devices
 321  * are discovered as part of the machine startup.
 322  */
 323 static int __ref impd1_probe(struct lm_device *dev)
 324 {
 325         struct impd1_module *impd1;
 326         int irq_base;
 327         int i;
 328 
 329         if (dev->id != module_id)
 330                 return -EINVAL;
 331 
 332         if (!devm_request_mem_region(&dev->dev, dev->resource.start,
 333                                      SZ_4K, "LM registers"))
 334                 return -EBUSY;
 335 
 336         impd1 = devm_kzalloc(&dev->dev, sizeof(struct impd1_module),
 337                              GFP_KERNEL);
 338         if (!impd1)
 339                 return -ENOMEM;
 340 
 341         impd1->base = devm_ioremap(&dev->dev, dev->resource.start, SZ_4K);
 342         if (!impd1->base)
 343                 return -ENOMEM;
 344 
 345         integrator_impd1_clk_init(impd1->base, dev->id);
 346 
 347         if (!devm_request_mem_region(&dev->dev,
 348                                      dev->resource.start + 0x03000000,
 349                                      SZ_4K, "VIC"))
 350                 return -EBUSY;
 351 
 352         impd1->vic_base = devm_ioremap(&dev->dev,
 353                                        dev->resource.start + 0x03000000,
 354                                        SZ_4K);
 355         if (!impd1->vic_base)
 356                 return -ENOMEM;
 357 
 358         irq_base = vic_init_cascaded(impd1->vic_base, dev->irq,
 359                                      IMPD1_VALID_IRQS, 0);
 360 
 361         lm_set_drvdata(dev, impd1);
 362 
 363         dev_info(&dev->dev, "IM-PD1 found at 0x%08lx\n",
 364                  (unsigned long)dev->resource.start);
 365 
 366         for (i = 0; i < ARRAY_SIZE(impd1_devs); i++) {
 367                 struct impd1_device *idev = impd1_devs + i;
 368                 struct amba_device *d;
 369                 unsigned long pc_base;
 370                 char devname[32];
 371                 int irq1 = idev->irq[0];
 372                 int irq2 = idev->irq[1];
 373 
 374                 /* Translate IRQs to IM-PD1 local numberspace */
 375                 if (irq1)
 376                         irq1 += irq_base;
 377                 if (irq2)
 378                         irq2 += irq_base;
 379 
 380                 pc_base = dev->resource.start + idev->offset;
 381                 snprintf(devname, 32, "lm%x:%5.5lx", dev->id, idev->offset >> 12);
 382 
 383                 /* Add GPIO descriptor lookup table for the PL061 block */
 384                 if (idev->offset == 0x00400000) {
 385                         struct gpiod_lookup_table *lookup;
 386                         char *chipname;
 387                         char *mmciname;
 388 
 389                         lookup = devm_kzalloc(&dev->dev,
 390                                               struct_size(lookup, table, 3),
 391                                               GFP_KERNEL);
 392                         chipname = devm_kstrdup(&dev->dev, devname, GFP_KERNEL);
 393                         mmciname = devm_kasprintf(&dev->dev, GFP_KERNEL,
 394                                                   "lm%x:00700", dev->id);
 395                         if (!lookup || !chipname || !mmciname)
 396                                 return -ENOMEM;
 397 
 398                         lookup->dev_id = mmciname;
 399                         /*
 400                          * Offsets on GPIO block 1:
 401                          * 3 = MMC WP (write protect)
 402                          * 4 = MMC CD (card detect)
 403                          *
 404                          * Offsets on GPIO block 2:
 405                          * 0 = Up key
 406                          * 1 = Down key
 407                          * 2 = Left key
 408                          * 3 = Right key
 409                          * 4 = Key lower left
 410                          * 5 = Key lower right
 411                          */
 412                         /* We need the two MMCI GPIO entries */
 413                         lookup->table[0].chip_label = chipname;
 414                         lookup->table[0].chip_hwnum = 3;
 415                         lookup->table[0].con_id = "wp";
 416                         lookup->table[1].chip_label = chipname;
 417                         lookup->table[1].chip_hwnum = 4;
 418                         lookup->table[1].con_id = "cd";
 419                         lookup->table[1].flags = GPIO_ACTIVE_LOW;
 420                         gpiod_add_lookup_table(lookup);
 421                 }
 422 
 423                 d = amba_ahb_device_add_res(&dev->dev, devname, pc_base, SZ_4K,
 424                                             irq1, irq2,
 425                                             idev->platform_data, idev->id,
 426                                             &dev->resource);
 427                 if (IS_ERR(d)) {
 428                         dev_err(&dev->dev, "unable to register device: %ld\n", PTR_ERR(d));
 429                         continue;
 430                 }
 431         }
 432 
 433         return 0;
 434 }
 435 
 436 static int impd1_remove_one(struct device *dev, void *data)
 437 {
 438         device_unregister(dev);
 439         return 0;
 440 }
 441 
 442 static void impd1_remove(struct lm_device *dev)
 443 {
 444         device_for_each_child(&dev->dev, NULL, impd1_remove_one);
 445         integrator_impd1_clk_exit(dev->id);
 446 
 447         lm_set_drvdata(dev, NULL);
 448 }
 449 
 450 static struct lm_driver impd1_driver = {
 451         .drv = {
 452                 .name   = "impd1",
 453                 /*
 454                  * As we're dropping the probe() function, suppress driver
 455                  * binding from sysfs.
 456                  */
 457                 .suppress_bind_attrs = true,
 458         },
 459         .probe          = impd1_probe,
 460         .remove         = impd1_remove,
 461 };
 462 
 463 static int __init impd1_init(void)
 464 {
 465         return lm_driver_register(&impd1_driver);
 466 }
 467 
 468 static void __exit impd1_exit(void)
 469 {
 470         lm_driver_unregister(&impd1_driver);
 471 }
 472 
 473 module_init(impd1_init);
 474 module_exit(impd1_exit);
 475 
 476 MODULE_LICENSE("GPL");
 477 MODULE_DESCRIPTION("Integrator/IM-PD1 logic module core driver");
 478 MODULE_AUTHOR("Deep Blue Solutions Ltd");

/* [<][>][^][v][top][bottom][index][help] */